1
1
mirror of https://github.com/casey/just.git synced 2024-09-11 05:55:31 +03:00

Add working-directory setting (#2283)

This commit is contained in:
Yuri Astrakhan 2024-07-30 20:50:32 -04:00 committed by GitHub
parent b70546aa87
commit 23a53fb50f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 165 additions and 14 deletions

View File

@ -80,6 +80,7 @@ setting : 'allow-duplicate-recipes' boolean?
| 'unstable' boolean?
| 'windows-powershell' boolean?
| 'windows-shell' ':=' string_list
| 'working-directory' ':=' string
boolean : ':=' ('true' | 'false')

View File

@ -824,6 +824,7 @@ foo:
| `unstable`<sup>1.31.0</sup> | boolean | `false` | Enable unstable features. |
| `windows-powershell` | boolean | `false` | Use PowerShell on Windows as default shell. (Deprecated. Use `windows-shell` instead. |
| `windows-shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |
| `working-directory`<sup>master</sup> | string | - | Set the working directory for recipes and backticks, relative to the default working directory. |
Boolean settings can be written as:

View File

@ -239,7 +239,17 @@ impl<'src, 'run> Evaluator<'src, 'run> {
let mut cmd = self.context.settings.shell_command(self.context.config);
cmd.arg(command);
cmd.args(args);
cmd.current_dir(&self.context.search.working_directory);
if let Some(working_directory) = &self.context.settings.working_directory {
cmd.current_dir(
self
.context
.search
.working_directory
.join(working_directory),
)
} else {
cmd.current_dir(&self.context.search.working_directory)
};
cmd.export(
self.context.settings,
self.context.dotenv,

View File

@ -30,6 +30,7 @@ pub(crate) enum Keyword {
Unstable,
WindowsPowershell,
WindowsShell,
WorkingDirectory,
X,
}

View File

@ -307,7 +307,10 @@ impl<'src> Node<'src> for Set<'src> {
set.push_mut(Tree::string(&argument.cooked));
}
}
Setting::DotenvFilename(value) | Setting::DotenvPath(value) | Setting::Tempdir(value) => {
Setting::DotenvFilename(value)
| Setting::DotenvPath(value)
| Setting::Tempdir(value)
| Setting::WorkingDirectory(value) => {
set.push_mut(Tree::string(&value.cooked));
}
}

View File

@ -967,6 +967,7 @@ impl<'run, 'src> Parser<'run, 'src> {
Keyword::Shell => Some(Setting::Shell(self.parse_interpreter()?)),
Keyword::Tempdir => Some(Setting::Tempdir(self.parse_string_literal()?)),
Keyword::WindowsShell => Some(Setting::WindowsShell(self.parse_interpreter()?)),
Keyword::WorkingDirectory => Some(Setting::WorkingDirectory(self.parse_string_literal()?)),
_ => None,
};
@ -2146,6 +2147,12 @@ mod tests {
tree: (justfile (set windows_powershell false)),
}
test! {
name: set_working_directory,
text: "set working-directory := 'foo'",
tree: (justfile (set working_directory "foo")),
}
test! {
name: conditional,
text: "a := if b == c { d } else { e }",

View File

@ -136,15 +136,21 @@ impl<'src, D> Recipe<'src, D> {
!self.attributes.contains(&Attribute::NoExitMessage)
}
fn working_directory<'a>(&'a self, search: &'a Search) -> Option<&Path> {
if self.change_directory() {
Some(if self.submodule_depth > 0 {
&self.working_directory
} else {
&search.working_directory
})
fn working_directory<'a>(&'a self, context: &'a ExecutionContext) -> Option<PathBuf> {
if !self.change_directory() {
return None;
}
let base = if self.submodule_depth > 0 {
&self.working_directory
} else {
None
&context.search.working_directory
};
if let Some(setting) = &context.settings.working_directory {
Some(base.join(setting))
} else {
Some(base.into())
}
}
@ -265,7 +271,7 @@ impl<'src, D> Recipe<'src, D> {
let mut cmd = context.settings.shell_command(config);
if let Some(working_directory) = self.working_directory(context.search) {
if let Some(working_directory) = self.working_directory(context) {
cmd.current_dir(working_directory);
}
@ -408,8 +414,11 @@ impl<'src, D> Recipe<'src, D> {
io_error: error,
})?;
let mut command =
executor.command(&path, self.name(), self.working_directory(context.search))?;
let mut command = executor.command(
&path,
self.name(),
self.working_directory(context).as_deref(),
)?;
if self.takes_positional_arguments(context.settings) {
command.args(positional);

View File

@ -19,6 +19,7 @@ pub(crate) enum Setting<'src> {
Unstable(bool),
WindowsPowerShell(bool),
WindowsShell(Interpreter<'src>),
WorkingDirectory(StringLiteral<'src>),
}
impl<'src> Display for Setting<'src> {
@ -38,7 +39,10 @@ impl<'src> Display for Setting<'src> {
Self::ScriptInterpreter(shell) | Self::Shell(shell) | Self::WindowsShell(shell) => {
write!(f, "[{shell}]")
}
Self::DotenvFilename(value) | Self::DotenvPath(value) | Self::Tempdir(value) => {
Self::DotenvFilename(value)
| Self::DotenvPath(value)
| Self::Tempdir(value)
| Self::WorkingDirectory(value) => {
write!(f, "{value}")
}
}

View File

@ -25,6 +25,7 @@ pub(crate) struct Settings<'src> {
pub(crate) unstable: bool,
pub(crate) windows_powershell: bool,
pub(crate) windows_shell: Option<Interpreter<'src>>,
pub(crate) working_directory: Option<PathBuf>,
}
impl<'src> Settings<'src> {
@ -84,6 +85,9 @@ impl<'src> Settings<'src> {
Setting::Tempdir(tempdir) => {
settings.tempdir = Some(tempdir.cooked);
}
Setting::WorkingDirectory(working_directory) => {
settings.working_directory = Some(working_directory.cooked.into());
}
}
}

View File

@ -62,6 +62,7 @@ fn alias() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -105,6 +106,7 @@ fn assignment() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -162,6 +164,7 @@ fn body() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -231,6 +234,7 @@ fn dependencies() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -338,6 +342,7 @@ fn dependency_argument() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -407,6 +412,7 @@ fn duplicate_recipes() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -454,6 +460,7 @@ fn duplicate_variables() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -504,6 +511,7 @@ fn doc_comment() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -540,6 +548,7 @@ fn empty_justfile() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -697,6 +706,7 @@ fn parameters() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -787,6 +797,7 @@ fn priors() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -837,6 +848,7 @@ fn private() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -887,6 +899,7 @@ fn quiet() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -952,6 +965,7 @@ fn settings() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1005,6 +1019,7 @@ fn shebang() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1055,6 +1070,7 @@ fn simple() {
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1108,6 +1124,7 @@ fn attribute() {
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1176,6 +1193,7 @@ fn module() {
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1199,6 +1217,7 @@ fn module() {
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1269,6 +1288,7 @@ fn module_group() {
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],
@ -1292,6 +1312,7 @@ fn module_group() {
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
"working_directory" : null,
},
"unexports": [],
"warnings": [],

View File

@ -181,3 +181,93 @@ fn search_dir_parent() -> Result<(), Box<dyn Error>> {
Ok(())
}
#[test]
fn setting() {
Test::new()
.justfile(
r#"
set working-directory := 'bar'
print1:
echo "$(basename "$PWD")"
[no-cd]
print2:
echo "$(basename "$PWD")"
"#,
)
.current_dir("foo")
.tree(tree! {
foo: {},
bar: {}
})
.args(["print1", "print2"])
.stderr(
r#"echo "$(basename "$PWD")"
echo "$(basename "$PWD")"
"#,
)
.stdout("bar\nfoo\n")
.run();
}
#[test]
fn no_cd_overrides_setting() {
Test::new()
.justfile(
"
set working-directory := 'bar'
[no-cd]
foo:
cat bar
",
)
.current_dir("foo")
.tree(tree! {
foo: {
bar: "hello",
}
})
.stderr("cat bar\n")
.stdout("hello")
.run();
}
#[test]
fn working_dir_in_submodule_is_relative_to_module_path() {
Test::new()
.write(
"foo/mod.just",
"
set working-directory := 'bar'
@foo:
cat file.txt
",
)
.justfile("mod foo")
.write("foo/bar/file.txt", "FILE")
.arg("foo")
.stdout("FILE")
.run();
}
#[test]
fn working_dir_applies_to_backticks() {
Test::new()
.justfile(
"
set working-directory := 'foo'
file := `cat file.txt`
@foo:
echo {{ file }}
",
)
.write("foo/file.txt", "FILE")
.stdout("FILE\n")
.run();
}