@@ -13,7 +13,9 @@ use std::fmt::{Debug, Formatter};
13
13
use std:: hash:: Hash ;
14
14
use std:: panic:: Location ;
15
15
use 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
+ } ;
17
19
use std:: sync:: { Arc , Mutex } ;
18
20
19
21
use build_helper:: ci:: CiEnv ;
@@ -209,15 +211,22 @@ impl<'a> BootstrapCommand {
209
211
exec_ctx. as_ref ( ) . start ( self , OutputMode :: Capture , OutputMode :: Print )
210
212
}
211
213
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 )
221
230
}
222
231
223
232
/// Mark the command as being executed, disarming the drop bomb.
@@ -449,6 +458,12 @@ enum CommandState<'a> {
449
458
} ,
450
459
}
451
460
461
+ pub struct StreamingCommand {
462
+ child : Child ,
463
+ pub stdout : Option < ChildStdout > ,
464
+ pub stderr : Option < ChildStderr > ,
465
+ }
466
+
452
467
#[ must_use]
453
468
pub struct DeferredCommand < ' a > {
454
469
state : CommandState < ' a > ,
@@ -617,6 +632,30 @@ impl ExecutionContext {
617
632
}
618
633
exit ! ( 1 ) ;
619
634
}
635
+
636
+ pub fn stream < ' a > (
637
+ & self ,
638
+ command : & ' a mut BootstrapCommand ,
639
+ stdout : OutputMode ,
640
+ stderr : OutputMode ,
641
+ ) -> Option < StreamingCommand > {
642
+ command. mark_as_executed ( ) ;
643
+ if !command. run_in_dry_run && self . dry_run ( ) {
644
+ return None ;
645
+ }
646
+ let cmd = & mut command. command ;
647
+ cmd. stdout ( stdout. stdio ( ) ) ;
648
+ cmd. stderr ( stderr. stdio ( ) ) ;
649
+ let child = cmd. spawn ( ) ;
650
+ let mut child = match child {
651
+ Ok ( child) => child,
652
+ Err ( e) => panic ! ( "failed to execute command: {cmd:?}\n ERROR: {e}" ) ,
653
+ } ;
654
+
655
+ let stdout = child. stdout . take ( ) ;
656
+ let stderr = child. stderr . take ( ) ;
657
+ return Some ( StreamingCommand { child, stdout, stderr } ) ;
658
+ }
620
659
}
621
660
622
661
impl AsRef < ExecutionContext > for ExecutionContext {
@@ -625,6 +664,16 @@ impl AsRef<ExecutionContext> for ExecutionContext {
625
664
}
626
665
}
627
666
667
+ impl StreamingCommand {
668
+ pub fn wait ( mut self ) -> Result < ExitStatus , std:: io:: Error > {
669
+ self . child . wait ( )
670
+ }
671
+
672
+ pub fn wait_with_output ( self ) -> Result < Output , std:: io:: Error > {
673
+ self . child . wait_with_output ( )
674
+ }
675
+ }
676
+
628
677
impl < ' a > DeferredCommand < ' a > {
629
678
pub fn wait_for_output ( self , exec_ctx : impl AsRef < ExecutionContext > ) -> CommandOutput {
630
679
match self . state {
0 commit comments