diff --git a/src/parser.rs b/src/parser.rs index 99544acd..1223153a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1082,6 +1082,7 @@ impl<'run, 'src> Parser<'run, 'src> { &mut self, ) -> CompileResult<'src, Option<(Token<'src>, BTreeSet>)>> { let mut attributes = BTreeMap::new(); + let mut working_directory_attribute_line = None; let mut token = None; @@ -1108,6 +1109,17 @@ impl<'run, 'src> Parser<'run, 'src> { let attribute = Attribute::new(name, arguments)?; + if let Attribute::WorkingDirectory(_) = &attribute { + if let Some(line) = working_directory_attribute_line { + return Err(name.error(CompileErrorKind::DuplicateAttribute { + attribute: name.lexeme(), + first: line, + })); + } + + working_directory_attribute_line = Some(name.line); + } + if let Some(line) = attributes.get(&attribute) { return Err(name.error(CompileErrorKind::DuplicateAttribute { attribute: name.lexeme(), diff --git a/src/recipe.rs b/src/recipe.rs index fdf6b27a..d9b81cfa 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -135,20 +135,15 @@ impl<'src, D> Recipe<'src, D> { return None; } - let working_dir = self - .attributes - .iter() - .filter_map(|attribute| match attribute { - Attribute::WorkingDirectory(dir) => Some(dir), - _ => None, - }) - .last(); + let working_directory = context.working_directory(); - Some( - working_dir - .map(|dir| context.working_directory().join(dir.raw)) - .unwrap_or(context.working_directory()), - ) + for attribute in &self.attributes { + if let Attribute::WorkingDirectory(dir) = attribute { + return Some(working_directory.join(&dir.cooked)); + } + } + + Some(working_directory) } fn no_quiet(&self) -> bool { diff --git a/tests/working_directory.rs b/tests/working_directory.rs index 461a5e24..3b181bb1 100644 --- a/tests/working_directory.rs +++ b/tests/working_directory.rs @@ -333,22 +333,13 @@ file := shell('cat file.txt') } #[test] -fn attribute() { +fn attribute_duplicate() { Test::new() .justfile( r#" - [working-directory('bar')] - print1: - echo "$(basename "$PWD")" - [working-directory('bar')] [working-directory('baz')] - print2: - echo "$(basename "$PWD")" - - [working-directory('bar')] - [no-cd] - print3: + print: echo "$(basename "$PWD")" "#, ) @@ -358,14 +349,48 @@ fn attribute() { bar: {}, baz: {}, }) - .args(["print1", "print2", "print3"]) + .args(["print"]) + .stderr( + r#"error: Recipe attribute `working-directory` first used on line 1 is duplicated on line 2 + ——▶ justfile:2:2 + │ +2 │ [working-directory('baz')] + │ ^^^^^^^^^^^^^^^^^ +"#, + ) + .stdout("") + .status(1) + .run(); +} + +#[test] +fn attribute() { + Test::new() + .justfile( + r#" + [working-directory('bar')] + print1: + echo "$(basename "$PWD")" + + [working-directory('baz')] + [no-cd] + print2: + echo "$(basename "$PWD")" + "#, + ) + .current_dir("foo") + .tree(tree! { + foo: {}, + bar: {}, + baz: {}, + }) + .args(["print1", "print2"]) .stderr( r#"echo "$(basename "$PWD")" echo "$(basename "$PWD")" -echo "$(basename "$PWD")" "#, ) - .stdout("bar\nbaz\nfoo\n") + .stdout("bar\nfoo\n") .run(); }