run_make_support/
macros.rs

1/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
2/// containing a `cmd: Command` field. The provided helpers are:
3///
4/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
5///    to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
6///    new specific helper methods over relying on these generic argument providers.
7/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
8///    methods of the same name on [`Command`].
9/// 3. Output and execution: `run` and `run_fail` are provided. These are higher-level convenience
10///    methods which wait for the command to finish running and assert that the command successfully
11///    ran or failed as expected. They return [`CompletedProcess`], which can be used to assert the
12///    stdout/stderr/exit code of the executed process.
13///
14/// Example usage:
15///
16/// ```ignore (illustrative)
17/// struct CommandWrapper { cmd: Command } // <- required `cmd` field
18///
19/// crate::macros::impl_common_helpers!(CommandWrapper);
20///
21/// impl CommandWrapper {
22///     // ... additional specific helper methods
23/// }
24/// ```
25///
26/// You can pass an optional second parameter which should be a function that is passed
27/// `&mut self` just before the command is executed.
28///
29/// [`Command`]: crate::command::Command
30/// [`CompletedProcess`]: crate::command::CompletedProcess
31macro_rules! impl_common_helpers {
32    ($wrapper: ident) => {
33        $crate::macros::impl_common_helpers!($wrapper, |_| {});
34    };
35    ($wrapper: ident, $before_exec: expr) => {
36        impl $wrapper {
37            /// In very rare circumstances, you may need a e.g. `bare_rustc()` or `bare_rustdoc()`
38            /// with host runtime libs configured, but want the underlying raw
39            /// [`std::process::Command`] (e.g. for manipulating pipes or whatever). This function
40            /// will consume the command wrapper and extract the underlying
41            /// [`std::process::Command`].
42            ///
43            /// Caution: this will mean that you can no longer use the convenience methods on the
44            /// command wrapper. Use as a last resort.
45            pub fn into_raw_command(self) -> ::std::process::Command {
46                self.cmd.into_raw_command()
47            }
48
49            /// Specify an environment variable.
50            pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
51            where
52                K: AsRef<::std::ffi::OsStr>,
53                V: AsRef<::std::ffi::OsStr>,
54            {
55                self.cmd.env(key, value);
56                self
57            }
58
59            /// Remove an environmental variable.
60            pub fn env_remove<K>(&mut self, key: K) -> &mut Self
61            where
62                K: AsRef<::std::ffi::OsStr>,
63            {
64                self.cmd.env_remove(key);
65                self
66            }
67
68            /// Generic command argument provider. Prefer specific helper methods if possible.
69            /// Note that for some executables, arguments might be platform specific. For C/C++
70            /// compilers, arguments might be platform *and* compiler specific.
71            pub fn arg<S>(&mut self, arg: S) -> &mut Self
72            where
73                S: AsRef<::std::ffi::OsStr>,
74            {
75                self.cmd.arg(arg);
76                self
77            }
78
79            /// Generic command arguments provider. Prefer specific helper methods if possible.
80            /// Note that for some executables, arguments might be platform specific. For C/C++
81            /// compilers, arguments might be platform *and* compiler specific.
82            pub fn args<V, S>(&mut self, args: V) -> &mut Self
83            where
84                V: AsRef<[S]>,
85                S: AsRef<::std::ffi::OsStr>,
86            {
87                self.cmd.args(args.as_ref());
88                self
89            }
90
91            /// Configuration for the child process’s standard input (stdin) handle.
92            ///
93            /// See [`std::process::Command::stdin`].
94            pub fn stdin<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self {
95                self.cmd.stdin(cfg);
96                self
97            }
98
99            /// Configuration for the child process’s standard output (stdout) handle.
100            ///
101            /// See [`std::process::Command::stdout`].
102            pub fn stdout<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self {
103                self.cmd.stdout(cfg);
104                self
105            }
106
107            /// Configuration for the child process’s standard error (stderr) handle.
108            ///
109            /// See [`std::process::Command::stderr`].
110            pub fn stderr<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self {
111                self.cmd.stderr(cfg);
112                self
113            }
114
115            /// Inspect what the underlying [`Command`] is up to the
116            /// current construction.
117            pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
118            where
119                I: FnOnce(&::std::process::Command),
120            {
121                self.cmd.inspect(inspector);
122                self
123            }
124
125            /// Set an auxiliary stream passed to the process, besides the stdio streams.
126            #[cfg(unix)]
127            pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
128                &mut self,
129                new_fd: std::os::fd::RawFd,
130                fd: F,
131            ) -> &mut Self {
132                self.cmd.set_aux_fd(new_fd, fd);
133                self
134            }
135
136            /// Run the constructed command and assert that it is successfully run.
137            #[track_caller]
138            pub fn run(&mut self) -> crate::command::CompletedProcess {
139                $before_exec(&mut *self);
140                self.cmd.run()
141            }
142
143            /// Run the constructed command and assert that it does not successfully run.
144            #[track_caller]
145            pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
146                $before_exec(&mut *self);
147                self.cmd.run_fail()
148            }
149
150            /// Run the command but do not check its exit status.
151            /// Only use if you explicitly don't care about the exit status.
152            /// Prefer to use [`Self::run`] and [`Self::run_fail`]
153            /// whenever possible.
154            #[track_caller]
155            pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess {
156                $before_exec(&mut *self);
157                self.cmd.run_unchecked()
158            }
159
160            /// Set the path where the command will be run.
161            pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self {
162                self.cmd.current_dir(path);
163                self
164            }
165        }
166    };
167}
168
169pub(crate) use impl_common_helpers;