use std::{
io,
process::{Command as StdCommand, Output},
};
use crate::{command::Command, io::ProcessIo, status::SpawnStatus};
pub fn handle(io: ProcessIo) -> io::Result<ProcessIo> {
match io {
ProcessIo::SpawnThenWait(io) => spawn_then_wait(io),
ProcessIo::SpawnThenWaitWithOutput(io) => spawn_then_wait_with_output(io),
}
}
pub fn spawn_then_wait(input: Result<SpawnStatus, Command>) -> io::Result<ProcessIo> {
let Err(command) = input else {
let kind = io::ErrorKind::InvalidInput;
return Err(io::Error::new(kind, "missing command"));
};
let mut command = StdCommand::from(command);
let mut child = command.spawn()?;
let stdin = child.stdin.take();
let stdout = child.stdout.take();
let stderr = child.stderr.take();
let output = SpawnStatus {
status: child.wait()?,
stdin: stdin.map(Into::into),
stdout: stdout.map(Into::into),
stderr: stderr.map(Into::into),
};
Ok(ProcessIo::SpawnThenWait(Ok(output)))
}
pub fn spawn_then_wait_with_output(input: Result<Output, Command>) -> io::Result<ProcessIo> {
let Err(command) = input else {
let kind = io::ErrorKind::InvalidInput;
return Err(io::Error::new(kind, "missing command"));
};
let mut command = StdCommand::from(command);
let output = command.output()?;
Ok(ProcessIo::SpawnThenWaitWithOutput(Ok(output)))
}
impl From<Command> for StdCommand {
fn from(builder: Command) -> Self {
let mut command = StdCommand::new(&*builder.get_program());
if let Some(args) = builder.get_args() {
for arg in args {
command.arg(&*arg);
}
}
if let Some(envs) = builder.envs {
for (key, val) in envs {
command.env(key, val);
}
}
if let Some(dir) = builder.current_dir {
command.current_dir(dir);
}
if let Some(cfg) = builder.stdin {
command.stdin(cfg);
}
if let Some(cfg) = builder.stdout {
command.stdout(cfg);
}
if let Some(cfg) = builder.stderr {
command.stderr(cfg);
}
command
}
}