1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
#![cfg(feature = "command")] use crate::IntoResult; use std::{ fmt::{self, Display}, io, process::{Child, ExitStatus, Output}, }; #[derive(Debug)] pub enum Error { SpawnFailed(io::Error), WaitFailed(ExitStatus), WaitWithOutputFailed(Output), } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::SpawnFailed(err) => write!(f, "Failed to spawn child process: {}", err), Self::WaitFailed(status) => { write!(f, "Command didn't complete successfully, ")?; if let Some(exit_code) = status.code() { write!(f, "exiting with code {}.", exit_code) } else { write!(f, "but returned no exit code.") } } Self::WaitWithOutputFailed(Output { status, stderr, .. }) => { write!(f, "{} ", Self::WaitFailed(status.to_owned()))?; if !stderr.is_empty() { write!(f, "stderr contents: {}", String::from_utf8_lossy(stderr)) } else { write!(f, "stderr was empty.") } } } } } impl From<io::Error> for Error { fn from(err: io::Error) -> Self { Self::SpawnFailed(err) } } impl From<ExitStatus> for Error { fn from(status: ExitStatus) -> Self { Self::WaitFailed(status) } } impl From<Output> for Error { fn from(output: Output) -> Self { Self::WaitWithOutputFailed(output) } } pub type Result<T> = std::result::Result<T, Error>; impl IntoResult<(), Error> for ExitStatus { fn into_result(self) -> Result<()> { self.success().into_result().map_err(|()| self.into()) } } impl IntoResult<(), Error> for io::Result<ExitStatus> { fn into_result(self) -> Result<()> { self.map_err(Into::into).and_then(IntoResult::into_result) } } impl IntoResult<Output, Error> for io::Result<Output> { fn into_result(self) -> Result<Output> { self.map_err(Into::into) .and_then(|output| output.status.into_result().map(|_| output)) } } impl IntoResult<Child, Error> for io::Result<Child> { fn into_result(self) -> Result<Child> { self.map_err(Into::into) } }