use std::{
ffi::OsStr,
process::Command,
process::{Child, ExitStatus, Output},
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ExecutorError {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("Failed to run command '{} {}', exit code {exit_code}",
.command
.get_program()
.to_string_lossy(),
.command
.get_args()
.map(OsStr::to_string_lossy)
.collect::<Vec<_>>()
.join(" "),
)]
FailedCommand {
command: Box<Command>,
exit_code: i32,
},
#[error("Unable to get mutable stdin")]
NoStdIn,
}
pub struct Executor<'a, S>
where
S: AsRef<[u8]> + ?Sized,
{
stdin: Option<&'a S>,
piped_commands: Box<dyn FnMut(Option<&'a S>) -> Result<Child, ExecutorError> + 'a>,
}
impl<'a, S> Executor<'a, S>
where
S: AsRef<[u8]> + ?Sized,
{
pub fn new(
stdin: Option<&'a S>,
piped_commands: impl FnMut(Option<&'a S>) -> Result<Child, ExecutorError> + 'a,
) -> Self {
Self {
stdin,
piped_commands: Box::new(piped_commands),
}
}
pub fn status(&mut self) -> Result<ExitStatus, ExecutorError> {
Ok((self.piped_commands)(self.stdin)?.wait()?)
}
pub fn output(&mut self) -> Result<Output, ExecutorError> {
Ok((self.piped_commands)(self.stdin)?.wait_with_output()?)
}
}