1use std::io;
2use std::path::PathBuf;
3
4#[derive(Debug, thiserror::Error)]
5pub enum ViaError {
6 #[error("{0}")]
7 InvalidCli(String),
8
9 #[error(transparent)]
10 Clap(#[from] clap::Error),
11
12 #[error("could not determine config path: {0}")]
13 ConfigNotFound(String),
14
15 #[error("failed to read config `{path}`: {source}")]
16 ReadConfig { path: PathBuf, source: io::Error },
17
18 #[error("failed to parse config: {0}")]
19 ParseConfig(#[from] toml::de::Error),
20
21 #[error("invalid config: {0}")]
22 InvalidConfig(String),
23
24 #[error("unknown service `{0}`")]
25 UnknownService(String),
26
27 #[error("unknown capability `{capability}` for service `{service}`")]
28 UnknownCapability { service: String, capability: String },
29
30 #[error("missing required argument: {0}")]
31 MissingArgument(String),
32
33 #[error("invalid argument: {0}")]
34 InvalidArgument(String),
35
36 #[error("program `{program}` was not found: {source}")]
37 MissingProgram { program: String, source: io::Error },
38
39 #[error("program `{program}` failed with status {status:?}: {stderr}")]
40 ExternalCommandFailed {
41 program: String,
42 status: Option<i32>,
43 stderr: String,
44 },
45
46 #[error("secret `{secret}` is not configured for service `{service}`")]
47 UnknownSecret { service: String, secret: String },
48
49 #[error("doctor checks failed; see output above for setup guidance")]
50 DoctorFailed,
51
52 #[error("http error: {0}")]
53 Http(#[from] reqwest::Error),
54
55 #[error("json error: {0}")]
56 Json(#[from] serde_json::Error),
57
58 #[error("io error: {0}")]
59 Io(#[from] io::Error),
60}
61
62impl ViaError {
63 pub fn exit_code(&self) -> u8 {
64 match self {
65 ViaError::Clap(error) => {
66 if error.use_stderr() {
67 2
68 } else {
69 0
70 }
71 }
72 ViaError::InvalidCli(_)
73 | ViaError::InvalidConfig(_)
74 | ViaError::UnknownService(_)
75 | ViaError::UnknownCapability { .. }
76 | ViaError::MissingArgument(_)
77 | ViaError::InvalidArgument(_)
78 | ViaError::UnknownSecret { .. } => 2,
79 ViaError::ConfigNotFound(_)
80 | ViaError::ReadConfig { .. }
81 | ViaError::ParseConfig(_)
82 | ViaError::MissingProgram { .. }
83 | ViaError::ExternalCommandFailed { .. }
84 | ViaError::DoctorFailed
85 | ViaError::Http(_)
86 | ViaError::Json(_)
87 | ViaError::Io(_) => 1,
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn config_and_usage_errors_exit_two() {
98 assert_eq!(ViaError::InvalidConfig("bad".to_owned()).exit_code(), 2);
99 assert_eq!(ViaError::UnknownService("github".to_owned()).exit_code(), 2);
100 }
101
102 #[test]
103 fn runtime_errors_exit_one() {
104 let error = ViaError::ConfigNotFound("missing".to_owned());
105
106 assert_eq!(error.exit_code(), 1);
107 }
108}