mirror of
https://github.com/casey/just.git
synced 2024-11-22 02:09:44 +03:00
Merge 18ff6b5705
into 7eea772785
This commit is contained in:
commit
978fa34f87
18
README.md
18
README.md
@ -1910,6 +1910,7 @@ Recipes, `mod` statements, and aliases may be annotated with attributes that cha
|
||||
| `[script(COMMAND)]`<sup>1.32.0</sup> | recipe | Execute recipe as a script interpreted by `COMMAND`. See [script recipes](#script-recipes) for more details. |
|
||||
| `[unix]`<sup>1.8.0</sup> | recipe | Enable recipe on Unixes. (Includes MacOS). |
|
||||
| `[windows]`<sup>1.8.0</sup> | recipe | Enable recipe on Windows. |
|
||||
| `[working-directory('bar')]`<sup>1.37.0</sup> | recipe | Set the working directory for the recipe, relative to the default working directory. |
|
||||
|
||||
A recipe can have multiple attributes, either on multiple lines:
|
||||
|
||||
@ -1973,6 +1974,23 @@ Can be used with paths that are relative to the current directory, because
|
||||
`[no-cd]` prevents `just` from changing the current directory when executing
|
||||
`commit`.
|
||||
|
||||
#### Changing Working Directory<sup>1.37.0</sup>
|
||||
|
||||
`just` normally executes recipes with the current directory set to the directory
|
||||
that contains the `justfile`. The execution directory can be changed with the
|
||||
`[working-directory('dir')]` attribute. This can be used to create recipes which
|
||||
are executed in a directory relative to the default directory.
|
||||
|
||||
For example, this `example` recipe:
|
||||
|
||||
```just
|
||||
[working-directory('dir')]
|
||||
example:
|
||||
echo "$(pwd)"
|
||||
```
|
||||
|
||||
Which will run in the `dir` directory.
|
||||
|
||||
#### Requiring Confirmation for Recipes<sup>1.17.0</sup>
|
||||
|
||||
`just` normally executes all recipes unless there is an error. The `[confirm]`
|
||||
|
@ -23,13 +23,14 @@ pub(crate) enum Attribute<'src> {
|
||||
Script(Option<Interpreter<'src>>),
|
||||
Unix,
|
||||
Windows,
|
||||
WorkingDirectory(StringLiteral<'src>),
|
||||
}
|
||||
|
||||
impl AttributeDiscriminant {
|
||||
fn argument_range(self) -> RangeInclusive<usize> {
|
||||
match self {
|
||||
Self::Confirm | Self::Doc => 0..=1,
|
||||
Self::Group | Self::Extension => 1..=1,
|
||||
Self::Group | Self::Extension | Self::WorkingDirectory => 1..=1,
|
||||
Self::Linux
|
||||
| Self::Macos
|
||||
| Self::NoCd
|
||||
@ -93,6 +94,9 @@ impl<'src> Attribute<'src> {
|
||||
}),
|
||||
AttributeDiscriminant::Unix => Self::Unix,
|
||||
AttributeDiscriminant::Windows => Self::Windows,
|
||||
AttributeDiscriminant::WorkingDirectory => {
|
||||
Self::WorkingDirectory(arguments.into_iter().next().unwrap())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -109,7 +113,8 @@ impl<'src> Display for Attribute<'src> {
|
||||
Self::Confirm(Some(argument))
|
||||
| Self::Doc(Some(argument))
|
||||
| Self::Extension(argument)
|
||||
| Self::Group(argument) => write!(f, "({argument})")?,
|
||||
| Self::Group(argument)
|
||||
| Self::WorkingDirectory(argument) => write!(f, "({argument})")?,
|
||||
Self::Script(Some(shell)) => write!(f, "({shell})")?,
|
||||
Self::Confirm(None)
|
||||
| Self::Doc(None)
|
||||
|
@ -1118,6 +1118,7 @@ impl<'run, 'src> Parser<'run, 'src> {
|
||||
&mut self,
|
||||
) -> CompileResult<'src, Option<(Token<'src>, BTreeSet<Attribute<'src>>)>> {
|
||||
let mut attributes = BTreeMap::new();
|
||||
let mut working_directory_attribute_line = None;
|
||||
|
||||
let mut token = None;
|
||||
|
||||
@ -1144,6 +1145,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(),
|
||||
|
@ -131,11 +131,19 @@ impl<'src, D> Recipe<'src, D> {
|
||||
}
|
||||
|
||||
fn working_directory<'a>(&'a self, context: &'a ExecutionContext) -> Option<PathBuf> {
|
||||
if self.change_directory() {
|
||||
Some(context.working_directory())
|
||||
} else {
|
||||
None
|
||||
if !self.change_directory() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let working_directory = 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 {
|
||||
|
@ -331,3 +331,95 @@ file := shell('cat file.txt')
|
||||
.stdout("FILE\n")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn attribute_duplicate() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
r#"
|
||||
[working-directory('bar')]
|
||||
[working-directory('baz')]
|
||||
print:
|
||||
echo "$(basename "$PWD")"
|
||||
"#,
|
||||
)
|
||||
.current_dir("foo")
|
||||
.tree(tree! {
|
||||
foo: {},
|
||||
bar: {},
|
||||
baz: {},
|
||||
})
|
||||
.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")"
|
||||
"#,
|
||||
)
|
||||
.stdout("bar\nfoo\n")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setting_and_attribute() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
r#"
|
||||
set working-directory := 'bar'
|
||||
|
||||
[working-directory('baz')]
|
||||
print1:
|
||||
echo "$(basename "$PWD")"
|
||||
echo "$(basename "$(dirname "$PWD")")"
|
||||
"#,
|
||||
)
|
||||
.current_dir("foo")
|
||||
.tree(tree! {
|
||||
foo: {},
|
||||
bar: {
|
||||
baz: {},
|
||||
},
|
||||
})
|
||||
.args(["print1"])
|
||||
.stderr(
|
||||
r#"echo "$(basename "$PWD")"
|
||||
echo "$(basename "$(dirname "$PWD")")"
|
||||
"#,
|
||||
)
|
||||
.stdout("baz\nbar\n")
|
||||
.run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user