Skip to content

Commit 3f3f12c

Browse files
committed
add streaming command struct for (spawn + piping scenario)
1 parent 1b61d43 commit 3f3f12c

File tree

1 file changed

+64
-10
lines changed

1 file changed

+64
-10
lines changed

src/bootstrap/src/utils/exec.rs

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use std::fmt::{Debug, Formatter};
1313
use std::hash::Hash;
1414
use std::panic::Location;
1515
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+
};
1719
use std::sync::{Arc, Mutex};
1820

1921
use 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]
453468
pub 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:?}\nERROR: {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

622670
impl 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+
628682
impl<'a> DeferredCommand<'a> {
629683
pub fn wait_for_output(self, exec_ctx: impl AsRef<ExecutionContext>) -> CommandOutput {
630684
match self.state {

0 commit comments

Comments
 (0)