1use std::process::Command;
2use std::io;
3use std::fmt;
4
5#[derive(Debug)]
7pub struct ChildError {
8 pub program: String,
10 pub code: Option<i32>
12}
13
14impl fmt::Display for ChildError {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 write!(
17 f,
18 "program `{}` failed with status code {}",
19 self.program,
20 match self.code {
21 Some(code) => code.to_string(),
22 None => String::from("unknown")
23 }
24 )
25 }
26}
27
28#[derive(Debug)]
30pub enum CmdSpawnError {
31 IO(io::Error),
33 Child(ChildError)
35}
36
37impl fmt::Display for CmdSpawnError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match &*self {
40 CmdSpawnError::IO(e) => write!(f, "command IO error {}", e),
41 CmdSpawnError::Child(e) => write!(f, "child {}", e),
42 }
43 }
44}
45
46impl From<CmdSpawnError> for io::Error {
47 fn from(val: CmdSpawnError) -> Self {
48 match val {
49 CmdSpawnError::IO(e) => e,
50 CmdSpawnError::Child(e) => {
51 io::Error::new(io::ErrorKind::Other, format!("{}", e))
52 },
53 }
54 }
55}
56
57pub fn command_spawn (command: &mut Command) -> Result<(), CmdSpawnError> {
65 let process = command.spawn();
66 match process {
67 Ok(mut child) => {
68 match child.wait() {
69 Ok(status) => {
70 if !status.success() {
71 return Err(
72 CmdSpawnError::Child(
73 ChildError {
74 program: command.get_program()
75 .to_str()
76 .unwrap_or("unknwown")
77 .to_string(),
78 code: status.code()
79 }
80 )
81 )
82 }
83 return Ok(())
84 },
85 Err(e) => return Err(CmdSpawnError::IO(e))
86 };
87 },
88 Err(e) => return Err(CmdSpawnError::IO(e))
89 }
90}
91
92pub trait CmdRun {
93 fn run(&mut self) -> Result<(), CmdSpawnError>;
101}
102
103impl CmdRun for Command {
104 fn run(&mut self) -> Result<(), CmdSpawnError> {
105 command_spawn(self)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::CmdRun;
112 use std::process::Command;
113
114 #[test]
115 fn cmd_spawn_success() {
116 let mut cmd = Command::new("test");
117 match cmd.args([
118 "-n",
119 "a"
120 ]).run() {
121 Ok(_) => (),
122 Err(e) => panic!("{}", e),
123 };
124 }
125
126 #[test]
127 fn cmd_spawn_child_error() {
128 let program = "test";
129 let mut cmd = Command::new(&"test");
130 match cmd.args([
131 "-n",
132 ""
133 ]).run() {
134 Ok(_) => panic!("should not have succeded"),
135 Err(e) => {
136 match e {
137 crate::CmdSpawnError::IO(e) => panic!("{}", e),
138 crate::CmdSpawnError::Child(e) => {
139 assert_eq!(e.program, program.to_owned());
140 assert_eq!(e.code, Some(1 as i32));
141 },
142 }
143 },
144 };
145 }
146}