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;