1use std::process::Command;
3
4pub struct Cmd {
5 c: String,
6}
7
8impl Cmd {
9 pub fn new(s: &str) -> Self {
10 Cmd { c: String::from(s) }
11 }
12
13 pub fn run(&self) -> Result<Vec<u8>, String> {
14 match shell_words::split(&self.c) {
15 Ok(v) => {
16 let mut args = Vec::new();
17 if v.len() > 1 {
18 args.extend(&v[1..]);
19 }
20 match Command::new(&v[0]).args(&args).output() {
21 Ok(output) => {
22 let mut out = output.stdout;
23
24 if !output.stderr.is_empty() {
25 out.extend(output.stderr);
26 }
27
28 Ok(out)
29 }
30 Err(e) => Err(format!("Failed to execute the command {} ({})", self.c, e)),
31 }
32 }
33 Err(_) => Err("Splitting error".to_string()),
34 }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::Cmd;
41
42 #[test]
43 fn echo() {
44 let c = Cmd::new("echo \"test\"");
45 match c.run() {
46 Ok(o) => {
47 let ostr = String::from_utf8_lossy(&o);
48 assert_eq!("test\n", ostr);
49 }
50 Err(e) => {
51 println!("{}", e);
52 assert!(false);
53 }
54 }
55 }
56
57 #[test]
58 fn echo_no_new_line() {
59 let c = Cmd::new("echo -n \"test\"");
60 match c.run() {
61 Ok(o) => {
62 let ostr = String::from_utf8_lossy(&o);
63 assert_eq!("test", ostr);
64 }
65 Err(e) => {
66 println!("{}", e);
67 assert!(false);
68 }
69 }
70 }
71
72 #[test]
73 fn bash() {
74 let c = Cmd::new("bash -c 'VAR=test ; echo $VAR'");
75 match c.run() {
76 Ok(o) => {
77 let ostr = String::from_utf8_lossy(&o);
78 assert_eq!("test\n", ostr);
79 }
80 Err(e) => {
81 println!("{}", e);
82 assert!(false);
83 }
84 }
85 }
86
87 #[test]
88 fn bash_multiple_opts() {
89 let c = Cmd::new("bash -r -c 'VAR=test ; echo $VAR'");
90 match c.run() {
91 Ok(o) => {
92 let ostr = String::from_utf8_lossy(&o);
93 assert_eq!("test\n", ostr);
94 }
95 Err(e) => {
96 println!("{}", e);
97 assert!(false);
98 }
99 }
100 }
101
102 #[test]
103 fn command_does_not_exist() {
104 let c = Cmd::new("xxxxyyyytttt");
105 match c.run() {
106 Ok(_) => {
107 assert!(false);
108 }
109 Err(e) => {
110 println!("{}", e);
111 assert!(true);
112 }
113 }
114 }
115}