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>;