use std::fmt;
use std::process;
use std::str;
use failure;
pub type OutputResult = Result<process::Output, OutputError>;
#[derive(Fail, Debug)]
pub struct OutputError {
cmd: Option<String>,
stdin: Option<Vec<u8>>,
cause: OutputCause,
}
impl OutputError {
pub fn new(output: process::Output) -> Self {
Self {
cmd: None,
stdin: None,
cause: OutputCause::Expected(Output { output }),
}
}
pub fn with_cause<E>(cause: E) -> Self
where
E: Into<failure::Error>,
{
Self {
cmd: None,
stdin: None,
cause: OutputCause::Unexpected(cause.into()),
}
}
pub fn set_cmd(mut self, cmd: String) -> Self {
self.cmd = Some(cmd);
self
}
pub fn set_stdin(mut self, stdin: Vec<u8>) -> Self {
self.stdin = Some(stdin);
self
}
pub fn as_output(&self) -> Option<&process::Output> {
match self.cause {
OutputCause::Expected(ref e) => Some(&e.output),
OutputCause::Unexpected(_) => None,
}
}
}
impl fmt::Display for OutputError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref cmd) = self.cmd {
writeln!(f, "command=`{}`", cmd)?;
}
if let Some(ref stdin) = self.stdin {
if let Ok(stdin) = str::from_utf8(stdin) {
writeln!(f, "stdin=```{}```", stdin)?;
} else {
writeln!(f, "stdin=```{:?}```", stdin)?;
}
}
write!(f, "{}", self.cause)
}
}
#[derive(Debug)]
enum OutputCause {
Expected(Output),
Unexpected(failure::Error),
}
impl fmt::Display for OutputCause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
OutputCause::Expected(ref e) => write!(f, "{}", e),
OutputCause::Unexpected(ref e) => write!(f, "{}", e),
}
}
}
#[derive(Fail, Debug)]
struct Output {
output: process::Output,
}
impl fmt::Display for Output {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
output_fmt(&self.output, f)
}
}
pub(crate) fn output_fmt(output: &process::Output, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(code) = output.status.code() {
writeln!(f, "code={}", code)?;
} else {
writeln!(f, "code=<interrupted>")?;
}
if let Ok(stdout) = str::from_utf8(&output.stdout) {
writeln!(f, "stdout=```{}```", stdout)?;
} else {
writeln!(f, "stdout=```{:?}```", output.stdout)?;
}
if let Ok(stderr) = str::from_utf8(&output.stderr) {
writeln!(f, "stderr=```{}```", stderr)?;
} else {
writeln!(f, "stderr=```{:?}```", output.stderr)?;
}
Ok(())
}