Breaking changes for --shell

This commit is contained in:
Félix Saparelli 2024-04-20 22:15:56 +12:00
parent b72248a38c
commit 184ac9d463
No known key found for this signature in database
2 changed files with 51 additions and 45 deletions

View File

@ -434,18 +434,18 @@ pub struct Args {
/// Use a different shell
///
/// By default, Watchexec will use 'sh' on unix and 'cmd' (CMD.EXE) on Windows. With this, you
/// can override that and use a different shell, for example one with more features or one which
/// has your custom aliases and functions.
/// By default, Watchexec will use '$SHELL' if it's defined or a default of 'sh' on Unix-likes,
/// and either 'pwsh', 'powershell', or 'cmd' (CMD.EXE) on Windows, depending on what Watchexec
/// detects is the running shell.
///
/// With this option, you can override that and use a different shell, for example one with more
/// features or one which has your custom aliases and functions.
///
/// If the value has spaces, it is parsed as a command line, and the first word used as the
/// shell program, with the rest as arguments to the shell.
///
/// The command is run with the '-c' flag (except for 'cmd' on Windows, where it's '/C').
///
/// Note that the default shell will change at the next major release: the value of '$SHELL'
/// will be respected, falling back to 'sh' on unix and to PowerShell on Windows.
///
/// The special value 'none' can be used to disable shell use entirely. In that case, the
/// command provided to Watchexec will be parsed, with the first word being the executable and
/// the rest being the arguments, and executed directly. Note that this parsing is rudimentary,
@ -465,7 +465,7 @@ pub struct Args {
///
/// $ watchexec --shell=pwsh -- Test-Connection localhost
///
/// Use with cmd (default on Windows):
/// Use with CMD.exe:
///
/// $ watchexec --shell=cmd -- dir
///
@ -492,17 +492,6 @@ pub struct Args {
)]
pub no_shell: bool,
/// Don't use a shell
///
/// This is a deprecated alias for '--shell=none'.
#[arg(
long,
hide = true,
help_heading = OPTSET_COMMAND,
alias = "no-shell", // deprecated
)]
pub no_shell_long: bool,
/// Shorthand for '--emit-events=none'
///
/// This is the old way to disable event emission into the environment. See '--emit-events' for

View File

@ -1,7 +1,7 @@
use std::{
borrow::Cow,
collections::HashMap,
env::current_dir,
env::{current_dir, var},
ffi::{OsStr, OsString},
fs::File,
io::{IsTerminal, Write},
@ -469,35 +469,52 @@ fn interpret_command_args(args: &Args) -> Result<Arc<Command>> {
panic!("(clap) Bug: command is not present");
}
let shell = match if args.no_shell || args.no_shell_long {
let shell = if args.no_shell {
None
} else {
args.shell.as_deref().or(Some("default"))
} {
Some("") => return Err(RuntimeError::CommandShellEmptyShell).into_diagnostic(),
Some("none") | None => None,
#[cfg(windows)]
Some("default") | Some("cmd") | Some("cmd.exe") | Some("CMD") | Some("CMD.EXE") => {
Some(Shell::cmd())
}
#[cfg(not(windows))]
Some("default") => Some(Shell::new("sh")),
Some(other) => {
let sh = other.split_ascii_whitespace().collect::<Vec<_>>();
// UNWRAP: checked by Some("")
#[allow(clippy::unwrap_used)]
let (shprog, shopts) = sh.split_first().unwrap();
Some(Shell {
prog: shprog.into(),
options: shopts.iter().map(|s| (*s).to_string()).collect(),
program_option: Some(Cow::Borrowed(OsStr::new("-c"))),
let shell = args.shell.clone().or_else(|| var("SHELL").ok());
match shell
.as_deref()
.or_else(|| {
if cfg!(not(windows)) {
Some("sh")
} else if var("POWERSHELL_DISTRIBUTION_CHANNEL").is_ok()
&& (which::which("pwsh").is_ok() || which::which("pwsh.exe").is_ok())
{
trace!("detected pwsh");
Some("pwsh")
} else if var("PSModulePath").is_ok()
&& (which::which("powershell").is_ok()
|| which::which("powershell.exe").is_ok())
{
trace!("detected powershell");
Some("powershell")
} else {
Some("cmd")
}
})
.or(Some("default"))
{
Some("") => return Err(RuntimeError::CommandShellEmptyShell).into_diagnostic(),
Some("none") | None => None,
#[cfg(windows)]
Some("cmd") | Some("cmd.exe") | Some("CMD") | Some("CMD.EXE") => Some(Shell::cmd()),
Some(other) => {
let sh = other.split_ascii_whitespace().collect::<Vec<_>>();
// UNWRAP: checked by Some("")
#[allow(clippy::unwrap_used)]
let (shprog, shopts) = sh.split_first().unwrap();
Some(Shell {
prog: shprog.into(),
options: shopts.iter().map(|s| (*s).to_string()).collect(),
program_option: Some(Cow::Borrowed(OsStr::new("-c"))),
})
}
}
};