Fix shell setting precedence (#1306)

This commit is contained in:
Casey Rodarmor 2022-08-08 19:50:31 -07:00 committed by GitHub
parent c6809b3364
commit 7c0a960555
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 130 additions and 84 deletions

View File

@ -44,7 +44,7 @@ jobs:
with: with:
components: clippy, rustfmt components: clippy, rustfmt
override: true override: true
toolchain: 1.53.0 toolchain: 1.54.0
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1

View File

@ -648,7 +648,8 @@ foo:
| `export` | boolean | Export all variables as environment variables. | | `export` | boolean | Export all variables as environment variables. |
| `positional-arguments` | boolean | Pass positional arguments. | | `positional-arguments` | boolean | Pass positional arguments. |
| `shell` | `[COMMAND, ARGS…]` | Set the command used to invoke recipes and evaluate backticks. | | `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: Boolean settings can be written as:
@ -775,6 +776,8 @@ hello:
Write-Host "Hello, world!" 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 ##### 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.* *`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. 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 Changelog
--------- ---------

29
examples/powershell.just Normal file
View 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"

View File

@ -30,50 +30,48 @@ impl<'src> Settings<'src> {
} }
pub(crate) fn shell_command(&self, config: &Config) -> Command { 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 cmd
} }
pub(crate) fn shell_binary<'a>(&'a self, config: &'a Config) -> &'a str { pub(crate) fn shell<'a>(&'a self, config: &'a Config) -> (&'a str, Vec<&'a str>) {
let shell_or_args_present = config.shell.is_some() || config.shell_args.is_some(); match (&config.shell, &config.shell_args) {
(Some(shell), Some(shell_args)) => (shell, shell_args.iter().map(String::as_ref).collect()),
if let (Some(shell), false) = (&self.shell, shell_or_args_present) { (Some(shell), None) => (shell, DEFAULT_SHELL_ARGS.to_vec()),
shell.command.cooked.as_ref() (None, Some(shell_args)) => (
} else if let Some(shell) = &config.shell { DEFAULT_SHELL,
shell shell_args.iter().map(String::as_ref).collect(),
} else if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) { ),
shell.command.cooked.as_ref() (None, None) => {
} else if cfg!(windows) && self.windows_powershell { if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) {
WINDOWS_POWERSHELL_SHELL (
} else { shell.command.cooked.as_ref(),
DEFAULT_SHELL shell
} .arguments
} .iter()
.map(|argument| argument.cooked.as_ref())
pub(crate) fn shell_arguments<'a>(&'a self, config: &'a Config) -> Vec<&'a str> { .collect(),
let shell_or_args_present = config.shell.is_some() || config.shell_args.is_some(); )
} else if cfg!(windows) && self.windows_powershell {
if let (Some(shell), false) = (&self.shell, shell_or_args_present) { (WINDOWS_POWERSHELL_SHELL, WINDOWS_POWERSHELL_ARGS.to_vec())
shell } else if let Some(shell) = &self.shell {
.arguments (
.iter() shell.command.cooked.as_ref(),
.map(|argument| argument.cooked.as_ref()) shell
.collect() .arguments
} else if let Some(shell_args) = &config.shell_args { .iter()
shell_args.iter().map(String::as_ref).collect() .map(|argument| argument.cooked.as_ref())
} else if let (true, Some(shell)) = (cfg!(windows), &self.windows_shell) { .collect(),
shell )
.arguments } else {
.iter() (DEFAULT_SHELL, DEFAULT_SHELL_ARGS.to_vec())
.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()
} }
} }
} }
@ -91,8 +89,7 @@ mod tests {
..testing::config(&[]) ..testing::config(&[])
}; };
assert_eq!(settings.shell_binary(&config), "sh"); assert_eq!(settings.shell(&config), ("sh", vec!["-cu"]));
assert_eq!(settings.shell_arguments(&config), vec!["-cu"]);
} }
#[test] #[test]
@ -106,14 +103,12 @@ mod tests {
}; };
if cfg!(windows) { if cfg!(windows) {
assert_eq!(settings.shell_binary(&config), "powershell.exe");
assert_eq!( assert_eq!(
settings.shell_arguments(&config), settings.shell(&config),
vec!["-NoLogo", "-Command"] ("powershell.exe", vec!["-NoLogo", "-Command"])
); );
} else { } else {
assert_eq!(settings.shell_binary(&config), "sh"); assert_eq!(settings.shell(&config), ("sh", vec!["-cu"]));
assert_eq!(settings.shell_arguments(&config), vec!["-cu"]);
} }
} }
@ -128,8 +123,7 @@ mod tests {
..testing::config(&[]) ..testing::config(&[])
}; };
assert_eq!(settings.shell_binary(&config), "lol"); assert_eq!(settings.shell(&config), ("lol", vec!["-nice"]));
assert_eq!(settings.shell_arguments(&config), vec!["-nice"]);
} }
#[test] #[test]
@ -144,8 +138,7 @@ mod tests {
..testing::config(&[]) ..testing::config(&[])
}; };
assert_eq!(settings.shell_binary(&config), "lol"); assert_eq!(settings.shell(&config), ("lol", vec!["-nice"]));
assert_eq!(settings.shell_arguments(&config), vec!["-nice"]);
} }
#[test] #[test]
@ -170,8 +163,7 @@ mod tests {
..testing::config(&[]) ..testing::config(&[])
}; };
assert_eq!(settings.shell_binary(&config), "asdf.exe"); assert_eq!(settings.shell(&config), ("asdf.exe", vec!["-nope"]));
assert_eq!(settings.shell_arguments(&config), vec!["-nope"]);
} }
#[test] #[test]
@ -184,7 +176,7 @@ mod tests {
..testing::config(&[]) ..testing::config(&[])
}; };
assert_eq!(settings.shell_binary(&config), "lol"); assert_eq!(settings.shell(&config).0, "lol");
} }
#[test] #[test]
@ -198,12 +190,6 @@ mod tests {
..testing::config(&[]) ..testing::config(&[])
}; };
if cfg!(windows) { assert_eq!(settings.shell(&config), ("sh", vec!["-nice"]));
assert_eq!(settings.shell_binary(&config), "powershell.exe");
} else {
assert_eq!(settings.shell_binary(&config), "sh");
}
assert_eq!(settings.shell_arguments(&config), vec!["-nice"]);
} }
} }

View File

@ -217,9 +217,10 @@ impl Subcommand {
let mut child = match result { let mut child = match result {
Ok(child) => child, Ok(child) => child,
Err(io_error) => { Err(io_error) => {
let (shell_binary, shell_arguments) = justfile.settings.shell(config);
return Err(Error::ChooserInvoke { return Err(Error::ChooserInvoke {
shell_binary: justfile.settings.shell_binary(config).to_owned(), shell_binary: shell_binary.to_owned(),
shell_arguments: justfile.settings.shell_arguments(config).join(" "), shell_arguments: shell_arguments.join(" "),
chooser, chooser,
io_error, io_error,
}); });

View File

@ -76,7 +76,5 @@ mod subsequents;
mod tempdir; mod tempdir;
mod undefined_variables; mod undefined_variables;
#[cfg(target_family = "windows")] #[cfg(target_family = "windows")]
mod windows_powershell;
#[cfg(target_family = "windows")]
mod windows_shell; mod windows_shell;
mod working_directory; mod working_directory;

View File

@ -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();
}

View File

@ -6,6 +6,42 @@ fn windows_shell_setting() {
.justfile( .justfile(
r#" r#"
set windows-shell := ["pwsh.exe", "-NoLogo", "-Command"] 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: foo:
Write-Output bar Write-Output bar