feat: Pipe
This commit is contained in:
73
src/pipe.rs
Normal file
73
src/pipe.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
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()?)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user