Skip to content

Commit 801f9e9

Browse files
authored
Merge pull request #1718 from GitoxideLabs/with-shell-choice
feat!: allow to choose the shell to use with `Prepare::with_shell_program()`.
2 parents 06ef1e9 + 838420f commit 801f9e9

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

gix-command/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ pub struct Prepare {
2626
pub args: Vec<OsString>,
2727
/// environment variables to set in the spawned process.
2828
pub env: Vec<(OsString, OsString)>,
29-
/// If `true`, we will use `sh` to execute the `command`.
29+
/// If `true`, we will use `shell_program` or `sh` to execute the `command`.
3030
pub use_shell: bool,
31+
/// The name or path to the shell program to use instead of `sh`.
32+
pub shell_program: Option<OsString>,
3133
/// If `true` (default `true` on windows and `false` everywhere else)
3234
/// we will see if it's safe to manually invoke `command` after splitting
3335
/// its arguments as a shell would do.
@@ -103,6 +105,12 @@ mod prepare {
103105
self
104106
}
105107

108+
/// Set the name or path to the shell `program` to use, to avoid using the default shell which is `sh`.
109+
pub fn with_shell_program(mut self, program: impl Into<OsString>) -> Self {
110+
self.shell_program = Some(program.into());
111+
self
112+
}
113+
106114
/// Unconditionally turn off using the shell when spawning the command.
107115
/// Note that not using the shell is the default so an effective use of this method
108116
/// is some time after [`with_shell()`][Prepare::with_shell()] was called.
@@ -199,7 +207,10 @@ mod prepare {
199207
cmd
200208
}
201209
None => {
202-
let mut cmd = Command::new(if cfg!(windows) { "sh" } else { "/bin/sh" });
210+
let mut cmd = Command::new(
211+
prep.shell_program
212+
.unwrap_or(if cfg!(windows) { "sh" } else { "/bin/sh" }.into()),
213+
);
203214
cmd.arg("-c");
204215
if !prep.args.is_empty() {
205216
if prep.command.to_str().map_or(true, |cmd| !cmd.contains("$@")) {
@@ -417,6 +428,7 @@ pub mod shebang {
417428
pub fn prepare(cmd: impl Into<OsString>) -> Prepare {
418429
Prepare {
419430
command: cmd.into(),
431+
shell_program: None,
420432
context: None,
421433
stdin: std::process::Stdio::null(),
422434
stdout: std::process::Stdio::piped(),

gix-command/tests/command.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,24 @@ mod prepare {
279279
);
280280
}
281281

282+
#[test]
283+
fn single_and_multiple_arguments_as_part_of_command_with_given_shell() {
284+
let cmd = std::process::Command::from(
285+
gix_command::prepare("ls first second third")
286+
.with_shell()
287+
.with_shell_program("/somepath/to/bash"),
288+
);
289+
assert_eq!(
290+
format!("{cmd:?}"),
291+
if cfg!(windows) {
292+
quoted(&["ls", "first", "second", "third"])
293+
} else {
294+
quoted(&["/somepath/to/bash", "-c", "ls first second third", "--"])
295+
},
296+
"with shell, this works as it performs word splitting on Windows, but on linux (or without splitting) it uses the given shell"
297+
);
298+
}
299+
282300
#[test]
283301
fn single_and_complex_arguments_as_part_of_command_with_shell() {
284302
let cmd = std::process::Command::from(gix_command::prepare("ls --foo \"a b\"").arg("additional").with_shell());

0 commit comments

Comments
 (0)