anyhow_std/process/
exitstatus.rs

1use std::ops::Deref;
2
3/// Wrap [std::process::ExitStatus] to provide the command in error contexts
4#[derive(Debug, derive_more::From, derive_more::Into)]
5pub struct ExitStatus {
6    es: std::process::ExitStatus,
7    cmddesc: String,
8}
9
10impl Deref for ExitStatus {
11    type Target = std::process::ExitStatus;
12
13    fn deref(&self) -> &Self::Target {
14        &self.es
15    }
16}
17
18impl ExitStatus {
19    /// Emulate nightly [ExitStatus::exit_ok](std::process::ExitStatus::exit_ok), provide the command in error contexts
20    pub fn exit_ok(&self) -> anyhow::Result<()> {
21        if self.success() {
22            Ok(())
23        } else {
24            Err(anyhow::anyhow!("error exit status").context(format!(
25                "status: {}",
26                self.code()
27                    .map(|i| i.to_string())
28                    .unwrap_or_else(|| "n/a".to_string())
29            )))
30        }
31    }
32
33    /// Exit the process; on errors print the error message to stderr
34    pub fn exit(&self) -> ! {
35        let code = match self.exit_ok() {
36            Ok(()) => 0,
37            Err(e) => {
38                eprintln!("{:#}", e);
39                self.code().unwrap_or(-1)
40            }
41        };
42        std::process::exit(code)
43    }
44}
45
46impl std::fmt::Display for ExitStatus {
47    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
48        self.es.fmt(f)
49    }
50}