cargo_release/
error.rs

1#[derive(Debug)]
2pub struct CliError {
3    error: Option<anyhow::Error>,
4    code: i32,
5}
6
7impl CliError {
8    pub fn silent(code: i32) -> Self {
9        Self { error: None, code }
10    }
11
12    pub fn message(e: impl Into<anyhow::Error>) -> Self {
13        Self {
14            error: Some(e.into()),
15            code: 101,
16        }
17    }
18}
19
20macro_rules! process_error_from {
21    ($from:ty) => {
22        impl From<$from> for CliError {
23            fn from(error: $from) -> Self {
24                Self::message(error)
25            }
26        }
27    };
28}
29
30process_error_from!(anyhow::Error);
31process_error_from!(std::io::Error);
32process_error_from!(semver::Error);
33process_error_from!(ignore::Error);
34process_error_from!(tame_index::Error);
35process_error_from!(tame_index::external::reqwest::Error);
36process_error_from!(cargo_metadata::Error);
37process_error_from!(toml::ser::Error);
38process_error_from!(toml_edit::ser::Error);
39
40impl From<i32> for CliError {
41    fn from(code: i32) -> Self {
42        Self::silent(code)
43    }
44}
45
46impl std::fmt::Display for CliError {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        if let Some(error) = self.error.as_ref() {
49            error.fmt(f)
50        } else {
51            Ok(())
52        }
53    }
54}
55
56/// Report, delegating exiting to the caller.
57pub fn report(result: Result<(), CliError>) -> i32 {
58    match result {
59        Ok(()) => 0,
60        Err(err) => {
61            if let Some(error) = err.error {
62                // At this point, we might be exiting due to a broken pipe, just do our best and
63                // move on.
64                let _ = crate::ops::shell::error(error);
65            }
66            err.code
67        }
68    }
69}
70
71pub type CargoResult<T> = anyhow::Result<T>;