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, name_real: Option, //get => `.name_path()` } 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 tty(&self) -> bool { self.output_to_tty } pub fn parent(&self) -> &ProcessArgs { &self.input } pub fn children(&self) -> &Vec { &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 { 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) }