| 1 | //! What a command can fail with, and the exit code each failure gives. |
| 2 | //! |
| 3 | //! The codes are stable, so scripts and agents can branch on them: |
| 4 | //! |
| 5 | //! | Code | Meaning | |
| 6 | //! | --- | --- | |
| 7 | //! | 0 | It worked. | |
| 8 | //! | 1 | It failed: the API refused, the network failed, checks failed. | |
| 9 | //! | 2 | The command was used wrongly: a flag, an argument, a JSON field. | |
| 10 | //! | 4 | Signing in is needed, or the token was refused. | |
| 11 | //! | 8 | Checks are still running (`g1t pr checks` without `--watch`). | |
| 12 | |
| 13 | use std::fmt; |
| 14 | |
| 15 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 16 | pub enum Kind { |
| 17 | Failed, |
| 18 | Usage, |
| 19 | Auth, |
| 20 | Pending, |
| 21 | } |
| 22 | |
| 23 | impl Kind { |
| 24 | pub fn code(self) -> u8 { |
| 25 | match self { |
| 26 | Kind::Failed => 1, |
| 27 | Kind::Usage => 2, |
| 28 | Kind::Auth => 4, |
| 29 | Kind::Pending => 8, |
| 30 | } |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | #[derive(Debug)] |
| 35 | pub struct Error { |
| 36 | pub kind: Kind, |
| 37 | pub message: String, |
| 38 | /// Already said on stderr: exit with the code and print nothing more. |
| 39 | pub silent: bool, |
| 40 | } |
| 41 | |
| 42 | pub type Result<T> = std::result::Result<T, Error>; |
| 43 | |
| 44 | impl Error { |
| 45 | pub fn failed(message: impl Into<String>) -> Error { |
| 46 | Error { |
| 47 | kind: Kind::Failed, |
| 48 | message: message.into(), |
| 49 | silent: false, |
| 50 | } |
| 51 | } |
| 52 | pub fn usage(message: impl Into<String>) -> Error { |
| 53 | Error { |
| 54 | kind: Kind::Usage, |
| 55 | message: message.into(), |
| 56 | silent: false, |
| 57 | } |
| 58 | } |
| 59 | pub fn auth(message: impl Into<String>) -> Error { |
| 60 | Error { |
| 61 | kind: Kind::Auth, |
| 62 | message: message.into(), |
| 63 | silent: false, |
| 64 | } |
| 65 | } |
| 66 | /// Exit with `kind`'s code without another line: the output said why. |
| 67 | pub fn exit(kind: Kind) -> Error { |
| 68 | Error { |
| 69 | kind, |
| 70 | message: String::new(), |
| 71 | silent: true, |
| 72 | } |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | impl fmt::Display for Error { |
| 77 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 78 | f.write_str(&self.message) |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | impl From<String> for Error { |
| 83 | fn from(message: String) -> Error { |
| 84 | Error::failed(message) |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | impl From<&str> for Error { |
| 89 | fn from(message: &str) -> Error { |
| 90 | Error::failed(message) |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | impl From<std::io::Error> for Error { |
| 95 | fn from(error: std::io::Error) -> Error { |
| 96 | Error::failed(error.to_string()) |
| 97 | } |
| 98 | } |