diff options
| author | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2024-04-13 14:49:44 +0000 |
|---|---|---|
| committer | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2024-04-13 14:49:44 +0000 |
| commit | b22099d4e0be8819b1cf476d32d02459a594278b (patch) | |
| tree | c1da3ff25eda9506a7e177b3d5a3cfd4b08d66ae /src | |
| parent | e994534242e742d52c7bab0f0637bc4ed14ec90d (diff) | |
| download | rust-b22099d4e0be8819b1cf476d32d02459a594278b.tar.gz rust-b22099d4e0be8819b1cf476d32d02459a594278b.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/tools/run-make-support/src/lib.rs | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f4d2634c470..504bd6030d9 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -129,3 +129,127 @@ pub fn set_host_rpath(cmd: &mut Command) { env::join_paths(paths.iter()).unwrap() }); } + +/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct +/// containing a `cmd: Command` field. The provided helpers are: +/// +/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended +/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add +/// new specific helper methods over relying on these generic argument providers. +/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to +/// methods of the same name on [`Command`]. +/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the +/// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are +/// higher-level convenience methods which waits for the command to finish running and assert +/// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when +/// possible. +/// +/// Example usage: +/// +/// ```ignore (illustrative) +/// struct CommandWrapper { cmd: Command } +/// +/// crate::impl_common_helpers!(CommandWrapper); +/// +/// impl CommandWrapper { +/// // ... additional specific helper methods +/// } +/// ``` +/// +/// [`Command`]: ::std::process::Command +/// [`Output`]: ::std::process::Output +macro_rules! impl_common_helpers { + ($wrapper: ident) => { + impl $wrapper { + /// Specify an environment variable. + pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + V: AsRef<::std::ffi::OsStr>, + { + self.cmd.env(key, value); + self + } + + /// Remove an environmental variable. + pub fn env_remove<K>(&mut self, key: K) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + { + self.cmd.env_remove(key); + self + } + + /// Clear all environmental variables. + pub fn env_var(&mut self) -> &mut Self { + self.cmd.env_clear(); + self + } + + /// Generic command argument provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn arg<S>(&mut self, arg: S) -> &mut Self + where + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.arg(arg); + self + } + + /// Generic command arguments provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn args<S>(&mut self, args: &[S]) -> &mut Self + where + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.args(args); + self + } + + /// Inspect what the underlying [`Command`][::std::process::Command] is up to the + /// current construction. + pub fn inspect<I>(&mut self, inspector: I) -> &mut Self + where + I: FnOnce(&::std::process::Command), + { + inspector(&self.cmd); + self + } + + /// Get the [`Output`][::std::process::Output] of the finished process. + pub fn output(&mut self) -> ::std::process::Output { + self.cmd.output().expect("failed to get output of finished process") + } + + /// Run the constructed command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> ::std::process::Output { + let caller_location = ::std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&self.cmd, output, caller_line_number); + } + output + } + + /// Run the constructed command and assert that it does not successfully run. + #[track_caller] + pub fn run_fail(&mut self) -> ::std::process::Output { + let caller_location = ::std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if output.status.success() { + handle_failed_output(&self.cmd, output, caller_line_number); + } + output + } + } + }; +} + +pub(crate) use impl_common_helpers; |
