1use std::ffi::OsStr;
4use std::process::Command;
5
6pub fn run(command: &mut Command, step: &str) -> Result<(), String> {
15 println!("==> {step}");
16 println!(" {}", describe(command));
17 let status = command
18 .status()
19 .map_err(|error| format!("running {step}: {error}"))?;
20 if status.success() {
21 Ok(())
22 } else {
23 Err(format!(
24 "{step} failed; fix the diagnostics above and run again"
25 ))
26 }
27}
28
29pub fn describe(command: &Command) -> String {
32 let mut line = quote(command.get_program());
33 for argument in command.get_args() {
34 line.push(' ');
35 line.push_str("e(argument));
36 }
37 line
38}
39
40fn quote(word: &OsStr) -> String {
42 let word = word.to_string_lossy();
43 let bare = !word.is_empty()
44 && word
45 .chars()
46 .all(|c| c.is_ascii_alphanumeric() || "_-./=:,+@".contains(c));
47 if bare {
48 word.into_owned()
49 } else {
50 format!("'{}'", word.replace('\'', r"'\''"))
51 }
52}