os_xtask_utils/
lib.rs

1#![deny(warnings, unsafe_code)]
2
3mod binutils;
4mod cargo;
5pub mod dir;
6mod git;
7mod make;
8mod qemu;
9mod tar;
10
11pub use binutils::BinUtil;
12pub use cargo::Cargo;
13pub use git::Git;
14pub use make::Make;
15pub use qemu::Qemu;
16pub use tar::Tar;
17
18use std::{
19    ffi::{OsStr, OsString},
20    path::Path,
21    process::{Command, ExitStatus, Output},
22};
23
24pub trait CommandExt: AsRef<Command> + AsMut<Command> {
25    #[inline]
26    fn arg(&mut self, s: impl AsRef<OsStr>) -> &mut Self {
27        self.as_mut().arg(s);
28        self
29    }
30
31    #[inline]
32    fn args<I, S>(&mut self, args: I) -> &mut Self
33    where
34        I: IntoIterator<Item = S>,
35        S: AsRef<OsStr>,
36    {
37        self.as_mut().args(args);
38        self
39    }
40
41    #[inline]
42    fn optional<T>(&mut self, option: &Option<T>, op: impl FnOnce(&mut Self, &T)) -> &mut Self {
43        if let Some(val) = option {
44            op(self, val);
45        }
46        self
47    }
48
49    #[inline]
50    fn conditional(&mut self, condition: bool, op: impl FnOnce(&mut Self)) -> &mut Self {
51        if condition {
52            op(self);
53        }
54        self
55    }
56
57    #[inline]
58    fn option(&mut self, option: Option<impl AsRef<OsStr>>) -> &mut Self {
59        if let Some(arg) = option {
60            self.as_mut().arg(arg);
61        }
62        self
63    }
64
65    #[inline]
66    fn current_dir(&mut self, dir: impl AsRef<Path>) -> &mut Self {
67        self.as_mut().current_dir(dir);
68        self
69    }
70
71    #[inline]
72    fn env(&mut self, key: impl AsRef<OsStr>, val: impl AsRef<OsStr>) -> &mut Self {
73        self.as_mut().env(key, val);
74        self
75    }
76
77    #[inline]
78    fn status(&mut self) -> ExitStatus {
79        self.as_mut().status().unwrap()
80    }
81
82    fn info(&self) -> OsString {
83        let cmd = self.as_ref();
84        let mut msg = OsString::new();
85        if let Some(dir) = cmd.get_current_dir() {
86            msg.push("cd ");
87            msg.push(dir);
88            msg.push(" && ");
89        }
90        msg.push(cmd.get_program());
91        for a in cmd.get_args() {
92            msg.push(" ");
93            msg.push(a);
94        }
95        for (k, v) in cmd.get_envs() {
96            msg.push(" ");
97            msg.push(k);
98            if let Some(v) = v {
99                msg.push("=");
100                msg.push(v);
101            }
102        }
103        msg
104    }
105
106    #[inline]
107    fn invoke(&mut self) {
108        let status = self.status();
109        if !status.success() {
110            panic!(
111                "Failed with code {}: {:?}",
112                status.code().unwrap(),
113                self.info()
114            );
115        }
116    }
117
118    #[inline]
119    fn output(&mut self) -> Output {
120        let output = self.as_mut().output().unwrap();
121        if !output.status.success() {
122            panic!(
123                "Failed with code {}: {:?}",
124                output.status.code().unwrap(),
125                self.info()
126            );
127        }
128        output
129    }
130}
131
132ext!(def; Ext);
133
134impl Ext {
135    #[inline]
136    pub fn new(program: impl AsRef<OsStr>) -> Self {
137        Self(Command::new(program))
138    }
139}
140
141mod m {
142    #[macro_export]
143    macro_rules! ext {
144        (def; $name:ident) => {
145            pub struct $name(std::process::Command);
146
147            ext!($name);
148        };
149
150        ($ty:ty) => {
151            impl AsRef<Command> for $ty {
152                fn as_ref(&self) -> &Command {
153                    &self.0
154                }
155            }
156
157            impl AsMut<Command> for $ty {
158                fn as_mut(&mut self) -> &mut Command {
159                    &mut self.0
160                }
161            }
162
163            impl $crate::CommandExt for $ty {}
164        };
165    }
166}