1pub trait CommandExt {
2 fn run(&mut self) -> std::io::Result<()>;
3 fn check_output(&mut self) -> std::io::Result<std::process::Output>;
4}
5
6pub trait OutputExt {
7 fn stdout(&self) -> &str;
8 fn stderr(&self) -> &str;
9 fn success(&self) -> bool;
10}
11
12impl CommandExt for std::process::Command {
13 fn run(&mut self) -> std::io::Result<()> {
14 let status = self.status()?;
15 if !status.success() {
16 return Err(std::io::Error::new(
17 std::io::ErrorKind::Other,
18 format!("Command exited with code: {}", status.code().unwrap()),
19 ));
20 }
21 Ok(())
22 }
23
24 fn check_output(&mut self) -> std::io::Result<std::process::Output> {
25 let output = self.output()?;
26 if output.status.success() {
27 Ok(output)
28 } else {
29 Err(std::io::Error::new(
30 std::io::ErrorKind::Other,
31 format!(
32 "Command exited with code: {}",
33 output.status.code().unwrap()
34 ),
35 ))
36 }
37 }
38}
39
40impl OutputExt for std::process::Output {
41 fn stdout(&self) -> &str {
42 std::str::from_utf8(&self.stdout).expect("Failed to convert stdout to str")
43 }
44
45 fn stderr(&self) -> &str {
46 std::str::from_utf8(&self.stderr).expect("Failed to convert stderr to str")
47 }
48 fn success(&self) -> bool {
49 self.status.success()
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_output() -> std::io::Result<()> {
59 let output = std::process::Command::new("echo").arg("hello").output()?;
60 let s = output.stdout();
61 assert_eq!(s, "hello\n");
62 Ok(())
63 }
64
65 #[test]
66 fn test_run() -> std::io::Result<()> {
67 std::process::Command::new("echo").arg("hello").run()?;
68 Ok(())
69 }
70}