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}