use super::utils::Check; use failure; use std::ffi::{OsStr, OsString}; use std::io; use std::path::Path; use std::process::{Child, Command, ExitStatus}; pub enum Executor { Wet(Command), Dry(DryCommand), } impl Executor { pub fn new>(program: S, dry: bool) -> Self { if dry { Executor::Dry(DryCommand { program: program.as_ref().into(), ..Default::default() }) } else { Executor::Wet(Command::new(program)) } } pub fn arg>(&mut self, arg: S) -> &mut Executor { match self { Executor::Wet(c) => { c.arg(arg); } Executor::Dry(c) => { c.args.push(arg.as_ref().into()); } } self } pub fn args(&mut self, args: I) -> &mut Executor where I: IntoIterator, S: AsRef, { match self { Executor::Wet(c) => { c.args(args); } Executor::Dry(c) => { c.args.extend(args.into_iter().map(|arg| arg.as_ref().into())); } } self } pub fn current_dir>(&mut self, dir: P) -> &mut Executor { match self { Executor::Wet(c) => { c.current_dir(dir); } Executor::Dry(c) => c.directory = Some(dir.as_ref().into()), } self } pub fn spawn(&mut self) -> Result { match self { Executor::Wet(c) => c.spawn().map(ExecutorChild::Wet), Executor::Dry(c) => { print!( "Dry running: {} {}", c.program.to_string_lossy(), c.args .iter() .map(|a| String::from(a.to_string_lossy())) .collect::>() .join(" ") ); match &c.directory { Some(dir) => println!(" in {}", dir.to_string_lossy()), None => println!(), }; Ok(ExecutorChild::Dry) } } } } #[derive(Default)] pub struct DryCommand { program: OsString, args: Vec, directory: Option, } pub enum ExecutorChild { Wet(Child), Dry, } impl ExecutorChild { pub fn wait(&mut self) -> Result { match self { ExecutorChild::Wet(c) => c.wait().map(ExecutorExitStatus::Wet), ExecutorChild::Dry => Ok(ExecutorExitStatus::Dry), } } } pub enum ExecutorExitStatus { Wet(ExitStatus), Dry, } impl Check for ExecutorExitStatus { fn check(self) -> Result<(), failure::Error> { match self { ExecutorExitStatus::Wet(e) => e.check(), ExecutorExitStatus::Dry => Ok(()), } } }