Skip to content

Commit 8c61b0b

Browse files
committed
basic support for 'sh' based execution (#450)
1 parent 2ba836f commit 8c61b0b

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

crate-status.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ Check out the [performance discussion][git-traverse-performance] as well.
241241
* [ ] for push
242242

243243
### git-command
244-
* [ ] execute commands with `sh`
244+
* [x] execute commands directly
245+
* [x] execute commands with `sh`
246+
* [ ] support for `GIT_EXEC_PATH` environment variable with `git-sec` filter
245247

246248
### git-note
247249

git-command/src/lib.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,77 @@
11
#![deny(rust_2018_idioms)]
22
#![forbid(unsafe_code)]
3-
#![allow(dead_code)]
43

54
use std::ffi::OsString;
65

76
pub struct Prepare {
87
command: OsString,
8+
stdin: std::process::Stdio,
9+
stdout: std::process::Stdio,
10+
stderr: std::process::Stdio,
911
use_shell: bool,
1012
}
1113

1214
mod prepare {
1315
use crate::Prepare;
16+
use std::process::Stdio;
1417

1518
/// Builder
1619
impl Prepare {
20+
/// If called, the command will not be executed directly, but with `sh`.
21+
///
22+
/// This also allows to pass shell scripts as command, or use commands that contain arguments which are subsequently
23+
/// parsed by `sh`.
1724
pub fn with_shell(mut self) -> Self {
1825
self.use_shell = true;
1926
self
2027
}
28+
29+
/// Configure the process to use `stdio` for _stdin.
30+
pub fn stdin(mut self, stdio: Stdio) -> Self {
31+
self.stdin = stdio;
32+
self
33+
}
34+
/// Configure the process to use `stdio` for _stdout_.
35+
pub fn stdout(mut self, stdio: Stdio) -> Self {
36+
self.stdout = stdio;
37+
self
38+
}
39+
/// Configure the process to use `stdio` for _stderr.
40+
pub fn stderr(mut self, stdio: Stdio) -> Self {
41+
self.stderr = stdio;
42+
self
43+
}
2144
}
2245

2346
/// Finalization
2447
impl Prepare {
2548
pub fn spawn(self) -> std::io::Result<std::process::Child> {
26-
todo!("create command and spawn that")
49+
let mut cmd = if self.use_shell {
50+
let mut cmd = std::process::Command::new(if cfg!(windows) { "sh" } else { "/bin/sh" });
51+
cmd.arg("-c");
52+
cmd.arg(self.command);
53+
cmd
54+
} else {
55+
std::process::Command::new(self.command)
56+
};
57+
cmd.stdin(self.stdin).stdout(self.stdout).stderr(self.stderr);
58+
cmd.spawn()
2759
}
2860
}
2961
}
3062

63+
/// Prepare `cmd` for [spawning][Process::spawn()] by configuring it with various builder methods.
64+
///
65+
/// Note that the default IO is configured for typical API usage, that is
66+
///
67+
/// - `stdin` is null
68+
/// - `stdout` and `stderr` are captured.
3169
pub fn prepare(cmd: impl Into<OsString>) -> Prepare {
3270
Prepare {
3371
command: cmd.into(),
72+
stdin: std::process::Stdio::null(),
73+
stdout: std::process::Stdio::piped(),
74+
stderr: std::process::Stdio::piped(),
3475
use_shell: false,
3576
}
3677
}

git-command/tests/command.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1+
use git_testtools::Result;
2+
13
mod spawn {
24
#[test]
3-
#[ignore]
4-
fn direct_command_execution_searches_in_path() {
5-
git_command::prepare(if cfg!(unix) { "ls" } else { "dir.exe" })
6-
.spawn()
7-
.unwrap();
5+
fn direct_command_execution_searches_in_path() -> crate::Result {
6+
assert!(git_command::prepare(if cfg!(unix) { "ls" } else { "dir.exe" })
7+
.spawn()?
8+
.wait()?
9+
.success());
10+
Ok(())
11+
}
12+
13+
#[cfg(unix)]
14+
#[test]
15+
fn direct_command_with_absolute_command_path() -> crate::Result {
16+
assert!(git_command::prepare("/bin/ls").spawn()?.wait()?.success());
17+
Ok(())
818
}
919

1020
mod with_shell {
1121
#[test]
12-
#[ignore]
13-
fn command_in_path_with_args() {
14-
git_command::prepare(if cfg!(unix) { "ls -l" } else { "dir.exe -a" })
22+
fn command_in_path_with_args() -> crate::Result {
23+
assert!(git_command::prepare(if cfg!(unix) { "ls -l" } else { "dir.exe -a" })
1524
.with_shell()
16-
.spawn()
17-
.unwrap();
25+
.spawn()?
26+
.wait()?
27+
.success());
28+
Ok(())
29+
}
30+
31+
#[test]
32+
fn sh_shell_specific_script_code() -> crate::Result {
33+
assert!(git_command::prepare(":;:;:").with_shell().spawn()?.wait()?.success());
34+
Ok(())
1835
}
1936
}
2037
}

0 commit comments

Comments
 (0)