stream_download/process/
command_builder.rs1use std::io;
2use std::process::Stdio;
3
4use super::{Command, SpawnCommand, SpawnedCommand, WrapIoResult, stdio_to_tmp_file};
5
6#[derive(Debug)]
9pub struct CommandBuilder {
10 commands: Vec<Command>,
11}
12
13impl CommandBuilder {
14 pub fn new<C>(command: C) -> Self
16 where
17 C: Into<Command>,
18 {
19 Self {
20 commands: vec![command.into()],
21 }
22 }
23
24 #[must_use]
27 pub fn pipe<C>(mut self, command: C) -> Self
28 where
29 C: Into<Command>,
30 {
31 self.commands.push(command.into());
32 self
33 }
34}
35
36impl SpawnCommand for CommandBuilder {
37 fn spawn(mut self) -> io::Result<SpawnedCommand> {
38 let last = self.commands.pop().expect("prevented by constructor");
39 let mut prev_stdout = None;
40 let mut stderr_files = Vec::new();
41
42 for command in self.commands {
43 let mut std_command = std::process::Command::new(command.program);
44 std_command
45 .args(command.args.clone())
46 .stdout(Stdio::piped());
47 if let Some(handle) = command.stderr_handle {
48 std_command.stderr(handle);
49 } else {
50 let (stdio, stderr_file) = stdio_to_tmp_file()?;
51 std_command.stderr(stdio);
52 stderr_files.push(stderr_file);
53 }
54
55 #[cfg(target_os = "windows")]
56 {
57 use std::os::windows::process::CommandExt;
59 std_command.creation_flags(0x08000000);
60 }
61
62 if let Some(prev_stdout) = prev_stdout.take() {
63 std_command.stdin(prev_stdout);
64 }
65 let mut command_out = std_command.spawn().wrap_err("error spawning process")?;
66 prev_stdout = command_out.stdout.take();
67 }
68 SpawnedCommand::new(last, prev_stdout, stderr_files)
69 }
70}