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:
|
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
|
||||||
|
|
||||||
|
16
README.md
16
README.md
@ -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
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 {
|
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"]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
@ -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(
|
.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
|
||||||
|
Loading…
Reference in New Issue
Block a user