extern crate std;
use std::error::Error as FmtError;
use self::Error::*;
#[derive(Debug)]
pub enum Error {
IOError(std::io::Error),
Failed(i32),
Killed,
}
impl From<i32> for Error {
fn from(code: i32) -> Self {
Failed(code)
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
IOError(error)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Failed(ref code) => write!(f, "{}: {}", self.description(), code),
_ => write!(f, "{}", self.description()),
}
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match *self {
IOError(ref err) => err.description(),
Killed => "Process received a deadly signal",
Failed(_) => "Process returned a non-zero exit code",
}
}
}
pub fn new(prog: &str) -> std::process::Command {
let mut cmd = std::process::Command::new(prog);
cmd.stdin(std::process::Stdio::null());
cmd
}
pub fn run(cmd: &mut std::process::Command) -> Result<(), Error> {
debug!("Running: {:?}", cmd);
match cmd.spawn() {
Ok(ref mut child) => {
match child.wait() {
Ok(status) => {
if status.success() { Ok(()) }
else {
if let Some(code) = status.code() { Err(Failed(code)) }
else { Err(Killed) }
}
},
Err(err) => { Err(IOError(err)) }
}
},
Err(err) => { Err(IOError(err)) }
}
}
pub fn run_get_stdout(mut cmd: &mut std::process::Command) -> Result<String, Error> {
cmd.stdout(std::process::Stdio::piped());
try!(run(&mut cmd));
let output = try!(cmd.output()).stdout;
Ok(String::from_utf8(output).unwrap())
}