You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
2.4 KiB

use std::{
error,
fmt,
path::{
PathBuf,
},
};
#[cfg(feature = "broken-pipe")]
pub const BROKEN_PIPE: char = '¦';
#[cfg(not(feature = "broken-pipe"))]
pub const BROKEN_PIPE: char = '|';
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ProcessArgs
{
pub name: String,
pub args: Vec<String>,
name_real: Option<PathBuf>, //get => `.name_path()`
}
mod proc_args;
pub use proc_args::*;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Operation
{
input: ProcessArgs,
outputs: Vec<ProcessArgs>,
output_to_tty: bool,
}
#[derive(Clone, Debug)]
pub struct Error(String, String);
impl error::Error for Error{}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "<{}>: {}", self.1, self.0)
}
}
impl Error
{
pub fn new<T>(message: T) -> Self
where T: AsRef<str>
{
Self(message.as_ref().to_owned(), program())
}
}
impl<T> From<T> for Error
where T: AsRef<str>
{
fn from(input: T) -> Self
{
Self::new(input)
}
}
impl Operation
{
pub fn new(input: ProcessArgs) -> Self
{
Self {
input,
outputs: Vec::new(),
output_to_tty: false,
}
}
pub fn tty(&self) -> bool
{
self.output_to_tty
}
pub fn parent(&self) -> &ProcessArgs
{
&self.input
}
pub fn children(&self) -> &Vec<ProcessArgs>
{
&self.outputs
}
pub fn validate(&mut self) -> Result<(), String>
{
if !self.output_to_tty && self.outputs.len()<1 {
return Err("Need at least one output.".to_owned());
}
self.input.name_real = Some(self.input.verify().or_else(|err| Err(format!("bad input <{}>: {}", &self.input, err)))?);
for x in self.outputs.iter_mut()
{
x.name_real = Some(x.verify().or_else(|err| Err(format!("bad output <{}>: {}", &x, err)))?);
}
Ok(())
}
}
pub fn program() -> String
{
std::env::args().next().unwrap()
}
pub fn parse() -> Result<Operation, Error>
{
let mut iter = std::env::args();
let this = iter.next().unwrap();
let mut not_last = false;
let input = ProcessArgs::parse(&mut iter, &mut not_last).or(Err("Expected at least one input"))?;
if !not_last {
return Err(Error::new("Need at least one output."));
}
let mut output = Operation::new(input);
while let Ok(op) = ProcessArgs::parse(&mut iter, &mut not_last) {
output.outputs.push(op);
}
if not_last {
output.output_to_tty = true;
}
output.validate()?;
Ok(output)
}