Run imported recipes in root justfile with correct working directory (#2056)

This commit is contained in:
Casey Rodarmor 2024-05-18 23:38:57 -07:00 committed by GitHub
parent b1c7491486
commit 104608d8cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 49 additions and 16 deletions

View File

@ -133,7 +133,7 @@ impl<'src> Analyzer<'src> {
define(recipe.name, "recipe", settings.allow_duplicate_recipes)?; define(recipe.name, "recipe", settings.allow_duplicate_recipes)?;
if recipe_table if recipe_table
.get(recipe.name.lexeme()) .get(recipe.name.lexeme())
.map_or(true, |original| recipe.depth <= original.depth) .map_or(true, |original| recipe.file_depth <= original.file_depth)
{ {
recipe_table.insert(recipe.clone()); recipe_table.insert(recipe.clone());
} }

View File

@ -21,9 +21,10 @@ impl Compiler {
loaded.push(relative.into()); loaded.push(relative.into());
let tokens = Lexer::lex(relative, src)?; let tokens = Lexer::lex(relative, src)?;
let mut ast = Parser::parse( let mut ast = Parser::parse(
current.file_depth,
&current.path, &current.path,
&current.namepath, &current.namepath,
current.depth, current.submodule_depth,
&tokens, &tokens,
&current.working_directory, &current.working_directory,
)?; )?;
@ -169,6 +170,7 @@ impl Compiler {
pub(crate) fn test_compile(src: &str) -> CompileResult<Justfile> { pub(crate) fn test_compile(src: &str) -> CompileResult<Justfile> {
let tokens = Lexer::test_lex(src)?; let tokens = Lexer::test_lex(src)?;
let ast = Parser::parse( let ast = Parser::parse(
0,
&PathBuf::new(), &PathBuf::new(),
&Namepath::default(), &Namepath::default(),
0, 0,

View File

@ -25,6 +25,7 @@ use {super::*, TokenKind::*};
/// contents of the set is printed in the resultant error message. /// contents of the set is printed in the resultant error message.
pub(crate) struct Parser<'run, 'src> { pub(crate) struct Parser<'run, 'src> {
expected_tokens: BTreeSet<TokenKind>, expected_tokens: BTreeSet<TokenKind>,
file_depth: u32,
file_path: &'run Path, file_path: &'run Path,
module_namepath: &'run Namepath<'src>, module_namepath: &'run Namepath<'src>,
next_token: usize, next_token: usize,
@ -37,6 +38,7 @@ pub(crate) struct Parser<'run, 'src> {
impl<'run, 'src> Parser<'run, 'src> { impl<'run, 'src> Parser<'run, 'src> {
/// Parse `tokens` into an `Ast` /// Parse `tokens` into an `Ast`
pub(crate) fn parse( pub(crate) fn parse(
file_depth: u32,
file_path: &'run Path, file_path: &'run Path,
module_namepath: &'run Namepath<'src>, module_namepath: &'run Namepath<'src>,
submodule_depth: u32, submodule_depth: u32,
@ -45,6 +47,7 @@ impl<'run, 'src> Parser<'run, 'src> {
) -> CompileResult<'src, Ast<'src>> { ) -> CompileResult<'src, Ast<'src>> {
Self { Self {
expected_tokens: BTreeSet::new(), expected_tokens: BTreeSet::new(),
file_depth,
file_path, file_path,
module_namepath, module_namepath,
next_token: 0, next_token: 0,
@ -456,7 +459,7 @@ impl<'run, 'src> Parser<'run, 'src> {
let value = self.parse_expression()?; let value = self.parse_expression()?;
self.expect_eol()?; self.expect_eol()?;
Ok(Assignment { Ok(Assignment {
depth: self.submodule_depth, depth: self.file_depth,
export, export,
name, name,
value, value,
@ -769,8 +772,8 @@ impl<'run, 'src> Parser<'run, 'src> {
attributes, attributes,
body, body,
dependencies, dependencies,
depth: self.submodule_depth,
doc, doc,
file_depth: self.file_depth,
file_path: self.file_path.into(), file_path: self.file_path.into(),
name, name,
namepath: self.module_namepath.join(name), namepath: self.module_namepath.join(name),
@ -778,6 +781,7 @@ impl<'run, 'src> Parser<'run, 'src> {
priors, priors,
private: name.lexeme().starts_with('_'), private: name.lexeme().starts_with('_'),
quiet, quiet,
submodule_depth: self.submodule_depth,
working_directory: self.working_directory.into(), working_directory: self.working_directory.into(),
}) })
} }
@ -1010,6 +1014,7 @@ mod tests {
let unindented = unindent(text); let unindented = unindent(text);
let tokens = Lexer::test_lex(&unindented).expect("lexing failed"); let tokens = Lexer::test_lex(&unindented).expect("lexing failed");
let justfile = Parser::parse( let justfile = Parser::parse(
0,
&PathBuf::new(), &PathBuf::new(),
&Namepath::default(), &Namepath::default(),
0, 0,
@ -1055,6 +1060,7 @@ mod tests {
let tokens = Lexer::test_lex(src).expect("Lexing failed in parse test..."); let tokens = Lexer::test_lex(src).expect("Lexing failed in parse test...");
match Parser::parse( match Parser::parse(
0,
&PathBuf::new(), &PathBuf::new(),
&Namepath::default(), &Namepath::default(),
0, 0,

View File

@ -22,10 +22,10 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> {
pub(crate) attributes: BTreeSet<Attribute<'src>>, pub(crate) attributes: BTreeSet<Attribute<'src>>,
pub(crate) body: Vec<Line<'src>>, pub(crate) body: Vec<Line<'src>>,
pub(crate) dependencies: Vec<D>, pub(crate) dependencies: Vec<D>,
#[serde(skip)]
pub(crate) depth: u32,
pub(crate) doc: Option<&'src str>, pub(crate) doc: Option<&'src str>,
#[serde(skip)] #[serde(skip)]
pub(crate) file_depth: u32,
#[serde(skip)]
pub(crate) file_path: PathBuf, pub(crate) file_path: PathBuf,
pub(crate) name: Name<'src>, pub(crate) name: Name<'src>,
pub(crate) namepath: Namepath<'src>, pub(crate) namepath: Namepath<'src>,
@ -35,6 +35,8 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> {
pub(crate) quiet: bool, pub(crate) quiet: bool,
pub(crate) shebang: bool, pub(crate) shebang: bool,
#[serde(skip)] #[serde(skip)]
pub(crate) submodule_depth: u32,
#[serde(skip)]
pub(crate) working_directory: PathBuf, pub(crate) working_directory: PathBuf,
} }
@ -126,7 +128,7 @@ impl<'src, D> Recipe<'src, D> {
fn working_directory<'a>(&'a self, search: &'a Search) -> Option<&Path> { fn working_directory<'a>(&'a self, search: &'a Search) -> Option<&Path> {
if self.change_directory() { if self.change_directory() {
Some(if self.depth > 0 { Some(if self.submodule_depth > 0 {
&self.working_directory &self.working_directory
} else { } else {
&search.working_directory &search.working_directory

View File

@ -1,37 +1,41 @@
use super::*; use super::*;
pub(crate) struct Source<'src> { pub(crate) struct Source<'src> {
pub(crate) path: PathBuf, pub(crate) file_depth: u32,
pub(crate) depth: u32,
pub(crate) namepath: Namepath<'src>, pub(crate) namepath: Namepath<'src>,
pub(crate) path: PathBuf,
pub(crate) submodule_depth: u32,
pub(crate) working_directory: PathBuf, pub(crate) working_directory: PathBuf,
} }
impl<'src> Source<'src> { impl<'src> Source<'src> {
pub(crate) fn root(path: &Path) -> Self { pub(crate) fn root(path: &Path) -> Self {
Self { Self {
path: path.into(), file_depth: 0,
depth: 0,
namepath: Namepath::default(), namepath: Namepath::default(),
path: path.into(),
submodule_depth: 0,
working_directory: path.parent().unwrap().into(), working_directory: path.parent().unwrap().into(),
} }
} }
pub(crate) fn import(&self, path: PathBuf) -> Self { pub(crate) fn import(&self, path: PathBuf) -> Self {
Self { Self {
depth: self.depth + 1, file_depth: self.file_depth + 1,
path,
namepath: self.namepath.clone(), namepath: self.namepath.clone(),
path,
submodule_depth: self.submodule_depth,
working_directory: self.working_directory.clone(), working_directory: self.working_directory.clone(),
} }
} }
pub(crate) fn module(&self, name: Name<'src>, path: PathBuf) -> Self { pub(crate) fn module(&self, name: Name<'src>, path: PathBuf) -> Self {
Self { Self {
file_depth: self.file_depth + 1,
namepath: self.namepath.join(name),
submodule_depth: self.submodule_depth + 1,
working_directory: path.parent().unwrap().into(), working_directory: path.parent().unwrap().into(),
path, path,
depth: self.depth + 1,
namepath: self.namepath.join(name),
} }
} }
} }

View File

@ -60,6 +60,7 @@ pub(crate) fn analysis_error(
let tokens = Lexer::test_lex(src).expect("Lexing failed in parse test..."); let tokens = Lexer::test_lex(src).expect("Lexing failed in parse test...");
let ast = Parser::parse( let ast = Parser::parse(
0,
&PathBuf::new(), &PathBuf::new(),
&Namepath::default(), &Namepath::default(),
0, 0,

View File

@ -48,8 +48,8 @@ impl<'src> UnresolvedRecipe<'src> {
attributes: self.attributes, attributes: self.attributes,
body: self.body, body: self.body,
dependencies, dependencies,
depth: self.depth,
doc: self.doc, doc: self.doc,
file_depth: self.file_depth,
file_path: self.file_path, file_path: self.file_path,
name: self.name, name: self.name,
namepath: self.namepath, namepath: self.namepath,
@ -58,6 +58,7 @@ impl<'src> UnresolvedRecipe<'src> {
private: self.private, private: self.private,
quiet: self.quiet, quiet: self.quiet,
shebang: self.shebang, shebang: self.shebang,
submodule_depth: self.submodule_depth,
working_directory: self.working_directory, working_directory: self.working_directory,
}) })
} }

View File

@ -344,3 +344,20 @@ fn shebang_recipes_in_imports_in_root_run_in_justfile_directory() {
.stdout("BAZ") .stdout("BAZ")
.run(); .run();
} }
#[test]
fn recipes_imported_in_root_run_in_command_line_provided_working_directory() {
Test::new()
.write("subdir/b.justfile", "@b:\n cat baz")
.write("subdir/a.justfile", "import 'b.justfile'\n@a: b\n cat baz")
.write("baz", "BAZ")
.args([
"--working-directory",
".",
"--justfile",
"subdir/a.justfile",
])
.test_round_trip(false)
.stdout("BAZBAZ")
.run();
}