about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
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
commitb22099d4e0be8819b1cf476d32d02459a594278b (patch)
treec1da3ff25eda9506a7e177b3d5a3cfd4b08d66ae /src
parente994534242e742d52c7bab0f0637bc4ed14ec90d (diff)
downloadrust-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.rs124
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;