Fix shell setting precedence (#1306)
This commit is contained in:
parent
c6809b3364
commit
7c0a960555
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -44,7 +44,7 @@ jobs:
|
||||
with:
|
||||
components: clippy, rustfmt
|
||||
override: true
|
||||
toolchain: 1.53.0
|
||||
toolchain: 1.54.0
|
||||
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
|
||||
|
16
README.md
16
README.md
@ -648,7 +648,8 @@ foo:
|
||||
| `export` | boolean | Export all variables as environment variables. |
|
||||
| `positional-arguments` | boolean | Pass positional arguments. |
|
||||
| `shell` | `[COMMAND, ARGS…]` | Set the command used to invoke recipes and evaluate backticks. |
|
||||
| `windows-powershell` | boolean | Use PowerShell on Windows as default shell. |
|
||||
| `windows-shell` | `[COMMAND, ARGS…]` | Set the command used to invoke recipes and evaluate backticks. |
|
||||
| `windows-powershell` | boolean | Use PowerShell on Windows as default shell. (Deprecated. Use `windows-shell` instead. |
|
||||
|
||||
Boolean settings can be written as:
|
||||
|
||||
@ -775,6 +776,8 @@ hello:
|
||||
Write-Host "Hello, world!"
|
||||
```
|
||||
|
||||
See [powershell.just](https://github.com/casey/just/blob/master/examples/powershell.just) for a justfile that uses PowerShell on all platforms.
|
||||
|
||||
##### Windows PowerShell
|
||||
|
||||
*`set windows-powershell` uses the legacy `powershell.exe` binary, and is no longer recommended. See the `windows-shell` setting above for a more flexible way to control which shell is used on Windows.*
|
||||
@ -2126,6 +2129,17 @@ foo $argument:
|
||||
|
||||
This defeats `just`'s ability to catch typos, for example if you type `$argumant`, but works for all possible values of `argument`, including those with double quotes.
|
||||
|
||||
### Configuring the Shell
|
||||
|
||||
There are a number of ways to configure the shell for linewise recipes, which are the default when a recipe does not start with a `#!` shebang. Their precedence, from highest to lowest, is:
|
||||
|
||||
1. The `--shell` and `--shell-arg` command line options. Passing either of these will cause `just` to ignore any settings in the current justfile.
|
||||
2. `set windows-shell := [...]`
|
||||
3. `set windows-powershell` (deprecated)
|
||||
4. `set shell := [...]`
|
||||
|
||||
Since `set windows-shell` has higher precedence than `set shell`, you can use `set windows-shell` to pick a shell on Windows, and `set shell` to pick a shell for all other platforms.
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
|
29
examples/powershell.just
Normal file
29
examples/powershell.just
Normal file
@ -0,0 +1,29 @@
|
||||
# Cross platform shebang:
|
||||
shebang := if os() == 'windows' {
|
||||
'powershell.exe'
|
||||
} else {
|
||||
'/usr/bin/env pwsh'
|
||||
}
|
||||
|
||||
# Set shell for non-Windows OSs:
|
||||
set shell := ["powershell", "-c"]
|
||||
|
||||
# Set shell for Windows OSs:
|
||||
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
|
||||
|
||||
# If you have PowerShell Core installed and want to use it,
|
||||
# use `pwsh.exe` instead of `powershell.exe`
|
||||
|
||||
linewise:
|
||||
Write-Host "Hello, world!"
|
||||
|
||||
shebang:
|
||||
#!{{shebang}}
|
||||
$PSV = $PSVersionTable.PSVersion | % {"$_" -split "\." }
|
||||
$psver = $PSV[0] + "." + $PSV[1]
|
||||
if ($PSV[2].Length -lt 4) {
|
||||
$psver += "." + $PSV[2] + " Core"
|
||||
} else {
|
||||
$psver += " Desktop"
|
||||
}
|
||||
echo "PowerShell $psver"
|
106
src/settings.rs
106
src/settings.rs
@ -30,50 +30,48 @@ impl<'src> Settings<'src> {
|
||||
}
|
||||
|
||||
pub(crate) fn shell_command(&self, config: &Config) -> Command {
|
||||
let mut cmd = Command::new(self.shell_binary(config));
|
||||
let (command, args) = self.shell(config);
|
||||
|
||||
cmd.args(self.shell_arguments(config));
|
||||
let mut cmd = Command::new(command);
|
||||
|
||||
cmd.args(args);
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
pub(crate) fn shell_binary<'a>(&'a self, config: &'a Config) -> &'a str {
|
||||
let shell_or_args_present = config.shell.is_some() || config.shell_args.is_some();
|
||||
|
||||
if let (Some(shell), false) = (&self.shell, shell_or_args_present) {
|
||||
shell.command.cooked.as_ref()
|
||||
} else if let Some(shell) = &config.shell {
|
||||
shell
|
||||
} else if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) {
|
||||
shell.command.cooked.as_ref()
|
||||
} else if cfg!(windows) && self.windows_powershell {
|
||||
WINDOWS_POWERSHELL_SHELL
|
||||
} else {
|
||||
DEFAULT_SHELL
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn shell_arguments<'a>(&'a self, config: &'a Config) -> Vec<&'a str> {
|
||||
let shell_or_args_present = config.shell.is_some() || config.shell_args.is_some();
|
||||
|
||||
if let (Some(shell), false) = (&self.shell, shell_or_args_present) {
|
||||
shell
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|argument| argument.cooked.as_ref())
|
||||
.collect()
|
||||
} else if let Some(shell_args) = &config.shell_args {
|
||||
shell_args.iter().map(String::as_ref).collect()
|
||||
} else if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) {
|
||||
shell
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|argument| argument.cooked.as_ref())
|
||||
.collect()
|
||||
} else if cfg!(windows) && self.windows_powershell {
|
||||
WINDOWS_POWERSHELL_ARGS.to_vec()
|
||||
} else {
|
||||
DEFAULT_SHELL_ARGS.to_vec()
|
||||
pub(crate) fn shell<'a>(&'a self, config: &'a Config) -> (&'a str, Vec<&'a str>) {
|
||||
match (&config.shell, &config.shell_args) {
|
||||
(Some(shell), Some(shell_args)) => (shell, shell_args.iter().map(String::as_ref).collect()),
|
||||
(Some(shell), None) => (shell, DEFAULT_SHELL_ARGS.to_vec()),
|
||||
(None, Some(shell_args)) => (
|
||||
DEFAULT_SHELL,
|
||||
shell_args.iter().map(String::as_ref).collect(),
|
||||
),
|
||||
(None, None) => {
|
||||
if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) {
|
||||
(
|
||||
shell.command.cooked.as_ref(),
|
||||
shell
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|argument| argument.cooked.as_ref())
|
||||
.collect(),
|
||||
)
|
||||
} else if cfg!(windows) && self.windows_powershell {
|
||||
(WINDOWS_POWERSHELL_SHELL, WINDOWS_POWERSHELL_ARGS.to_vec())
|
||||
} else if let Some(shell) = &self.shell {
|
||||
(
|
||||
shell.command.cooked.as_ref(),
|
||||
shell
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|argument| argument.cooked.as_ref())
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
(DEFAULT_SHELL, DEFAULT_SHELL_ARGS.to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,8 +89,7 @@ mod tests {
|
||||
..testing::config(&[])
|
||||
};
|
||||
|
||||
assert_eq!(settings.shell_binary(&config), "sh");
|
||||
assert_eq!(settings.shell_arguments(&config), vec!["-cu"]);
|
||||
assert_eq!(settings.shell(&config), ("sh", vec!["-cu"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -106,14 +103,12 @@ mod tests {
|
||||
};
|
||||
|
||||
if cfg!(windows) {
|
||||
assert_eq!(settings.shell_binary(&config), "powershell.exe");
|
||||
assert_eq!(
|
||||
settings.shell_arguments(&config),
|
||||
vec!["-NoLogo", "-Command"]
|
||||
settings.shell(&config),
|
||||
("powershell.exe", vec!["-NoLogo", "-Command"])
|
||||
);
|
||||
} else {
|
||||
assert_eq!(settings.shell_binary(&config), "sh");
|
||||
assert_eq!(settings.shell_arguments(&config), vec!["-cu"]);
|
||||
assert_eq!(settings.shell(&config), ("sh", vec!["-cu"]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,8 +123,7 @@ mod tests {
|
||||
..testing::config(&[])
|
||||
};
|
||||
|
||||
assert_eq!(settings.shell_binary(&config), "lol");
|
||||
assert_eq!(settings.shell_arguments(&config), vec!["-nice"]);
|
||||
assert_eq!(settings.shell(&config), ("lol", vec!["-nice"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -144,8 +138,7 @@ mod tests {
|
||||
..testing::config(&[])
|
||||
};
|
||||
|
||||
assert_eq!(settings.shell_binary(&config), "lol");
|
||||
assert_eq!(settings.shell_arguments(&config), vec!["-nice"]);
|
||||
assert_eq!(settings.shell(&config), ("lol", vec!["-nice"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -170,8 +163,7 @@ mod tests {
|
||||
..testing::config(&[])
|
||||
};
|
||||
|
||||
assert_eq!(settings.shell_binary(&config), "asdf.exe");
|
||||
assert_eq!(settings.shell_arguments(&config), vec!["-nope"]);
|
||||
assert_eq!(settings.shell(&config), ("asdf.exe", vec!["-nope"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -184,7 +176,7 @@ mod tests {
|
||||
..testing::config(&[])
|
||||
};
|
||||
|
||||
assert_eq!(settings.shell_binary(&config), "lol");
|
||||
assert_eq!(settings.shell(&config).0, "lol");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -198,12 +190,6 @@ mod tests {
|
||||
..testing::config(&[])
|
||||
};
|
||||
|
||||
if cfg!(windows) {
|
||||
assert_eq!(settings.shell_binary(&config), "powershell.exe");
|
||||
} else {
|
||||
assert_eq!(settings.shell_binary(&config), "sh");
|
||||
}
|
||||
|
||||
assert_eq!(settings.shell_arguments(&config), vec!["-nice"]);
|
||||
assert_eq!(settings.shell(&config), ("sh", vec!["-nice"]));
|
||||
}
|
||||
}
|
||||
|
@ -217,9 +217,10 @@ impl Subcommand {
|
||||
let mut child = match result {
|
||||
Ok(child) => child,
|
||||
Err(io_error) => {
|
||||
let (shell_binary, shell_arguments) = justfile.settings.shell(config);
|
||||
return Err(Error::ChooserInvoke {
|
||||
shell_binary: justfile.settings.shell_binary(config).to_owned(),
|
||||
shell_arguments: justfile.settings.shell_arguments(config).join(" "),
|
||||
shell_binary: shell_binary.to_owned(),
|
||||
shell_arguments: shell_arguments.join(" "),
|
||||
chooser,
|
||||
io_error,
|
||||
});
|
||||
|
@ -76,7 +76,5 @@ mod subsequents;
|
||||
mod tempdir;
|
||||
mod undefined_variables;
|
||||
#[cfg(target_family = "windows")]
|
||||
mod windows_powershell;
|
||||
#[cfg(target_family = "windows")]
|
||||
mod windows_shell;
|
||||
mod working_directory;
|
||||
|
@ -1,18 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn windows_poweshell_setting_uses_powershell() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
r#"
|
||||
set windows-powershell
|
||||
|
||||
foo:
|
||||
Write-Output bar
|
||||
"#,
|
||||
)
|
||||
.shell(false)
|
||||
.stdout("bar\r\n")
|
||||
.stderr("Write-Output bar\n")
|
||||
.run();
|
||||
}
|
@ -6,6 +6,42 @@ fn windows_shell_setting() {
|
||||
.justfile(
|
||||
r#"
|
||||
set windows-shell := ["pwsh.exe", "-NoLogo", "-Command"]
|
||||
set shell := ["asdfasdfasdfasdf"]
|
||||
|
||||
foo:
|
||||
Write-Output bar
|
||||
"#,
|
||||
)
|
||||
.shell(false)
|
||||
.stdout("bar\r\n")
|
||||
.stderr("Write-Output bar\n")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_powershell_setting_uses_powershell() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
r#"
|
||||
set windows-powershell
|
||||
set shell := ["asdfasdfasdfasdf"]
|
||||
|
||||
foo:
|
||||
Write-Output bar
|
||||
"#,
|
||||
)
|
||||
.shell(false)
|
||||
.stdout("bar\r\n")
|
||||
.stderr("Write-Output bar\n")
|
||||
.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_poweshell_setting_uses_powershell() {
|
||||
Test::new()
|
||||
.justfile(
|
||||
r#"
|
||||
set windows-powershell
|
||||
|
||||
foo:
|
||||
Write-Output bar
|
||||
|
Loading…
Reference in New Issue
Block a user