@@ -4,11 +4,12 @@ use std::ffi::{OsStr, OsString};
44use std:: fmt;
55use std:: io:: Write ;
66use std:: path:: Path ;
7- use std:: process:: { Command , ExitStatus , Output , Stdio } ;
7+ use std:: process:: { Child , Command , ExitStatus , Output , Stdio } ;
88
99use failure:: Fail ;
1010use jobserver:: Client ;
1111use shell_escape:: escape;
12+ use tempfile:: { NamedTempFile , TempPath } ;
1213
1314use crate :: util:: { process_error, read2, CargoResult , CargoResultExt } ;
1415
@@ -152,13 +153,9 @@ impl ProcessBuilder {
152153
153154 /// Runs the process, waiting for completion, and mapping non-success exit codes to an error.
154155 pub fn exec ( & self ) -> CargoResult < ( ) > {
155- let exit = match self . build_command ( ) . status ( ) {
156- Err ( ref err) if imp:: command_line_too_big ( err) => self
157- . build_command_and_response_file ( )
158- . and_then ( |( mut cmd, _file) | cmd. status ( ) . map_err ( |e| e. into ( ) ) ) ,
159- other => other. map_err ( |e| e. into ( ) ) ,
160- }
161- . chain_err ( || process_error ( & format ! ( "could not execute process {}" , self ) , None , None ) ) ?;
156+ let exit = self . status ( ) . chain_err ( || {
157+ process_error ( & format ! ( "could not execute process {}" , self ) , None , None )
158+ } ) ?;
162159
163160 if exit. success ( ) {
164161 Ok ( ( ) )
@@ -193,13 +190,9 @@ impl ProcessBuilder {
193190
194191 /// Executes the process, returning the stdio output, or an error if non-zero exit status.
195192 pub fn exec_with_output ( & self ) -> CargoResult < Output > {
196- let output = match self . build_command ( ) . output ( ) {
197- Err ( ref err) if imp:: command_line_too_big ( err) => self
198- . build_command_and_response_file ( )
199- . and_then ( |( mut cmd, _file) | cmd. output ( ) . map_err ( |e| e. into ( ) ) ) ,
200- other => other. map_err ( |e| e. into ( ) ) ,
201- }
202- . chain_err ( || process_error ( & format ! ( "could not execute process {}" , self ) , None , None ) ) ?;
193+ let output = self . output ( ) . chain_err ( || {
194+ process_error ( & format ! ( "could not execute process {}" , self ) , None , None )
195+ } ) ?;
203196
204197 if output. status . success ( ) {
205198 Ok ( output)
@@ -231,26 +224,13 @@ impl ProcessBuilder {
231224 let mut stdout = Vec :: new ( ) ;
232225 let mut stderr = Vec :: new ( ) ;
233226
234- let mut cmd = self . build_command ( ) ;
235- cmd. stdout ( Stdio :: piped ( ) )
236- . stderr ( Stdio :: piped ( ) )
237- . stdin ( Stdio :: null ( ) ) ;
238-
239227 let mut callback_error = None ;
240228 let status = ( || -> CargoResult < ExitStatus > {
241- let mut response_file = None ;
242- let mut child = match cmd. spawn ( ) {
243- Err ( ref err) if imp:: command_line_too_big ( err) => self
244- . build_command_and_response_file ( )
245- . and_then ( |( mut cmd, file) | {
246- cmd. stdout ( Stdio :: piped ( ) )
247- . stderr ( Stdio :: piped ( ) )
248- . stdin ( Stdio :: null ( ) ) ;
249- response_file = Some ( file) ;
250- Ok ( cmd. spawn ( ) ?)
251- } ) ,
252- other => other. map_err ( |e| e. into ( ) ) ,
253- } ?;
229+ let ( mut child, _response_file) = self . spawn_with ( |cmd| {
230+ cmd. stdout ( Stdio :: piped ( ) )
231+ . stderr ( Stdio :: piped ( ) )
232+ . stdin ( Stdio :: null ( ) ) ;
233+ } ) ?;
254234 let out = child. stdout . take ( ) . unwrap ( ) ;
255235 let err = child. stderr . take ( ) . unwrap ( ) ;
256236 read2 ( out, err, & mut |is_out, data, eof| {
@@ -350,7 +330,7 @@ impl ProcessBuilder {
350330
351331 /// Converts `ProcessBuilder` into a `std::process::Command` and a rustc style response
352332 /// file. Also handles the jobserver, if present.
353- pub fn build_command_and_response_file ( & self ) -> CargoResult < ( Command , tempfile :: TempPath ) > {
333+ pub fn build_command_and_response_file ( & self ) -> CargoResult < ( Command , TempPath ) > {
354334 // The rust linker also jumps through similar hoops, although with a different
355335 // of response file, which this borrows from. Some references:
356336 // https://github.com/rust-lang/rust/blob/ef92009c1dbe2750f1d24a6619b827721fb49749/src/librustc_codegen_ssa/back/link.rs#L935
@@ -362,7 +342,7 @@ impl ProcessBuilder {
362342 }
363343 // cmd.exe can handle up to 8k work of args, this leaves some headroom if using a .cmd rustc wrapper.
364344 let mut cmd_remaining: usize = 1024 * 6 ;
365- let mut response_file = tempfile :: NamedTempFile :: new ( ) ?;
345+ let mut response_file = NamedTempFile :: new ( ) ?;
366346 for arg in & self . args {
367347 cmd_remaining = cmd_remaining. saturating_sub ( arg. len ( ) ) ;
368348 if cmd_remaining > 0 {
@@ -391,6 +371,37 @@ impl ProcessBuilder {
391371 }
392372 Ok ( ( command, response_file. into_temp_path ( ) ) )
393373 }
374+
375+ fn status ( & self ) -> CargoResult < ExitStatus > {
376+ let ( mut child, _response_file) = self . spawn_with ( |_cmd| { } ) ?;
377+ Ok ( child. wait ( ) ?)
378+ }
379+
380+ fn output ( & self ) -> CargoResult < Output > {
381+ let ( child, _response_file) = self . spawn_with ( |cmd| {
382+ cmd. stdout ( Stdio :: piped ( ) )
383+ . stderr ( Stdio :: piped ( ) )
384+ . stdin ( Stdio :: null ( ) ) ;
385+ } ) ?;
386+ Ok ( child. wait_with_output ( ) ?)
387+ }
388+
389+ fn spawn_with (
390+ & self ,
391+ mut modify_command : impl FnMut ( & mut Command ) ,
392+ ) -> CargoResult < ( Child , Option < TempPath > ) > {
393+ let mut command = self . build_command ( ) ;
394+ modify_command ( & mut command) ;
395+ match command. spawn ( ) {
396+ Ok ( child) => Ok ( ( child, None ) ) ,
397+ Err ( ref err) if imp:: command_line_too_big ( err) => {
398+ let ( mut command, response_file) = self . build_command_and_response_file ( ) ?;
399+ modify_command ( & mut command) ;
400+ Ok ( ( command. spawn ( ) ?, Some ( response_file) ) )
401+ }
402+ Err ( other) => Err ( other. into ( ) ) ,
403+ }
404+ }
394405}
395406
396407/// A helper function to create a `ProcessBuilder`.
0 commit comments