Skip to content

Commit

Permalink
Merge pull request GitoxideLabs#1718 from GitoxideLabs/with-shell-choice
Browse files Browse the repository at this point in the history
feat!: allow to choose the shell to use with `Prepare::with_shell_program()`.
  • Loading branch information
Byron authored Dec 9, 2024
2 parents 06ef1e9 + 838420f commit 801f9e9
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
16 changes: 14 additions & 2 deletions gix-command/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ pub struct Prepare {
pub args: Vec<OsString>,
/// environment variables to set in the spawned process.
pub env: Vec<(OsString, OsString)>,
/// If `true`, we will use `sh` to execute the `command`.
/// If `true`, we will use `shell_program` or `sh` to execute the `command`.
pub use_shell: bool,
/// The name or path to the shell program to use instead of `sh`.
pub shell_program: Option<OsString>,
/// If `true` (default `true` on windows and `false` everywhere else)
/// we will see if it's safe to manually invoke `command` after splitting
/// its arguments as a shell would do.
Expand Down Expand Up @@ -103,6 +105,12 @@ mod prepare {
self
}

/// Set the name or path to the shell `program` to use, to avoid using the default shell which is `sh`.
pub fn with_shell_program(mut self, program: impl Into<OsString>) -> Self {
self.shell_program = Some(program.into());
self
}

/// Unconditionally turn off using the shell when spawning the command.
/// Note that not using the shell is the default so an effective use of this method
/// is some time after [`with_shell()`][Prepare::with_shell()] was called.
Expand Down Expand Up @@ -199,7 +207,10 @@ mod prepare {
cmd
}
None => {
let mut cmd = Command::new(if cfg!(windows) { "sh" } else { "/bin/sh" });
let mut cmd = Command::new(
prep.shell_program
.unwrap_or(if cfg!(windows) { "sh" } else { "/bin/sh" }.into()),
);
cmd.arg("-c");
if !prep.args.is_empty() {
if prep.command.to_str().map_or(true, |cmd| !cmd.contains("$@")) {
Expand Down Expand Up @@ -417,6 +428,7 @@ pub mod shebang {
pub fn prepare(cmd: impl Into<OsString>) -> Prepare {
Prepare {
command: cmd.into(),
shell_program: None,
context: None,
stdin: std::process::Stdio::null(),
stdout: std::process::Stdio::piped(),
Expand Down
18 changes: 18 additions & 0 deletions gix-command/tests/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,24 @@ mod prepare {
);
}

#[test]
fn single_and_multiple_arguments_as_part_of_command_with_given_shell() {
let cmd = std::process::Command::from(
gix_command::prepare("ls first second third")
.with_shell()
.with_shell_program("/somepath/to/bash"),
);
assert_eq!(
format!("{cmd:?}"),
if cfg!(windows) {
quoted(&["ls", "first", "second", "third"])
} else {
quoted(&["/somepath/to/bash", "-c", "ls first second third", "--"])
},
"with shell, this works as it performs word splitting on Windows, but on linux (or without splitting) it uses the given shell"
);
}

#[test]
fn single_and_complex_arguments_as_part_of_command_with_shell() {
let cmd = std::process::Command::from(gix_command::prepare("ls --foo \"a b\"").arg("additional").with_shell());
Expand Down

0 comments on commit 801f9e9

Please sign in to comment.