From 8d709525ef9ddf3b0699837bc1f50e82caca9f35 Mon Sep 17 00:00:00 2001 From: Kurt Lawrence Date: Thu, 19 Oct 2023 17:43:40 +1000 Subject: [PATCH] add piping extension to commands (#21) --- src/cmd.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/cmd.rs b/src/cmd.rs index a462400..5c66006 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -206,6 +206,16 @@ pub trait CommandBuilder { /// Akin to [`Command::current_dir`]. fn with_current_dir>(self, path: P) -> Self; + + /// Pipe `stdout` of _this_ into `next` command. + fn pipe(self, next: Command) -> Result + where + Self: Sized; + + /// Pipe `stderr` of _this_ into `next` command. + fn pipe_stderr(self, next: Command) -> Result + where + Self: Sized; } impl CommandBuilder for Command { @@ -227,6 +237,32 @@ impl CommandBuilder for Command { self.current_dir(dir); self } + + fn pipe(mut self, mut next: Command) -> Result { + let cmd = self + .stdout(Stdio::piped()) + .spawn() + .map_err(|e| miette!("encountered error with command {}: {e}", self.cmd_str()))?; + + let out = cmd.stdout.expect("piped so should exist"); + let stdin = Stdio::from(out); + + next.stdin(stdin); + Ok(next) + } + + fn pipe_stderr(mut self, mut next: Command) -> Result { + let cmd = self + .stderr(Stdio::piped()) + .spawn() + .map_err(|e| miette!("encountered error with command {}: {e}", self.cmd_str()))?; + + let out = cmd.stderr.expect("piped so should exist"); + let stdin = Stdio::from(out); + + next.stdin(stdin); + Ok(next) + } } /// Output [`Command`] as a text string, useful for debugging. @@ -325,6 +361,7 @@ mod tests { let x = cmd!(watcmd: "foo").execute_str(Verbose).unwrap_err(); assert_snapshot!("unknown-cmd", pretty_print_err(x)); } + #[test] fn cmd_naming_with_env() { let x = cmd!(ls).with_env("YO", "zog").cmd_str(); @@ -338,4 +375,39 @@ mod tests { .cmd_str(); assert_eq!(&x, "ls foo bar"); } + + #[test] + fn cmd_piping() { + let x = cmd!(ls) + .pipe(cmd!(grep: Cargo.*)) + .unwrap() + .execute_str(Quiet) + .unwrap(); + let mut x = x.trim().split('\n').collect::>(); + x.sort(); + + assert_eq!(&x, &["Cargo.lock", "Cargo.toml",]); + + let x = cmd!(ls) + .pipe(cmd!(grep: Cargo.*)) + .unwrap() + .pipe(cmd!(grep: toml)) + .unwrap() + .execute_str(Quiet) + .unwrap(); + let mut x = x.trim().split('\n').collect::>(); + x.sort(); + + assert_eq!(&x, &["Cargo.toml",]); + + let x = cmd!(ls: foo) + .pipe_stderr(cmd!(grep: foo)) + .unwrap() + .execute_str(Quiet) + .unwrap(); + let mut x = x.trim().split('\n').collect::>(); + x.sort(); + + assert_eq!(&x, &["ls: cannot access 'foo': No such file or directory",]); + } }