1#![allow(unknown_lints)]
2#![allow(bare_trait_objects)]
3#![allow(clippy::upper_case_acronyms)]
4
5use std::convert;
6use std::error;
7use std::fmt;
8use std::io;
9
10use git2;
11#[cfg(feature = "pcre")]
12use pcre2;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum ExitStatus {
16 Success = 0,
17 NonFatal = 1,
18 Fatal = 2,
19 ExternalProgramFailed = 3,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum ErrorKind {
24 NoSuchRevision,
25 Conflict,
26 GitError,
27 PCREError,
28 IOError,
29 BadPktlineHeader,
30 InvalidPacket,
31 UnexpectedPacket,
32 InvalidLFSOid,
33 InvalidInteger,
34 ParseError,
35 UnknownCommand,
36 MissingData,
37 ExtraData,
38 CorruptData,
39 NotAllowed,
40 InvalidPath,
41 DowncastError,
42}
43
44#[derive(Debug)]
45pub struct Error {
46 kind: ErrorKind,
47 internal: Option<Box<error::Error + Send + Sync>>,
48 message: Option<String>,
49}
50
51impl fmt::Display for Error {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 match self.kind {
54 ErrorKind::NoSuchRevision => write!(f, "fatal: needed a single revision"),
57 ErrorKind::Conflict => write!(f, "fatal: conflict"),
58 ErrorKind::PCREError => match self.internal {
59 Some(ref e) => write!(f, "fatal: invalid regular expression: {}", e),
60 None => write!(f, "fatal: invalid regular expression"),
61 },
62 ErrorKind::IOError => match self.internal {
63 Some(ref e) => write!(f, "fatal: I/O error: {}", e),
64 None => write!(f, "fatal: unknown I/O error"),
65 },
66 ErrorKind::GitError => match self.internal {
67 Some(ref e) => write!(f, "fatal: {}", e),
68 None => write!(f, "fatal: an unknown error occurred"),
69 },
70 ErrorKind::BadPktlineHeader => write!(f, "malformed or unknown pkt-line header"),
71 ErrorKind::InvalidPacket => write!(f, "invalid or malformed packet"),
72 ErrorKind::UnexpectedPacket => write!(f, "unexpected packet while parsing"),
73 ErrorKind::InvalidLFSOid => write!(f, "invalid or malformed LFS oid"),
74 ErrorKind::InvalidInteger => write!(f, "invalid or malformed integer or size value"),
75 ErrorKind::ParseError => write!(f, "parse error"),
76 ErrorKind::UnknownCommand => write!(f, "unknown command or operation"),
77 ErrorKind::MissingData => write!(f, "incomplete or missing data"),
78 ErrorKind::ExtraData => write!(f, "extra data"),
79 ErrorKind::CorruptData => write!(f, "corrupt data"),
80 ErrorKind::NotAllowed => write!(f, "not allowed"),
81 ErrorKind::InvalidPath => write!(f, "invalid path"),
82 ErrorKind::DowncastError => write!(f, "unexpected type when downcasting"),
83 }?;
84 if let Some(ref msg) = self.message {
85 write!(f, ": {}", msg)?;
86 };
87 Ok(())
88 }
89}
90
91impl error::Error for Error {
92 fn description(&self) -> &str {
93 "an unknown error"
94 }
95}
96
97impl PartialEq for Error {
98 fn eq(&self, other: &Self) -> bool {
99 self.kind == other.kind
100 }
101}
102
103impl Error {
104 pub fn new<E: Into<Box<error::Error + Send + Sync>>>(
108 kind: ErrorKind,
109 error: Option<E>,
110 ) -> Self {
111 Error {
112 kind,
113 internal: error.map(|e| e.into()),
114 message: None,
115 }
116 }
117
118 pub fn new_simple(kind: ErrorKind) -> Self {
120 Error {
121 kind,
122 internal: None,
123 message: None,
124 }
125 }
126
127 pub fn from_message<M: Into<String>>(kind: ErrorKind, msg: M) -> Self {
129 Error {
130 kind,
131 internal: None,
132 message: Some(msg.into()),
133 }
134 }
135
136 pub fn kind(&self) -> ErrorKind {
138 self.kind
139 }
140
141 pub fn io_kind(&self) -> io::ErrorKind {
146 match self.internal {
147 Some(ref e) => match e.downcast_ref::<io::Error>() {
148 Some(x) => x.kind(),
149 None => io::ErrorKind::InvalidData,
150 },
151 None => io::ErrorKind::InvalidData,
152 }
153 }
154
155 pub fn fatal(&self) -> bool {
160 self.exit_status() == ExitStatus::Fatal
161 }
162
163 pub fn exit_status(&self) -> ExitStatus {
165 match self.kind {
166 ErrorKind::NoSuchRevision => ExitStatus::NonFatal,
167 ErrorKind::Conflict => ExitStatus::NonFatal,
168 _ => ExitStatus::Fatal,
169 }
170 }
171}
172
173impl convert::From<Error> for io::Error {
174 fn from(error: Error) -> io::Error {
175 io::Error::new(error.io_kind(), error)
176 }
177}
178
179impl convert::From<git2::Error> for Error {
180 fn from(error: git2::Error) -> Self {
181 let kind = match error.code() {
182 git2::ErrorCode::NotFound => ErrorKind::NoSuchRevision,
183 git2::ErrorCode::Conflict => ErrorKind::Conflict,
184 _ => ErrorKind::GitError,
185 };
186 Error::new(kind, Some(error))
187 }
188}
189
190#[cfg(feature = "pcre")]
191impl convert::From<pcre2::Error> for Error {
192 fn from(error: pcre2::Error) -> Self {
193 Error::new(ErrorKind::PCREError, Some(error))
194 }
195}
196
197impl convert::From<io::Error> for Error {
198 fn from(error: io::Error) -> Self {
199 Error::new(ErrorKind::IOError, Some(error))
200 }
201}