1extern crate execute;
66
67use std::process::Stdio;
68
69use execute::{Execute, command, shell};
70
71#[derive(Clone)]
72pub struct RunCmdOutput {
73 pub cmd: String,
74 pub stdout: String,
75 pub stderr: String,
76 pub exitcode: i32
77}
78
79pub struct RunCmd {
80 retval: RunCmdOutput,
81 verbose: bool,
82 execute: bool,
83 shell: bool
84}
85
86impl RunCmd {
87
88 pub fn new(cmd: &str) -> RunCmd {
89 RunCmd {
90 retval: RunCmdOutput {
91 cmd: String::from(cmd),
92 stdout: String::from(""),
93 stderr: String::from(""),
94 exitcode: 0
95 },
96 execute: false,
97 verbose: false,
98 shell: false
99 }
100 }
101
102 #[allow(dead_code)]
105 pub fn verbose(&mut self) -> &mut RunCmd {
106 self.verbose = true;
107 self
108 }
109
110 #[allow(dead_code)]
112 pub fn shell(&mut self) -> &mut RunCmd {
113 self.shell = true;
114 self
115 }
116
117 fn print(&self) {
118 println!("cmd:\n '{}'\n", self.retval.cmd);
119 println!("stdout:\n '{}'\n", self.retval.stdout);
120 println!("stderr:\n '{}'\n", self.retval.stderr);
121 println!("exitcode: '{}'\n\n", self.retval.exitcode);
122 }
123
124 pub fn executep(&mut self) {
126 self.execute = true;
127
128 let retval = self.execute();
129
130 if retval.exitcode != 0 {
131 if self.verbose {
132 self.print();
133 }
134 panic!("Exitcode != 0")
135 }
136 }
137
138 pub fn execute(&mut self) -> RunCmdOutput {
140 let mut executor;
141
142 if self.shell {
143 executor = shell(&self.retval.cmd)
144 } else {
145 executor = command(&self.retval.cmd)
146 }
147
148 if self.verbose || !self.execute {
149 executor.stdout(Stdio::piped());
150 executor.stderr(Stdio::piped());
151 }
152
153 let output = executor.execute_output().unwrap();
154
155 if let Some(exit_code) = output.status.code() {
156 self.retval.exitcode = exit_code;
157 self.retval.stdout = String::from_utf8(output.stdout).unwrap();
158 self.retval.stderr = String::from_utf8(output.stderr).unwrap();
159 } else {
160 self.retval.exitcode = -1;
161 self.retval.stderr = String::from("Interrupted! in RunCmd");
162 }
163
164 if self.verbose {
165 self.print();
166 }
167
168 return self.retval.clone()
169 }
170
171}
172
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn execute_pass() {
180 RunCmd::new("bash -c \"exit 0\"").executep();
181 }
182
183 #[test]
184 #[should_panic]
185 fn execute_fail() {
186 RunCmd::new("bash -c \"exit -1\"").executep();
187 }
188
189 #[test]
190 fn execute_verbose() {
191 RunCmd::new("echo bar; exit 0")
192 .verbose()
193 .execute();
194 }
195
196 #[test]
197 fn execute_shell() {
198 RunCmd::new("echo foobar; exit 0").shell().execute();
199 }
200
201 #[test]
202 fn execute_output_pass() {
203 let retval = RunCmd::new("bash -c \"echo foo; >&2 echo bar; exit -1\"").execute();
204 assert_eq!(retval.exitcode, 255);
205 assert_eq!(&retval.stdout, "foo\n");
206 assert_eq!(&retval.stderr, "bar\n");
207 assert_eq!(&retval.cmd, "bash -c \"echo foo; >&2 echo bar; exit -1\"");
208 }
209
210 #[test]
211 fn execute_output_shell_pass() {
212 let retval = RunCmd::new("echo foo; >&2 echo bar; exit -1").shell().execute();
213 assert_eq!(retval.exitcode, 255);
214 assert_eq!(&retval.stdout, "foo\n");
215 assert_eq!(&retval.stderr, "bar\n");
216 assert_eq!(&retval.cmd, "echo foo; >&2 echo bar; exit -1");
217 }
218
219}