Skip to content

Commit b22099d

Browse files
committed
run-make-support: introduce macro for common methods to avoid repetition
Add a helper macro for adding common methods to command wrappers. Common methods include helpers that delegate to `Command` and running methods. - `arg` and `args` (delegates to `Command`) - `env`, `env_remove` and `env_clear` (delegates to `Command`) - `output`, `run` and `run_fail` This helps to avoid needing to copy-pasta / reimplement these common methods on a new command wrapper, which hopefully reduces the friction for run-make test writers wanting to introduce new command wrappers.
1 parent e994534 commit b22099d

File tree

1 file changed

+124
-0
lines changed
  • src/tools/run-make-support/src

1 file changed

+124
-0
lines changed

src/tools/run-make-support/src/lib.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,127 @@ pub fn set_host_rpath(cmd: &mut Command) {
129129
env::join_paths(paths.iter()).unwrap()
130130
});
131131
}
132+
133+
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
134+
/// containing a `cmd: Command` field. The provided helpers are:
135+
///
136+
/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
137+
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
138+
/// new specific helper methods over relying on these generic argument providers.
139+
/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
140+
/// methods of the same name on [`Command`].
141+
/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the
142+
/// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are
143+
/// higher-level convenience methods which waits for the command to finish running and assert
144+
/// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when
145+
/// possible.
146+
///
147+
/// Example usage:
148+
///
149+
/// ```ignore (illustrative)
150+
/// struct CommandWrapper { cmd: Command }
151+
///
152+
/// crate::impl_common_helpers!(CommandWrapper);
153+
///
154+
/// impl CommandWrapper {
155+
/// // ... additional specific helper methods
156+
/// }
157+
/// ```
158+
///
159+
/// [`Command`]: ::std::process::Command
160+
/// [`Output`]: ::std::process::Output
161+
macro_rules! impl_common_helpers {
162+
($wrapper: ident) => {
163+
impl $wrapper {
164+
/// Specify an environment variable.
165+
pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
166+
where
167+
K: AsRef<::std::ffi::OsStr>,
168+
V: AsRef<::std::ffi::OsStr>,
169+
{
170+
self.cmd.env(key, value);
171+
self
172+
}
173+
174+
/// Remove an environmental variable.
175+
pub fn env_remove<K>(&mut self, key: K) -> &mut Self
176+
where
177+
K: AsRef<::std::ffi::OsStr>,
178+
{
179+
self.cmd.env_remove(key);
180+
self
181+
}
182+
183+
/// Clear all environmental variables.
184+
pub fn env_var(&mut self) -> &mut Self {
185+
self.cmd.env_clear();
186+
self
187+
}
188+
189+
/// Generic command argument provider. Prefer specific helper methods if possible.
190+
/// Note that for some executables, arguments might be platform specific. For C/C++
191+
/// compilers, arguments might be platform *and* compiler specific.
192+
pub fn arg<S>(&mut self, arg: S) -> &mut Self
193+
where
194+
S: AsRef<::std::ffi::OsStr>,
195+
{
196+
self.cmd.arg(arg);
197+
self
198+
}
199+
200+
/// Generic command arguments provider. Prefer specific helper methods if possible.
201+
/// Note that for some executables, arguments might be platform specific. For C/C++
202+
/// compilers, arguments might be platform *and* compiler specific.
203+
pub fn args<S>(&mut self, args: &[S]) -> &mut Self
204+
where
205+
S: AsRef<::std::ffi::OsStr>,
206+
{
207+
self.cmd.args(args);
208+
self
209+
}
210+
211+
/// Inspect what the underlying [`Command`][::std::process::Command] is up to the
212+
/// current construction.
213+
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
214+
where
215+
I: FnOnce(&::std::process::Command),
216+
{
217+
inspector(&self.cmd);
218+
self
219+
}
220+
221+
/// Get the [`Output`][::std::process::Output] of the finished process.
222+
pub fn output(&mut self) -> ::std::process::Output {
223+
self.cmd.output().expect("failed to get output of finished process")
224+
}
225+
226+
/// Run the constructed command and assert that it is successfully run.
227+
#[track_caller]
228+
pub fn run(&mut self) -> ::std::process::Output {
229+
let caller_location = ::std::panic::Location::caller();
230+
let caller_line_number = caller_location.line();
231+
232+
let output = self.cmd.output().unwrap();
233+
if !output.status.success() {
234+
handle_failed_output(&self.cmd, output, caller_line_number);
235+
}
236+
output
237+
}
238+
239+
/// Run the constructed command and assert that it does not successfully run.
240+
#[track_caller]
241+
pub fn run_fail(&mut self) -> ::std::process::Output {
242+
let caller_location = ::std::panic::Location::caller();
243+
let caller_line_number = caller_location.line();
244+
245+
let output = self.cmd.output().unwrap();
246+
if output.status.success() {
247+
handle_failed_output(&self.cmd, output, caller_line_number);
248+
}
249+
output
250+
}
251+
}
252+
};
253+
}
254+
255+
pub(crate) use impl_common_helpers;

0 commit comments

Comments
 (0)