use std::{ error, fmt, }; #[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, } mod proc_args; pub use proc_args::*; #[derive(Clone, Debug, PartialEq, Eq)] pub struct Operation { input: ProcessArgs, outputs: Vec, 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(message: T) -> Self where T: AsRef { Self(message.as_ref().to_owned(), program()) } } impl From for Error where T: AsRef { 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 parent(&self) -> &ProcessArgs { &self.input } pub fn children(&self) -> &Vec { &self.outputs } pub fn validate(&self) -> Result<(), String> { if !self.output_to_tty && self.outputs.len()<1 { return Err("Need at least one output.".to_owned()); } self.input.verify().or_else(|err| Err(format!("bad input <{}>: {}", &self.input, err)))?; for x in self.outputs.iter() { 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 { 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) }