Files
comlexr/src/pipe.rs
2025-01-30 21:04:54 -05:00

74 lines
1.9 KiB
Rust

use std::{
ffi::OsStr,
process::Command,
process::{Child, ExitStatus, Output},
};
use thiserror::Error;
/// Errors that can be created when running the `PipeExecutor`
#[derive(Debug, Error)]
pub enum ExecutorError {
/// IO Error
#[error(transparent)]
Io(#[from] std::io::Error),
/// Failed Command 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: Command, exit_code: i32 },
/// No stdin Error
#[error("Unable to get mutable stdin")]
NoStdIn,
}
/// A lazy piped command executor.
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,
{
/// Construct a `PipeExecutor`.
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),
}
}
/// Retrieves the `ExitStatus` of the last command.
///
/// # Errors
/// Will error if the exit status of any chained commands fail.
pub fn status(&mut self) -> Result<ExitStatus, ExecutorError> {
Ok((self.piped_commands)(self.stdin)?.wait()?)
}
/// Retrieves the `Output` of the last command.
///
/// # Errors
/// Will error if the exit status of any chained commands fail.
pub fn output(&mut self) -> Result<Output, ExecutorError> {
Ok((self.piped_commands)(self.stdin)?.wait_with_output()?)
}
}