Skip to main content

semora_cli/
exit.rs

1//! Exit codes. `wait` defines them in the spec; every command uses the same ones.
2
3use std::fmt;
4
5pub const OK: i32 = 0;
6pub const ERROR: i32 = 1;
7pub const TIMEOUT: i32 = 2;
8pub const AUTH: i32 = 3;
9pub const NOT_FOUND: i32 = 4;
10
11/// An error that carries its exit code.
12#[derive(Debug)]
13pub struct Exit {
14    pub code: i32,
15    pub message: String,
16}
17
18impl fmt::Display for Exit {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        f.write_str(&self.message)
21    }
22}
23
24impl std::error::Error for Exit {}
25
26pub fn auth(message: impl Into<String>) -> anyhow::Error {
27    Exit {
28        code: AUTH,
29        message: message.into(),
30    }
31    .into()
32}
33
34pub fn not_found(message: impl Into<String>) -> anyhow::Error {
35    Exit {
36        code: NOT_FOUND,
37        message: message.into(),
38    }
39    .into()
40}
41
42pub fn timeout(message: impl Into<String>) -> anyhow::Error {
43    Exit {
44        code: TIMEOUT,
45        message: message.into(),
46    }
47    .into()
48}
49
50/// The exit code an error maps to.
51pub fn code_of(err: &anyhow::Error) -> i32 {
52    err.downcast_ref::<Exit>().map(|e| e.code).unwrap_or(ERROR)
53}
54
55pub fn is_not_found(err: &anyhow::Error) -> bool {
56    code_of(err) == NOT_FOUND
57}
58
59/// The server answered 409.
60#[derive(Debug)]
61pub struct Conflict(pub String);
62
63impl fmt::Display for Conflict {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        f.write_str(&self.0)
66    }
67}
68
69impl std::error::Error for Conflict {}
70
71pub fn is_conflict(err: &anyhow::Error) -> bool {
72    err.downcast_ref::<Conflict>().is_some()
73}