18 pub enum CommandError { |
18 pub enum CommandError { |
19 /// Exit with an error message and "standard" failure exit code. |
19 /// Exit with an error message and "standard" failure exit code. |
20 Abort { |
20 Abort { |
21 message: Vec<u8>, |
21 message: Vec<u8>, |
22 detailed_exit_code: exit_codes::ExitCode, |
22 detailed_exit_code: exit_codes::ExitCode, |
|
23 hint: Option<Vec<u8>>, |
23 }, |
24 }, |
24 |
25 |
25 /// Exit with a failure exit code but no message. |
26 /// Exit with a failure exit code but no message. |
26 Unsuccessful, |
27 Unsuccessful, |
27 |
28 |
48 // TODO: bytes-based (instead of Unicode-based) formatting |
49 // TODO: bytes-based (instead of Unicode-based) formatting |
49 // of error messages to handle non-UTF-8 filenames etc: |
50 // of error messages to handle non-UTF-8 filenames etc: |
50 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output |
51 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output |
51 message: utf8_to_local(message.as_ref()).into(), |
52 message: utf8_to_local(message.as_ref()).into(), |
52 detailed_exit_code: detailed_exit_code, |
53 detailed_exit_code: detailed_exit_code, |
|
54 hint: None, |
|
55 } |
|
56 } |
|
57 |
|
58 pub fn abort_with_exit_code_and_hint( |
|
59 message: impl AsRef<str>, |
|
60 detailed_exit_code: exit_codes::ExitCode, |
|
61 hint: Option<impl AsRef<str>>, |
|
62 ) -> Self { |
|
63 CommandError::Abort { |
|
64 message: utf8_to_local(message.as_ref()).into(), |
|
65 detailed_exit_code, |
|
66 hint: hint.map(|h| utf8_to_local(h.as_ref()).into()), |
53 } |
67 } |
54 } |
68 } |
55 |
69 |
56 pub fn abort_with_exit_code_bytes( |
70 pub fn abort_with_exit_code_bytes( |
57 message: impl AsRef<[u8]>, |
71 message: impl AsRef<[u8]>, |
60 // TODO: use this everywhere it makes sense instead of the string |
74 // TODO: use this everywhere it makes sense instead of the string |
61 // version. |
75 // version. |
62 CommandError::Abort { |
76 CommandError::Abort { |
63 message: message.as_ref().into(), |
77 message: message.as_ref().into(), |
64 detailed_exit_code, |
78 detailed_exit_code, |
|
79 hint: None, |
65 } |
80 } |
66 } |
81 } |
67 |
82 |
68 pub fn unsupported(message: impl AsRef<str>) -> Self { |
83 pub fn unsupported(message: impl AsRef<str>) -> Self { |
69 CommandError::UnsupportedFeature { |
84 CommandError::UnsupportedFeature { |
119 } |
137 } |
120 |
138 |
121 impl From<RepoError> for CommandError { |
139 impl From<RepoError> for CommandError { |
122 fn from(error: RepoError) -> Self { |
140 fn from(error: RepoError) -> Self { |
123 match error { |
141 match error { |
124 RepoError::NotFound { at } => CommandError::Abort { |
142 RepoError::NotFound { at } => { |
125 message: format_bytes!( |
143 CommandError::abort_with_exit_code_bytes( |
126 b"abort: repository {} not found", |
144 format_bytes!( |
127 get_bytes_from_path(at) |
145 b"abort: repository {} not found", |
128 ), |
146 get_bytes_from_path(at) |
129 detailed_exit_code: exit_codes::ABORT, |
147 ), |
130 }, |
148 exit_codes::ABORT, |
|
149 ) |
|
150 } |
131 RepoError::ConfigParseError(error) => error.into(), |
151 RepoError::ConfigParseError(error) => error.into(), |
132 RepoError::Other(error) => error.into(), |
152 RepoError::Other(error) => error.into(), |
133 } |
153 } |
134 } |
154 } |
135 } |
155 } |
136 |
156 |
137 impl<'a> From<&'a NoRepoInCwdError> for CommandError { |
157 impl<'a> From<&'a NoRepoInCwdError> for CommandError { |
138 fn from(error: &'a NoRepoInCwdError) -> Self { |
158 fn from(error: &'a NoRepoInCwdError) -> Self { |
139 let NoRepoInCwdError { cwd } = error; |
159 let NoRepoInCwdError { cwd } = error; |
140 CommandError::Abort { |
160 CommandError::abort_with_exit_code_bytes( |
141 message: format_bytes!( |
161 format_bytes!( |
142 b"abort: no repository found in '{}' (.hg not found)!", |
162 b"abort: no repository found in '{}' (.hg not found)!", |
143 get_bytes_from_path(cwd) |
163 get_bytes_from_path(cwd) |
144 ), |
164 ), |
145 detailed_exit_code: exit_codes::ABORT, |
165 exit_codes::ABORT, |
146 } |
166 ) |
147 } |
167 } |
148 } |
168 } |
149 |
169 |
150 impl From<ConfigError> for CommandError { |
170 impl From<ConfigError> for CommandError { |
151 fn from(error: ConfigError) -> Self { |
171 fn from(error: ConfigError) -> Self { |
166 let line_message = if let Some(line_number) = line { |
186 let line_message = if let Some(line_number) = line { |
167 format_bytes!(b":{}", line_number.to_string().into_bytes()) |
187 format_bytes!(b":{}", line_number.to_string().into_bytes()) |
168 } else { |
188 } else { |
169 Vec::new() |
189 Vec::new() |
170 }; |
190 }; |
171 CommandError::Abort { |
191 CommandError::abort_with_exit_code_bytes( |
172 message: format_bytes!( |
192 format_bytes!( |
173 b"config error at {}{}: {}", |
193 b"config error at {}{}: {}", |
174 origin, |
194 origin, |
175 line_message, |
195 line_message, |
176 message |
196 message |
177 ), |
197 ), |
178 detailed_exit_code: exit_codes::CONFIG_ERROR_ABORT, |
198 exit_codes::CONFIG_ERROR_ABORT, |
179 } |
199 ) |
180 } |
200 } |
181 } |
201 } |
182 |
202 |
183 impl From<(RevlogError, &str)> for CommandError { |
203 impl From<(RevlogError, &str)> for CommandError { |
184 fn from((err, rev): (RevlogError, &str)) -> CommandError { |
204 fn from((err, rev): (RevlogError, &str)) -> CommandError { |