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/// [`Command`]: crate::command::Command
27/// [`CompletedProcess`]: crate::command::CompletedProcess
28macro_rules! impl_common_helpers {
29 ($wrapper: ident) => {
30 impl $wrapper {
31 /// In very rare circumstances, you may need a e.g. `bare_rustc()` or `bare_rustdoc()`
32 /// with host runtime libs configured, but want the underlying raw
33 /// [`std::process::Command`] (e.g. for manipulating pipes or whatever). This function
34 /// will consume the command wrapper and extract the underlying
35 /// [`std::process::Command`].
36 ///
37 /// Caution: this will mean that you can no longer use the convenience methods on the
38 /// command wrapper. Use as a last resort.
39 pub fn into_raw_command(self) -> ::std::process::Command {
40 self.cmd.into_raw_command()
41 }
42
43 /// Specify an environment variable.
44 pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
45 where
46 K: AsRef<::std::ffi::OsStr>,
47 V: AsRef<::std::ffi::OsStr>,
48 {
49 self.cmd.env(key, value);
50 self
51 }
52
53 /// Remove an environmental variable.
54 pub fn env_remove<K>(&mut self, key: K) -> &mut Self
55 where
56 K: AsRef<::std::ffi::OsStr>,
57 {
58 self.cmd.env_remove(key);
59 self
60 }
61
62 /// Generic command argument provider. Prefer specific helper methods if possible.
63 /// Note that for some executables, arguments might be platform specific. For C/C++
64 /// compilers, arguments might be platform *and* compiler specific.
65 pub fn arg<S>(&mut self, arg: S) -> &mut Self
66 where
67 S: AsRef<::std::ffi::OsStr>,
68 {
69 self.cmd.arg(arg);
70 self
71 }
72
73 /// Generic command arguments provider. Prefer specific helper methods if possible.
74 /// Note that for some executables, arguments might be platform specific. For C/C++
75 /// compilers, arguments might be platform *and* compiler specific.
76 pub fn args<V, S>(&mut self, args: V) -> &mut Self
77 where
78 V: AsRef<[S]>,
79 S: AsRef<::std::ffi::OsStr>,
80 {
81 self.cmd.args(args.as_ref());
82 self
83 }
84
85 /// Configuration for the child process’s standard input (stdin) handle.
86 ///
87 /// See [`std::process::Command::stdin`].
88 pub fn stdin<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self {
89 self.cmd.stdin(cfg);
90 self
91 }
92
93 /// Configuration for the child process’s standard output (stdout) handle.
94 ///
95 /// See [`std::process::Command::stdout`].
96 pub fn stdout<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self {
97 self.cmd.stdout(cfg);
98 self
99 }
100
101 /// Configuration for the child process’s standard error (stderr) handle.
102 ///
103 /// See [`std::process::Command::stderr`].
104 pub fn stderr<T: Into<::std::process::Stdio>>(&mut self, cfg: T) -> &mut Self {
105 self.cmd.stderr(cfg);
106 self
107 }
108
109 /// Inspect what the underlying [`Command`] is up to the
110 /// current construction.
111 pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
112 where
113 I: FnOnce(&::std::process::Command),
114 {
115 self.cmd.inspect(inspector);
116 self
117 }
118
119 /// Set an auxiliary stream passed to the process, besides the stdio streams.
120 #[cfg(unix)]
121 pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>(
122 &mut self,
123 new_fd: std::os::fd::RawFd,
124 fd: F,
125 ) -> &mut Self {
126 self.cmd.set_aux_fd(new_fd, fd);
127 self
128 }
129
130 /// Run the constructed command and assert that it is successfully run.
131 #[track_caller]
132 pub fn run(&mut self) -> crate::command::CompletedProcess {
133 self.cmd.run()
134 }
135
136 /// Run the constructed command and assert that it does not successfully run.
137 #[track_caller]
138 pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
139 self.cmd.run_fail()
140 }
141
142 /// Run the command but do not check its exit status.
143 /// Only use if you explicitly don't care about the exit status.
144 /// Prefer to use [`Self::run`] and [`Self::run_fail`]
145 /// whenever possible.
146 #[track_caller]
147 pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess {
148 self.cmd.run_unchecked()
149 }
150
151 /// Set the path where the command will be run.
152 pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self {
153 self.cmd.current_dir(path);
154 self
155 }
156 }
157 };
158}
159
160pub(crate) use impl_common_helpers;