comparison mercurial/error.py @ 47289:33c0c25d0b0f

errors: let each Abort subclass define its error code It's more flexible to have the error codes defined on the error types themselves. That way extensions can easily set their own exit code. It also means that we can reduce a bit of duplication betwen `scmutil.callcatch()` and `chgserver.chgcmdserver.validate()`. Differential Revision: https://phab.mercurial-scm.org/D10735
author Martin von Zweigbergk <martinvonz@google.com>
date Tue, 18 May 2021 17:15:49 -0700
parents abd18d6306f1
children 5e736d2e9703
comparison
equal deleted inserted replaced
47288:16b48ebf656e 47289:33c0c25d0b0f
183 183
184 184
185 class Abort(Hint, Exception): 185 class Abort(Hint, Exception):
186 """Raised if a command needs to print an error and exit.""" 186 """Raised if a command needs to print an error and exit."""
187 187
188 def __init__(self, message, hint=None): 188 def __init__(self, message, hint=None, detailed_exit_code=None):
189 # type: (bytes, Optional[bytes]) -> None 189 # type: (bytes, Optional[bytes]) -> None
190 self.message = message 190 self.message = message
191 self.hint = hint 191 self.hint = hint
192 self.detailed_exit_code = detailed_exit_code
192 # Pass the message into the Exception constructor to help extensions 193 # Pass the message into the Exception constructor to help extensions
193 # that look for exc.args[0]. 194 # that look for exc.args[0].
194 Exception.__init__(self, message) 195 Exception.__init__(self, message)
195 196
196 def __bytes__(self): 197 def __bytes__(self):
218 """Indicates that the user made an error in their input. 219 """Indicates that the user made an error in their input.
219 220
220 Examples: Invalid command, invalid flags, invalid revision. 221 Examples: Invalid command, invalid flags, invalid revision.
221 """ 222 """
222 223
224 def __init__(self, message, hint=None):
225 super(InputError, self).__init__(
226 message, hint=hint, detailed_exit_code=10
227 )
228
223 229
224 class StateError(Abort): 230 class StateError(Abort):
225 """Indicates that the operation might work if retried in a different state. 231 """Indicates that the operation might work if retried in a different state.
226 232
227 Examples: Unresolved merge conflicts, unfinished operations. 233 Examples: Unresolved merge conflicts, unfinished operations.
228 """ 234 """
229 235
236 def __init__(self, message, hint=None):
237 super(StateError, self).__init__(
238 message, hint=hint, detailed_exit_code=20
239 )
240
230 241
231 class CanceledError(Abort): 242 class CanceledError(Abort):
232 """Indicates that the user canceled the operation. 243 """Indicates that the user canceled the operation.
233 244
234 Examples: Close commit editor with error status, quit chistedit. 245 Examples: Close commit editor with error status, quit chistedit.
235 """ 246 """
236 247
248 def __init__(self, message, hint=None):
249 super(CanceledError, self).__init__(
250 message, hint=hint, detailed_exit_code=250
251 )
252
237 253
238 class SecurityError(Abort): 254 class SecurityError(Abort):
239 """Indicates that some aspect of security failed. 255 """Indicates that some aspect of security failed.
240 256
241 Examples: Bad server credentials, expired local credentials for network 257 Examples: Bad server credentials, expired local credentials for network
242 filesystem, mismatched GPG signature, DoS protection. 258 filesystem, mismatched GPG signature, DoS protection.
243 """ 259 """
244 260
261 def __init__(self, message, hint=None):
262 super(SecurityError, self).__init__(
263 message, hint=hint, detailed_exit_code=150
264 )
265
245 266
246 class HookLoadError(Abort): 267 class HookLoadError(Abort):
247 """raised when loading a hook fails, aborting an operation 268 """raised when loading a hook fails, aborting an operation
248 269
249 Exists to allow more specialized catching.""" 270 Exists to allow more specialized catching."""
252 class HookAbort(Abort): 273 class HookAbort(Abort):
253 """raised when a validation hook fails, aborting an operation 274 """raised when a validation hook fails, aborting an operation
254 275
255 Exists to allow more specialized catching.""" 276 Exists to allow more specialized catching."""
256 277
278 def __init__(self, message, hint=None):
279 super(HookAbort, self).__init__(
280 message, hint=hint, detailed_exit_code=40
281 )
282
257 283
258 class ConfigError(Abort): 284 class ConfigError(Abort):
259 """Exception raised when parsing config files""" 285 """Exception raised when parsing config files"""
260 286
261 def __init__(self, message, location=None, hint=None): 287 def __init__(self, message, location=None, hint=None):
262 # type: (bytes, Optional[bytes], Optional[bytes]) -> None 288 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
263 super(ConfigError, self).__init__(message, hint=hint) 289 super(ConfigError, self).__init__(
290 message, hint=hint, detailed_exit_code=30
291 )
264 self.location = location 292 self.location = location
265 293
266 def format(self): 294 def format(self):
267 # type: () -> bytes 295 # type: () -> bytes
268 from .i18n import _ 296 from .i18n import _
305 333
306 334
307 class RemoteError(Abort): 335 class RemoteError(Abort):
308 """Exception raised when interacting with a remote repo fails""" 336 """Exception raised when interacting with a remote repo fails"""
309 337
338 def __init__(self, message, hint=None):
339 super(RemoteError, self).__init__(
340 message, hint=hint, detailed_exit_code=100
341 )
342
310 343
311 class OutOfBandError(RemoteError): 344 class OutOfBandError(RemoteError):
312 """Exception raised when a remote repo reports failure""" 345 """Exception raised when a remote repo reports failure"""
313 346
314 def __init__(self, message=None, hint=None): 347 def __init__(self, message=None, hint=None):
325 class ParseError(Abort): 358 class ParseError(Abort):
326 """Raised when parsing config files and {rev,file}sets (msg[, pos])""" 359 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
327 360
328 def __init__(self, message, location=None, hint=None): 361 def __init__(self, message, location=None, hint=None):
329 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None 362 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
330 super(ParseError, self).__init__(message, hint=hint) 363 super(ParseError, self).__init__(
364 message, hint=hint, detailed_exit_code=10
365 )
331 self.location = location 366 self.location = location
332 367
333 def format(self): 368 def format(self):
334 # type: () -> bytes 369 # type: () -> bytes
335 from .i18n import _ 370 from .i18n import _