From 104608d8ccf97d9e3c8c6ff772b9b9aee568ecbb Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sat, 18 May 2024 23:38:57 -0700 Subject: [PATCH] Run imported recipes in root justfile with correct working directory (#2056) --- src/analyzer.rs | 2 +- src/compiler.rs | 4 +++- src/parser.rs | 10 ++++++++-- src/recipe.rs | 8 +++++--- src/source.rs | 20 ++++++++++++-------- src/testing.rs | 1 + src/unresolved_recipe.rs | 3 ++- tests/imports.rs | 17 +++++++++++++++++ 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/analyzer.rs b/src/analyzer.rs index 0180fbe..eb85b4f 100644 --- a/src/analyzer.rs +++ b/src/analyzer.rs @@ -133,7 +133,7 @@ impl<'src> Analyzer<'src> { define(recipe.name, "recipe", settings.allow_duplicate_recipes)?; if recipe_table .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()); } diff --git a/src/compiler.rs b/src/compiler.rs index 6305c54..a1e987a 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -21,9 +21,10 @@ impl Compiler { loaded.push(relative.into()); let tokens = Lexer::lex(relative, src)?; let mut ast = Parser::parse( + current.file_depth, ¤t.path, ¤t.namepath, - current.depth, + current.submodule_depth, &tokens, ¤t.working_directory, )?; @@ -169,6 +170,7 @@ impl Compiler { pub(crate) fn test_compile(src: &str) -> CompileResult { let tokens = Lexer::test_lex(src)?; let ast = Parser::parse( + 0, &PathBuf::new(), &Namepath::default(), 0, diff --git a/src/parser.rs b/src/parser.rs index 5760a41..e3abcbf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -25,6 +25,7 @@ use {super::*, TokenKind::*}; /// contents of the set is printed in the resultant error message. pub(crate) struct Parser<'run, 'src> { expected_tokens: BTreeSet, + file_depth: u32, file_path: &'run Path, module_namepath: &'run Namepath<'src>, next_token: usize, @@ -37,6 +38,7 @@ pub(crate) struct Parser<'run, 'src> { impl<'run, 'src> Parser<'run, 'src> { /// Parse `tokens` into an `Ast` pub(crate) fn parse( + file_depth: u32, file_path: &'run Path, module_namepath: &'run Namepath<'src>, submodule_depth: u32, @@ -45,6 +47,7 @@ impl<'run, 'src> Parser<'run, 'src> { ) -> CompileResult<'src, Ast<'src>> { Self { expected_tokens: BTreeSet::new(), + file_depth, file_path, module_namepath, next_token: 0, @@ -456,7 +459,7 @@ impl<'run, 'src> Parser<'run, 'src> { let value = self.parse_expression()?; self.expect_eol()?; Ok(Assignment { - depth: self.submodule_depth, + depth: self.file_depth, export, name, value, @@ -769,8 +772,8 @@ impl<'run, 'src> Parser<'run, 'src> { attributes, body, dependencies, - depth: self.submodule_depth, doc, + file_depth: self.file_depth, file_path: self.file_path.into(), name, namepath: self.module_namepath.join(name), @@ -778,6 +781,7 @@ impl<'run, 'src> Parser<'run, 'src> { priors, private: name.lexeme().starts_with('_'), quiet, + submodule_depth: self.submodule_depth, working_directory: self.working_directory.into(), }) } @@ -1010,6 +1014,7 @@ mod tests { let unindented = unindent(text); let tokens = Lexer::test_lex(&unindented).expect("lexing failed"); let justfile = Parser::parse( + 0, &PathBuf::new(), &Namepath::default(), 0, @@ -1055,6 +1060,7 @@ mod tests { let tokens = Lexer::test_lex(src).expect("Lexing failed in parse test..."); match Parser::parse( + 0, &PathBuf::new(), &Namepath::default(), 0, diff --git a/src/recipe.rs b/src/recipe.rs index 5834d5b..48784d9 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -22,10 +22,10 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> { pub(crate) attributes: BTreeSet>, pub(crate) body: Vec>, pub(crate) dependencies: Vec, - #[serde(skip)] - pub(crate) depth: u32, pub(crate) doc: Option<&'src str>, #[serde(skip)] + pub(crate) file_depth: u32, + #[serde(skip)] pub(crate) file_path: PathBuf, pub(crate) name: Name<'src>, pub(crate) namepath: Namepath<'src>, @@ -35,6 +35,8 @@ pub(crate) struct Recipe<'src, D = Dependency<'src>> { pub(crate) quiet: bool, pub(crate) shebang: bool, #[serde(skip)] + pub(crate) submodule_depth: u32, + #[serde(skip)] 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> { if self.change_directory() { - Some(if self.depth > 0 { + Some(if self.submodule_depth > 0 { &self.working_directory } else { &search.working_directory diff --git a/src/source.rs b/src/source.rs index bbb319a..8826b4d 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,37 +1,41 @@ use super::*; pub(crate) struct Source<'src> { - pub(crate) path: PathBuf, - pub(crate) depth: u32, + pub(crate) file_depth: u32, pub(crate) namepath: Namepath<'src>, + pub(crate) path: PathBuf, + pub(crate) submodule_depth: u32, pub(crate) working_directory: PathBuf, } impl<'src> Source<'src> { pub(crate) fn root(path: &Path) -> Self { Self { - path: path.into(), - depth: 0, + file_depth: 0, namepath: Namepath::default(), + path: path.into(), + submodule_depth: 0, working_directory: path.parent().unwrap().into(), } } pub(crate) fn import(&self, path: PathBuf) -> Self { Self { - depth: self.depth + 1, - path, + file_depth: self.file_depth + 1, namepath: self.namepath.clone(), + path, + submodule_depth: self.submodule_depth, working_directory: self.working_directory.clone(), } } pub(crate) fn module(&self, name: Name<'src>, path: PathBuf) -> 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(), path, - depth: self.depth + 1, - namepath: self.namepath.join(name), } } } diff --git a/src/testing.rs b/src/testing.rs index bf3cbbf..3de2e2b 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -60,6 +60,7 @@ pub(crate) fn analysis_error( let tokens = Lexer::test_lex(src).expect("Lexing failed in parse test..."); let ast = Parser::parse( + 0, &PathBuf::new(), &Namepath::default(), 0, diff --git a/src/unresolved_recipe.rs b/src/unresolved_recipe.rs index fe30f15..80d4904 100644 --- a/src/unresolved_recipe.rs +++ b/src/unresolved_recipe.rs @@ -48,8 +48,8 @@ impl<'src> UnresolvedRecipe<'src> { attributes: self.attributes, body: self.body, dependencies, - depth: self.depth, doc: self.doc, + file_depth: self.file_depth, file_path: self.file_path, name: self.name, namepath: self.namepath, @@ -58,6 +58,7 @@ impl<'src> UnresolvedRecipe<'src> { private: self.private, quiet: self.quiet, shebang: self.shebang, + submodule_depth: self.submodule_depth, working_directory: self.working_directory, }) } diff --git a/tests/imports.rs b/tests/imports.rs index 0d32fad..ce6dcf9 100644 --- a/tests/imports.rs +++ b/tests/imports.rs @@ -344,3 +344,20 @@ fn shebang_recipes_in_imports_in_root_run_in_justfile_directory() { .stdout("BAZ") .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(); +}