1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
extern crate config;
use self::config::types::{Config, ScalarValue, Value};
use std::env::home_dir;
use std::process::Command;
pub struct CommandLine {
program: String,
args: Vec<String>,
}
fn expand_home(path: &String) -> String {
if path.starts_with("~/") {
if let Some(home) = home_dir() {
return format!("{}/{}", home.display(), &path[2..])
}
}
path.clone()
}
fn make_command_vec(vec: &Vec<Value>) -> Result<CommandLine, String> {
if vec.is_empty() {
return Err(format!("empty execution vector"));
}
let mut prog_args = vec![];
for v in vec {
match *v {
Value::Svalue(ref sv) =>
match *sv {
ScalarValue::Str(ref s) => prog_args.push(s),
_ => return Err(format!("non-string program value")),
},
_ => return Err(format!("non-string program value")),
}
}
let (prog, args) = prog_args.split_at(1);
Ok(CommandLine {
program: expand_home(prog[0]),
args: args.iter().map(|&arg| (*arg).clone()).collect(),
})
}
fn make_command_str(string: &String) -> Result<CommandLine, String> {
if string.is_empty() {
Err(format!("empty execution string"))
} else {
Ok(CommandLine {
program: expand_home(string),
args: vec![],
})
}
}
pub fn read_command_line_from_config(conf: &Config, path: &str) -> Option<CommandLine> {
conf.lookup(path).and_then(|val| {
let cmd_line = match *val {
Value::Array(ref a) => make_command_vec(a),
Value::Svalue(ref sv) =>
match *sv {
ScalarValue::Str(ref s) => make_command_str(s),
_ => Err(format!("unsupported type for {}", path)),
},
_ => Err(format!("unsupported type for {}", path)),
};
cmd_line.map_err(|err| {
println!("Failed to make a command line for '{}': {:?}", path, err);
}).ok()
})
}
pub fn run_command_line(cmd_line: &CommandLine) -> Result<(), String> {
let cmd = Command::new(&cmd_line.program)
.args(&cmd_line.args)
.output();
match cmd {
Ok(output) =>
if output.status.success() {
Ok(())
} else {
Err(format!("failed to execute process ({:?}):\noutput:\n{}\nerror:{}",
output.status.code(),
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)))
},
_ => Err(format!("failed to execute process")),
}
}