Add [no-cd] attribute (#1400)

This commit is contained in:
Casey Rodarmor 2022-11-02 23:37:35 -07:00 committed by GitHub
parent 659b8211ad
commit 331f61f59c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 106 additions and 21 deletions

View File

@ -1203,13 +1203,14 @@ These functions can fail, for example if a path does not have an extension, whic
Recipes may be annotated with attributes that change their behavior. Recipes may be annotated with attributes that change their behavior.
| Name | Description | | Name | Description |
| ------------------- | ------------------------------------------------- | | ------------------- | ----------------------------------------------- |
| `[no-exit-message]` | Don't print an error message when a recipe fails. | | `[no-cd]` | Don't change directory before executing recipe. |
| `[linux]` | Enable recipe on Linux. | | `[no-exit-message]` | Don't print an error message if recipe fails. |
| `[macos]` | Enable recipe on MacOS. | | `[linux]` | Enable recipe on Linux. |
| `[unix]` | Enable recipe on Unixes. | | `[macos]` | Enable recipe on MacOS. |
| `[windows]` | Enable recipe on Windows. | | `[unix]` | Enable recipe on Unixes. |
| `[windows]` | Enable recipe on Windows. |
#### Enabling and Disabling Recipes #### Enabling and Disabling Recipes
@ -1235,6 +1236,27 @@ run:
main.exe main.exe
``` ```
#### Disabling Changing Directory<sup>master</sup>
`just` normally executes recipes with the current directory set to the
directory that contains the `justfile`. This can be disabled using the
`[no-cd]` attribute. This can be used to create recipes which use paths
relative to the invocation directory, or which operate on the current
directory.
For exmaple, this `commit` recipe:
```make
[no-cd]
commit file:
git add {{file}}
git commit
```
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`.
### Command Evaluation Using Backticks ### Command Evaluation Using Backticks
Backticks can be used to store the result of commands: Backticks can be used to store the result of commands:

View File

@ -8,6 +8,7 @@ use super::*;
pub(crate) enum Attribute { pub(crate) enum Attribute {
Linux, Linux,
Macos, Macos,
NoCd,
NoExitMessage, NoExitMessage,
Unix, Unix,
Windows, Windows,

View File

@ -6,13 +6,15 @@ pub(crate) struct Platform;
impl PlatformInterface for Platform { impl PlatformInterface for Platform {
fn make_shebang_command( fn make_shebang_command(
path: &Path, path: &Path,
working_directory: &Path, working_directory: Option<&Path>,
_shebang: Shebang, _shebang: Shebang,
) -> Result<Command, OutputError> { ) -> Result<Command, OutputError> {
// shebang scripts can be executed directly on unix // shebang scripts can be executed directly on unix
let mut cmd = Command::new(path); let mut cmd = Command::new(path);
cmd.current_dir(working_directory); if let Some(working_directory) = working_directory {
cmd.current_dir(working_directory);
}
Ok(cmd) Ok(cmd)
} }
@ -48,7 +50,7 @@ impl PlatformInterface for Platform {
impl PlatformInterface for Platform { impl PlatformInterface for Platform {
fn make_shebang_command( fn make_shebang_command(
path: &Path, path: &Path,
working_directory: &Path, working_directory: Option<&Path>,
shebang: Shebang, shebang: Shebang,
) -> Result<Command, OutputError> { ) -> Result<Command, OutputError> {
use std::borrow::Cow; use std::borrow::Cow;
@ -57,7 +59,9 @@ impl PlatformInterface for Platform {
let command = if shebang.interpreter.contains('/') { let command = if shebang.interpreter.contains('/') {
// …translate path to the interpreter from unix style to windows style. // …translate path to the interpreter from unix style to windows style.
let mut cygpath = Command::new("cygpath"); let mut cygpath = Command::new("cygpath");
cygpath.current_dir(working_directory); if let Some(working_directory) = working_directory {
cygpath.current_dir(working_directory);
}
cygpath.arg("--windows"); cygpath.arg("--windows");
cygpath.arg(shebang.interpreter); cygpath.arg(shebang.interpreter);
@ -69,7 +73,9 @@ impl PlatformInterface for Platform {
let mut cmd = Command::new(command.as_ref()); let mut cmd = Command::new(command.as_ref());
cmd.current_dir(working_directory); if let Some(working_directory) = working_directory {
cmd.current_dir(working_directory);
}
if let Some(argument) = shebang.argument { if let Some(argument) = shebang.argument {
cmd.arg(argument); cmd.arg(argument);

View File

@ -5,7 +5,7 @@ pub(crate) trait PlatformInterface {
/// shebang line `shebang` /// shebang line `shebang`
fn make_shebang_command( fn make_shebang_command(
path: &Path, path: &Path,
working_directory: &Path, working_directory: Option<&Path>,
shebang: Shebang, shebang: Shebang,
) -> Result<Command, OutputError>; ) -> Result<Command, OutputError>;

View File

@ -66,6 +66,10 @@ impl<'src, D> Recipe<'src, D> {
!self.private !self.private
} }
pub(crate) fn change_directory(&self) -> bool {
!self.attributes.contains(&Attribute::NoCd)
}
pub(crate) fn enabled(&self) -> bool { pub(crate) fn enabled(&self) -> bool {
let windows = self.attributes.contains(&Attribute::Windows); let windows = self.attributes.contains(&Attribute::Windows);
let linux = self.attributes.contains(&Attribute::Linux); let linux = self.attributes.contains(&Attribute::Linux);
@ -190,7 +194,9 @@ impl<'src, D> Recipe<'src, D> {
let mut cmd = context.settings.shell_command(config); let mut cmd = context.settings.shell_command(config);
cmd.current_dir(&context.search.working_directory); if self.change_directory() {
cmd.current_dir(&context.search.working_directory);
}
cmd.arg(command); cmd.arg(command);
@ -322,13 +328,19 @@ impl<'src, D> Recipe<'src, D> {
})?; })?;
// create a command to run the script // create a command to run the script
let mut command = let mut command = Platform::make_shebang_command(
Platform::make_shebang_command(&path, &context.search.working_directory, shebang).map_err( &path,
|output_error| Error::Cygpath { if self.change_directory() {
recipe: self.name(), Some(&context.search.working_directory)
output_error, } else {
}, None
)?; },
shebang,
)
.map_err(|output_error| Error::Cygpath {
recipe: self.name(),
output_error,
})?;
if context.settings.positional_arguments { if context.settings.positional_arguments {
command.args(positional); command.args(positional);

View File

@ -60,6 +60,7 @@ mod json;
mod line_prefixes; mod line_prefixes;
mod misc; mod misc;
mod multibyte_char; mod multibyte_char;
mod no_cd;
mod no_exit_message; mod no_exit_message;
mod os_attributes; mod os_attributes;
mod parser; mod parser;

43
tests/no_cd.rs Normal file
View File

@ -0,0 +1,43 @@
use super::*;
#[test]
fn linewise() {
Test::new()
.justfile(
"
[no-cd]
foo:
cat bar
",
)
.current_dir("foo")
.tree(tree! {
foo: {
bar: "hello",
}
})
.stderr("cat bar\n")
.stdout("hello")
.run();
}
#[test]
fn shebang() {
Test::new()
.justfile(
"
[no-cd]
foo:
#!/bin/sh
cat bar
",
)
.current_dir("foo")
.tree(tree! {
foo: {
bar: "hello",
}
})
.stdout("hello")
.run();
}