@@ -13,7 +13,9 @@ use std::fmt::{Debug, Formatter};
1313use std:: hash:: Hash ;
1414use std:: panic:: Location ;
1515use std:: path:: Path ;
16- use std:: process:: { Child , Command , CommandArgs , CommandEnvs , ExitStatus , Output , Stdio } ;
16+ use std:: process:: {
17+ Child , ChildStderr , ChildStdout , Command , CommandArgs , CommandEnvs , ExitStatus , Output , Stdio ,
18+ } ;
1719use std:: sync:: { Arc , Mutex } ;
1820
1921use build_helper:: ci:: CiEnv ;
@@ -209,15 +211,22 @@ impl<'a> BootstrapCommand {
209211 exec_ctx. as_ref ( ) . start ( self , OutputMode :: Capture , OutputMode :: Print )
210212 }
211213
212- /// Provides access to the stdlib Command inside.
213- /// FIXME: This function should be eventually removed from bootstrap.
214- pub fn as_command_mut ( & mut self ) -> & mut Command {
215- // We proactively mark this command as executed since we can't be certain how the returned
216- // command will be handled. Caching must also be avoided here, as the inner command could be
217- // modified externally without us being aware.
218- self . mark_as_executed ( ) ;
219- self . do_not_cache ( ) ;
220- & mut self . command
214+ /// Spawn the command in background, while capturing and returns a handle to stream the output.
215+ #[ track_caller]
216+ pub fn stream_capture (
217+ & ' a mut self ,
218+ exec_ctx : impl AsRef < ExecutionContext > ,
219+ ) -> Option < StreamingCommand > {
220+ exec_ctx. as_ref ( ) . stream ( self , OutputMode :: Capture , OutputMode :: Capture )
221+ }
222+
223+ /// Spawn the command in background, while capturing and returning stdout, and printing stderr.
224+ #[ track_caller]
225+ pub fn stream_capture_stdout (
226+ & ' a mut self ,
227+ exec_ctx : impl AsRef < ExecutionContext > ,
228+ ) -> Option < StreamingCommand > {
229+ exec_ctx. as_ref ( ) . stream ( self , OutputMode :: Capture , OutputMode :: Print )
221230 }
222231
223232 /// Mark the command as being executed, disarming the drop bomb.
@@ -449,6 +458,12 @@ enum CommandState<'a> {
449458 } ,
450459}
451460
461+ pub struct StreamingCommand {
462+ child : Child ,
463+ pub stdout : Option < ChildStdout > ,
464+ pub stderr : Option < ChildStderr > ,
465+ }
466+
452467#[ must_use]
453468pub struct DeferredCommand < ' a > {
454469 state : CommandState < ' a > ,
@@ -617,6 +632,39 @@ impl ExecutionContext {
617632 }
618633 exit ! ( 1 ) ;
619634 }
635+
636+ <<<<<<< HEAD
637+ pub fn stream< ' a > (
638+ =======
639+ /// Spawns the command with configured stdout and stderr handling.
640+ ///
641+ /// Returns `None` if in dry-run mode and the command is not allowed to run.
642+ ///
643+ /// Panics if the command fails to spawn.
644+ pub fn stream (
645+ >>>>>>> c2e83361cec ( add comment to exec)
646+ & self ,
647+ command : & ' a mut BootstrapCommand ,
648+ stdout : OutputMode ,
649+ stderr : OutputMode ,
650+ ) -> Option < StreamingCommand > {
651+ command. mark_as_executed ( ) ;
652+ if !command. run_in_dry_run && self . dry_run ( ) {
653+ return None ;
654+ }
655+ let cmd = & mut command. command ;
656+ cmd. stdout ( stdout. stdio ( ) ) ;
657+ cmd. stderr ( stderr. stdio ( ) ) ;
658+ let child = cmd. spawn ( ) ;
659+ let mut child = match child {
660+ Ok ( child) => child,
661+ Err ( e) => panic ! ( "failed to execute command: {cmd:?}\n ERROR: {e}" ) ,
662+ } ;
663+
664+ let stdout = child. stdout . take ( ) ;
665+ let stderr = child. stderr . take ( ) ;
666+ return Some ( StreamingCommand { child, stdout, stderr } ) ;
667+ }
620668}
621669
622670impl AsRef < ExecutionContext > for ExecutionContext {
@@ -625,6 +673,12 @@ impl AsRef<ExecutionContext> for ExecutionContext {
625673 }
626674}
627675
676+ impl StreamingCommand {
677+ pub fn wait ( mut self ) -> Result < ExitStatus , std:: io:: Error > {
678+ self . child . wait ( )
679+ }
680+ }
681+
628682impl < ' a > DeferredCommand < ' a > {
629683 pub fn wait_for_output ( self , exec_ctx : impl AsRef < ExecutionContext > ) -> CommandOutput {
630684 match self . state {
0 commit comments