use log::{debug, trace};
use std::process::Output;
use thiserror::Error;
use crate::{command::Command, io::ProcessIo};
#[derive(Debug, Error)]
pub enum SpawnThenWaitWithOutputError {
#[error("Invalid argument: expected {0}, got {1:?}")]
InvalidArgument(&'static str, ProcessIo),
#[error("Command not initialized")]
NotInitialized,
}
#[derive(Debug)]
pub enum SpawnThenWaitWithOutputResult {
Ok(Output),
Io(ProcessIo),
Err(SpawnThenWaitWithOutputError),
}
#[derive(Debug)]
pub struct SpawnThenWaitWithOutput {
cmd: Option<Command>,
}
impl SpawnThenWaitWithOutput {
pub fn new(cmd: Command) -> Self {
trace!("prepare command to be spawned: {cmd:?}");
let cmd = Some(cmd);
Self { cmd }
}
pub fn resume(&mut self, arg: Option<ProcessIo>) -> SpawnThenWaitWithOutputResult {
let Some(arg) = arg else {
let Some(cmd) = self.cmd.take() else {
return SpawnThenWaitWithOutputResult::Err(
SpawnThenWaitWithOutputError::NotInitialized,
);
};
trace!("break: need I/O to spawn command");
return SpawnThenWaitWithOutputResult::Io(ProcessIo::SpawnThenWaitWithOutput(Err(cmd)));
};
trace!("resume after spawning command");
let ProcessIo::SpawnThenWaitWithOutput(io) = arg else {
let err = SpawnThenWaitWithOutputError::InvalidArgument("spawn output", arg);
return SpawnThenWaitWithOutputResult::Err(err);
};
let output = match io {
Ok(output) => output,
Err(cmd) => {
let io = ProcessIo::SpawnThenWaitWithOutput(Err(cmd));
return SpawnThenWaitWithOutputResult::Io(io);
}
};
debug!("spawned command: {:?}", output.status);
SpawnThenWaitWithOutputResult::Ok(output)
}
}