command_macro/
lib.rs

1extern crate shlex;
2
3use std::process::Command;
4use std::fmt;
5
6pub trait ExecuteCommand {
7    fn execute(&mut self);
8}
9
10impl ExecuteCommand for Command {
11    fn execute(&mut self) {
12        if !self.status().expect("Failed to run command.").success() {
13            ::std::process::exit(1);
14        }
15    }
16}
17
18pub enum CommandArg {
19    Empty,
20    Literal(String),
21    List(Vec<String>),
22}
23
24impl fmt::Display for CommandArg {
25    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26        use CommandArg::*;
27        match *self {
28            Empty => write!(f, ""),
29            Literal(ref value) => {
30                write!(f, "{}", shlex::quote(&format!("{}", value)))
31            },
32            List(ref list) => {
33                write!(f, "{}", list
34                    .iter()
35                    .map(|x| shlex::quote(&format!("{}", x)).to_string())
36                    .collect::<Vec<_>>()
37                    .join(" "))
38            }
39        }
40    }
41}
42
43impl<'a, 'b> From<&'a &'b str> for CommandArg {
44    fn from(value: &&str) -> Self {
45        CommandArg::Literal(value.to_string())
46    }
47}
48
49impl<'a> From<&'a str> for CommandArg {
50    fn from(value: &str) -> Self {
51        CommandArg::Literal(value.to_string())
52    }
53}
54
55impl<'a, T> From<&'a [T]> for CommandArg
56    where T: fmt::Display {
57    fn from(list: &[T]) -> Self {
58        CommandArg::List(
59            list
60                .iter()
61                .map(|x| format!("{}", x))
62                .collect()
63        )
64    }
65}
66
67impl<'a, T> From<&'a Vec<T>> for CommandArg
68    where T: fmt::Display {
69    fn from(list: &Vec<T>) -> Self {
70        CommandArg::from(list.as_slice())
71    }
72}
73
74impl<'a, T> From<&'a Option<T>> for CommandArg
75    where T: fmt::Display {
76    fn from(opt: &Option<T>) -> Self {
77        if let Some(ref value) = *opt {
78            CommandArg::Literal(format!("{}", value))
79        } else {
80            CommandArg::Empty
81        }
82    }
83}
84
85pub fn command_arg<'a, T>(value: &'a T) -> CommandArg
86    where CommandArg: std::convert::From<&'a T> {
87    CommandArg::from(value)
88}
89
90pub fn commandify(value: String) -> Command {
91    let mut args = shlex::split(value.trim()).unwrap_or(vec![]);
92    let cmd_text = args.remove(0);
93    let mut cmd = Command::new(cmd_text);
94    cmd.args(args);
95    cmd
96}
97
98#[macro_export]
99macro_rules! command {
100    (cd: $cd:expr, $($args:tt)*) => ({
101        command!($($args)*)
102            .current_dir($cd)
103    });
104    (env: $name:ident = $value:expr, $($args:tt)*) => ({
105        command!($($args)*)
106            .env(stringify!($name), format!("{}", $value))
107    });
108    ($fmt:expr ,*) => ({
109        ::command_macro::commandify(format!($fmt))
110    });
111    ($fmt:expr, $( $id:ident = $value:expr ,)*) => ({
112        ::command_macro::commandify(
113            format!($fmt, $( $id = ::command_macro::command_arg(&$value) ,)*)
114        )
115    });
116}