@@ -115,3 +115,127 @@ fn handle_failed_output(cmd: &Command, output: Output, caller_line_number: u32)
115115 eprintln ! ( "=== STDERR ===\n {}\n \n " , String :: from_utf8( output. stderr) . unwrap( ) ) ;
116116 std:: process:: exit ( 1 )
117117}
118+
119+ /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
120+ /// containing a `cmd: Command` field. The provided helpers are:
121+ ///
122+ /// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
123+ /// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
124+ /// new specific helper methods over relying on these generic argument providers.
125+ /// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
126+ /// methods of the same name on [`Command`].
127+ /// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the
128+ /// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are
129+ /// higher-level convenience methods which waits for the command to finish running and assert
130+ /// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when
131+ /// possible.
132+ ///
133+ /// Example usage:
134+ ///
135+ /// ```ignore (illustrative)
136+ /// struct CommandWrapper { cmd: Command }
137+ ///
138+ /// crate::impl_common_helpers!(CommandWrapper);
139+ ///
140+ /// impl CommandWrapper {
141+ /// // ... additional specific helper methods
142+ /// }
143+ /// ```
144+ ///
145+ /// [`Command`]: ::std::process::Command
146+ /// [`Output`]: ::std::process::Output
147+ macro_rules! impl_common_helpers {
148+ ( $wrapper: ident) => {
149+ impl $wrapper {
150+ /// Specify an environment variable.
151+ pub fn env<K , V >( & mut self , key: K , value: V ) -> & mut Self
152+ where
153+ K : AsRef <:: std:: ffi:: OsStr >,
154+ V : AsRef <:: std:: ffi:: OsStr >,
155+ {
156+ self . cmd. env( key, value) ;
157+ self
158+ }
159+
160+ /// Remove an environmental variable.
161+ pub fn env_remove<K >( & mut self , key: K ) -> & mut Self
162+ where
163+ K : AsRef <:: std:: ffi:: OsStr >,
164+ {
165+ self . cmd. env_remove( key) ;
166+ self
167+ }
168+
169+ /// Clear all environmental variables.
170+ pub fn env_var( & mut self ) -> & mut Self {
171+ self . cmd. env_clear( ) ;
172+ self
173+ }
174+
175+ /// Generic command argument provider. Prefer specific helper methods if possible.
176+ /// Note that for some executables, arguments might be platform specific. For C/C++
177+ /// compilers, arguments might be platform *and* compiler specific.
178+ pub fn arg<S >( & mut self , arg: S ) -> & mut Self
179+ where
180+ S : AsRef <:: std:: ffi:: OsStr >,
181+ {
182+ self . cmd. arg( arg) ;
183+ self
184+ }
185+
186+ /// Generic command arguments provider. Prefer specific helper methods if possible.
187+ /// Note that for some executables, arguments might be platform specific. For C/C++
188+ /// compilers, arguments might be platform *and* compiler specific.
189+ pub fn args<S >( & mut self , args: & [ S ] ) -> & mut Self
190+ where
191+ S : AsRef <:: std:: ffi:: OsStr >,
192+ {
193+ self . cmd. args( args) ;
194+ self
195+ }
196+
197+ /// Inspect what the underlying [`Command`][::std::process::Command] is up to the
198+ /// current construction.
199+ pub fn inspect<I >( & mut self , inspector: I ) -> & mut Self
200+ where
201+ I : FnOnce ( & :: std:: process:: Command ) ,
202+ {
203+ inspector( & self . cmd) ;
204+ self
205+ }
206+
207+ /// Get the [`Output`][::std::process::Output] of the finished process.
208+ pub fn output( & mut self ) -> :: std:: process:: Output {
209+ self . cmd. output( ) . expect( "failed to get output of finished process" )
210+ }
211+
212+ /// Run the constructed command and assert that it is successfully run.
213+ #[ track_caller]
214+ pub fn run( & mut self ) -> :: std:: process:: Output {
215+ let caller_location = :: std:: panic:: Location :: caller( ) ;
216+ let caller_line_number = caller_location. line( ) ;
217+
218+ let output = self . cmd. output( ) . unwrap( ) ;
219+ if !output. status. success( ) {
220+ handle_failed_output( & self . cmd, output, caller_line_number) ;
221+ }
222+ output
223+ }
224+
225+ /// Run the constructed command and assert that it does not successfully run.
226+ #[ track_caller]
227+ pub fn run_fail( & mut self ) -> :: std:: process:: Output {
228+ let caller_location = :: std:: panic:: Location :: caller( ) ;
229+ let caller_line_number = caller_location. line( ) ;
230+
231+ let output = self . cmd. output( ) . unwrap( ) ;
232+ if output. status. success( ) {
233+ handle_failed_output( & self . cmd, output, caller_line_number) ;
234+ }
235+ output
236+ }
237+ }
238+ } ;
239+ }
240+
241+ pub ( crate ) use impl_common_helpers;
0 commit comments