##// END OF EJS Templates
errors: move Abort earlier, so more exceptions can subclass it...
Martin von Zweigbergk -
r48070:5e736d2e default
parent child Browse files
Show More
@@ -1,666 +1,666
1 # error.py - Mercurial exceptions
1 # error.py - Mercurial exceptions
2 #
2 #
3 # Copyright 2005-2008 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2008 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """Mercurial exceptions.
8 """Mercurial exceptions.
9
9
10 This allows us to catch exceptions at higher levels without forcing
10 This allows us to catch exceptions at higher levels without forcing
11 imports.
11 imports.
12 """
12 """
13
13
14 from __future__ import absolute_import
14 from __future__ import absolute_import
15
15
16 import difflib
16 import difflib
17
17
18 # Do not import anything but pycompat here, please
18 # Do not import anything but pycompat here, please
19 from . import pycompat
19 from . import pycompat
20
20
21 if pycompat.TYPE_CHECKING:
21 if pycompat.TYPE_CHECKING:
22 from typing import (
22 from typing import (
23 Any,
23 Any,
24 AnyStr,
24 AnyStr,
25 Iterable,
25 Iterable,
26 List,
26 List,
27 Optional,
27 Optional,
28 Sequence,
28 Sequence,
29 Union,
29 Union,
30 )
30 )
31
31
32
32
33 def _tobytes(exc):
33 def _tobytes(exc):
34 """Byte-stringify exception in the same way as BaseException_str()"""
34 """Byte-stringify exception in the same way as BaseException_str()"""
35 if not exc.args:
35 if not exc.args:
36 return b''
36 return b''
37 if len(exc.args) == 1:
37 if len(exc.args) == 1:
38 return pycompat.bytestr(exc.args[0])
38 return pycompat.bytestr(exc.args[0])
39 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
39 return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args)
40
40
41
41
42 class Hint(object):
42 class Hint(object):
43 """Mix-in to provide a hint of an error
43 """Mix-in to provide a hint of an error
44
44
45 This should come first in the inheritance list to consume a hint and
45 This should come first in the inheritance list to consume a hint and
46 pass remaining arguments to the exception class.
46 pass remaining arguments to the exception class.
47 """
47 """
48
48
49 def __init__(self, *args, **kw):
49 def __init__(self, *args, **kw):
50 self.hint = kw.pop('hint', None)
50 self.hint = kw.pop('hint', None)
51 super(Hint, self).__init__(*args, **kw)
51 super(Hint, self).__init__(*args, **kw)
52
52
53
53
54 class Abort(Hint, Exception):
55 """Raised if a command needs to print an error and exit."""
56
57 def __init__(self, message, hint=None, detailed_exit_code=None):
58 # type: (bytes, Optional[bytes]) -> None
59 self.message = message
60 self.hint = hint
61 self.detailed_exit_code = detailed_exit_code
62 # Pass the message into the Exception constructor to help extensions
63 # that look for exc.args[0].
64 Exception.__init__(self, message)
65
66 def __bytes__(self):
67 return self.message
68
69 if pycompat.ispy3:
70
71 def __str__(self):
72 # the output would be unreadable if the message was translated,
73 # but do not replace it with encoding.strfromlocal(), which
74 # may raise another exception.
75 return pycompat.sysstr(self.__bytes__())
76
77 def format(self):
78 # type: () -> bytes
79 from .i18n import _
80
81 message = _(b"abort: %s\n") % self.message
82 if self.hint:
83 message += _(b"(%s)\n") % self.hint
84 return message
85
86
54 class StorageError(Hint, Exception):
87 class StorageError(Hint, Exception):
55 """Raised when an error occurs in a storage layer.
88 """Raised when an error occurs in a storage layer.
56
89
57 Usually subclassed by a storage-specific exception.
90 Usually subclassed by a storage-specific exception.
58 """
91 """
59
92
60 __bytes__ = _tobytes
93 __bytes__ = _tobytes
61
94
62
95
63 class RevlogError(StorageError):
96 class RevlogError(StorageError):
64 pass
97 pass
65
98
66
99
67 class SidedataHashError(RevlogError):
100 class SidedataHashError(RevlogError):
68 def __init__(self, key, expected, got):
101 def __init__(self, key, expected, got):
69 self.hint = None
102 self.hint = None
70 self.sidedatakey = key
103 self.sidedatakey = key
71 self.expecteddigest = expected
104 self.expecteddigest = expected
72 self.actualdigest = got
105 self.actualdigest = got
73
106
74
107
75 class FilteredIndexError(IndexError):
108 class FilteredIndexError(IndexError):
76 __bytes__ = _tobytes
109 __bytes__ = _tobytes
77
110
78
111
79 class LookupError(RevlogError, KeyError):
112 class LookupError(RevlogError, KeyError):
80 def __init__(self, name, index, message):
113 def __init__(self, name, index, message):
81 self.name = name
114 self.name = name
82 self.index = index
115 self.index = index
83 # this can't be called 'message' because at least some installs of
116 # this can't be called 'message' because at least some installs of
84 # Python 2.6+ complain about the 'message' property being deprecated
117 # Python 2.6+ complain about the 'message' property being deprecated
85 self.lookupmessage = message
118 self.lookupmessage = message
86 if isinstance(name, bytes) and len(name) == 20:
119 if isinstance(name, bytes) and len(name) == 20:
87 from .node import hex
120 from .node import hex
88
121
89 name = hex(name)
122 name = hex(name)
90 # if name is a binary node, it can be None
123 # if name is a binary node, it can be None
91 RevlogError.__init__(
124 RevlogError.__init__(
92 self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message)
125 self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message)
93 )
126 )
94
127
95 def __bytes__(self):
128 def __bytes__(self):
96 return RevlogError.__bytes__(self)
129 return RevlogError.__bytes__(self)
97
130
98 def __str__(self):
131 def __str__(self):
99 return RevlogError.__str__(self)
132 return RevlogError.__str__(self)
100
133
101
134
102 class AmbiguousPrefixLookupError(LookupError):
135 class AmbiguousPrefixLookupError(LookupError):
103 pass
136 pass
104
137
105
138
106 class FilteredLookupError(LookupError):
139 class FilteredLookupError(LookupError):
107 pass
140 pass
108
141
109
142
110 class ManifestLookupError(LookupError):
143 class ManifestLookupError(LookupError):
111 pass
144 pass
112
145
113
146
114 class CommandError(Exception):
147 class CommandError(Exception):
115 """Exception raised on errors in parsing the command line."""
148 """Exception raised on errors in parsing the command line."""
116
149
117 def __init__(self, command, message):
150 def __init__(self, command, message):
118 # type: (bytes, bytes) -> None
151 # type: (bytes, bytes) -> None
119 self.command = command
152 self.command = command
120 self.message = message
153 self.message = message
121 super(CommandError, self).__init__()
154 super(CommandError, self).__init__()
122
155
123 __bytes__ = _tobytes
156 __bytes__ = _tobytes
124
157
125
158
126 class UnknownCommand(Exception):
159 class UnknownCommand(Exception):
127 """Exception raised if command is not in the command table."""
160 """Exception raised if command is not in the command table."""
128
161
129 def __init__(self, command, all_commands=None):
162 def __init__(self, command, all_commands=None):
130 # type: (bytes, Optional[List[bytes]]) -> None
163 # type: (bytes, Optional[List[bytes]]) -> None
131 self.command = command
164 self.command = command
132 self.all_commands = all_commands
165 self.all_commands = all_commands
133 super(UnknownCommand, self).__init__()
166 super(UnknownCommand, self).__init__()
134
167
135 __bytes__ = _tobytes
168 __bytes__ = _tobytes
136
169
137
170
138 class AmbiguousCommand(Exception):
171 class AmbiguousCommand(Exception):
139 """Exception raised if command shortcut matches more than one command."""
172 """Exception raised if command shortcut matches more than one command."""
140
173
141 def __init__(self, prefix, matches):
174 def __init__(self, prefix, matches):
142 # type: (bytes, List[bytes]) -> None
175 # type: (bytes, List[bytes]) -> None
143 self.prefix = prefix
176 self.prefix = prefix
144 self.matches = matches
177 self.matches = matches
145 super(AmbiguousCommand, self).__init__()
178 super(AmbiguousCommand, self).__init__()
146
179
147 __bytes__ = _tobytes
180 __bytes__ = _tobytes
148
181
149
182
150 class WorkerError(Exception):
183 class WorkerError(Exception):
151 """Exception raised when a worker process dies."""
184 """Exception raised when a worker process dies."""
152
185
153 def __init__(self, status_code):
186 def __init__(self, status_code):
154 # type: (int) -> None
187 # type: (int) -> None
155 self.status_code = status_code
188 self.status_code = status_code
156 # Pass status code to superclass just so it becomes part of __bytes__
189 # Pass status code to superclass just so it becomes part of __bytes__
157 super(WorkerError, self).__init__(status_code)
190 super(WorkerError, self).__init__(status_code)
158
191
159 __bytes__ = _tobytes
192 __bytes__ = _tobytes
160
193
161
194
162 class InterventionRequired(Hint, Exception):
195 class InterventionRequired(Hint, Exception):
163 """Exception raised when a command requires human intervention."""
196 """Exception raised when a command requires human intervention."""
164
197
165 __bytes__ = _tobytes
198 __bytes__ = _tobytes
166
199
167
200
168 class ConflictResolutionRequired(InterventionRequired):
201 class ConflictResolutionRequired(InterventionRequired):
169 """Exception raised when a continuable command required merge conflict resolution."""
202 """Exception raised when a continuable command required merge conflict resolution."""
170
203
171 def __init__(self, opname):
204 def __init__(self, opname):
172 # type: (bytes) -> None
205 # type: (bytes) -> None
173 from .i18n import _
206 from .i18n import _
174
207
175 self.opname = opname
208 self.opname = opname
176 InterventionRequired.__init__(
209 InterventionRequired.__init__(
177 self,
210 self,
178 _(
211 _(
179 b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')"
212 b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')"
180 )
213 )
181 % opname,
214 % opname,
182 )
215 )
183
216
184
217
185 class Abort(Hint, Exception):
186 """Raised if a command needs to print an error and exit."""
187
188 def __init__(self, message, hint=None, detailed_exit_code=None):
189 # type: (bytes, Optional[bytes]) -> None
190 self.message = message
191 self.hint = hint
192 self.detailed_exit_code = detailed_exit_code
193 # Pass the message into the Exception constructor to help extensions
194 # that look for exc.args[0].
195 Exception.__init__(self, message)
196
197 def __bytes__(self):
198 return self.message
199
200 if pycompat.ispy3:
201
202 def __str__(self):
203 # the output would be unreadable if the message was translated,
204 # but do not replace it with encoding.strfromlocal(), which
205 # may raise another exception.
206 return pycompat.sysstr(self.__bytes__())
207
208 def format(self):
209 # type: () -> bytes
210 from .i18n import _
211
212 message = _(b"abort: %s\n") % self.message
213 if self.hint:
214 message += _(b"(%s)\n") % self.hint
215 return message
216
217
218 class InputError(Abort):
218 class InputError(Abort):
219 """Indicates that the user made an error in their input.
219 """Indicates that the user made an error in their input.
220
220
221 Examples: Invalid command, invalid flags, invalid revision.
221 Examples: Invalid command, invalid flags, invalid revision.
222 """
222 """
223
223
224 def __init__(self, message, hint=None):
224 def __init__(self, message, hint=None):
225 super(InputError, self).__init__(
225 super(InputError, self).__init__(
226 message, hint=hint, detailed_exit_code=10
226 message, hint=hint, detailed_exit_code=10
227 )
227 )
228
228
229
229
230 class StateError(Abort):
230 class StateError(Abort):
231 """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.
232
232
233 Examples: Unresolved merge conflicts, unfinished operations.
233 Examples: Unresolved merge conflicts, unfinished operations.
234 """
234 """
235
235
236 def __init__(self, message, hint=None):
236 def __init__(self, message, hint=None):
237 super(StateError, self).__init__(
237 super(StateError, self).__init__(
238 message, hint=hint, detailed_exit_code=20
238 message, hint=hint, detailed_exit_code=20
239 )
239 )
240
240
241
241
242 class CanceledError(Abort):
242 class CanceledError(Abort):
243 """Indicates that the user canceled the operation.
243 """Indicates that the user canceled the operation.
244
244
245 Examples: Close commit editor with error status, quit chistedit.
245 Examples: Close commit editor with error status, quit chistedit.
246 """
246 """
247
247
248 def __init__(self, message, hint=None):
248 def __init__(self, message, hint=None):
249 super(CanceledError, self).__init__(
249 super(CanceledError, self).__init__(
250 message, hint=hint, detailed_exit_code=250
250 message, hint=hint, detailed_exit_code=250
251 )
251 )
252
252
253
253
254 class SecurityError(Abort):
254 class SecurityError(Abort):
255 """Indicates that some aspect of security failed.
255 """Indicates that some aspect of security failed.
256
256
257 Examples: Bad server credentials, expired local credentials for network
257 Examples: Bad server credentials, expired local credentials for network
258 filesystem, mismatched GPG signature, DoS protection.
258 filesystem, mismatched GPG signature, DoS protection.
259 """
259 """
260
260
261 def __init__(self, message, hint=None):
261 def __init__(self, message, hint=None):
262 super(SecurityError, self).__init__(
262 super(SecurityError, self).__init__(
263 message, hint=hint, detailed_exit_code=150
263 message, hint=hint, detailed_exit_code=150
264 )
264 )
265
265
266
266
267 class HookLoadError(Abort):
267 class HookLoadError(Abort):
268 """raised when loading a hook fails, aborting an operation
268 """raised when loading a hook fails, aborting an operation
269
269
270 Exists to allow more specialized catching."""
270 Exists to allow more specialized catching."""
271
271
272
272
273 class HookAbort(Abort):
273 class HookAbort(Abort):
274 """raised when a validation hook fails, aborting an operation
274 """raised when a validation hook fails, aborting an operation
275
275
276 Exists to allow more specialized catching."""
276 Exists to allow more specialized catching."""
277
277
278 def __init__(self, message, hint=None):
278 def __init__(self, message, hint=None):
279 super(HookAbort, self).__init__(
279 super(HookAbort, self).__init__(
280 message, hint=hint, detailed_exit_code=40
280 message, hint=hint, detailed_exit_code=40
281 )
281 )
282
282
283
283
284 class ConfigError(Abort):
284 class ConfigError(Abort):
285 """Exception raised when parsing config files"""
285 """Exception raised when parsing config files"""
286
286
287 def __init__(self, message, location=None, hint=None):
287 def __init__(self, message, location=None, hint=None):
288 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
288 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
289 super(ConfigError, self).__init__(
289 super(ConfigError, self).__init__(
290 message, hint=hint, detailed_exit_code=30
290 message, hint=hint, detailed_exit_code=30
291 )
291 )
292 self.location = location
292 self.location = location
293
293
294 def format(self):
294 def format(self):
295 # type: () -> bytes
295 # type: () -> bytes
296 from .i18n import _
296 from .i18n import _
297
297
298 if self.location is not None:
298 if self.location is not None:
299 message = _(b"config error at %s: %s\n") % (
299 message = _(b"config error at %s: %s\n") % (
300 pycompat.bytestr(self.location),
300 pycompat.bytestr(self.location),
301 self.message,
301 self.message,
302 )
302 )
303 else:
303 else:
304 message = _(b"config error: %s\n") % self.message
304 message = _(b"config error: %s\n") % self.message
305 if self.hint:
305 if self.hint:
306 message += _(b"(%s)\n") % self.hint
306 message += _(b"(%s)\n") % self.hint
307 return message
307 return message
308
308
309
309
310 class UpdateAbort(Abort):
310 class UpdateAbort(Abort):
311 """Raised when an update is aborted for destination issue"""
311 """Raised when an update is aborted for destination issue"""
312
312
313
313
314 class MergeDestAbort(Abort):
314 class MergeDestAbort(Abort):
315 """Raised when an update is aborted for destination issues"""
315 """Raised when an update is aborted for destination issues"""
316
316
317
317
318 class NoMergeDestAbort(MergeDestAbort):
318 class NoMergeDestAbort(MergeDestAbort):
319 """Raised when an update is aborted because there is nothing to merge"""
319 """Raised when an update is aborted because there is nothing to merge"""
320
320
321
321
322 class ManyMergeDestAbort(MergeDestAbort):
322 class ManyMergeDestAbort(MergeDestAbort):
323 """Raised when an update is aborted because destination is ambiguous"""
323 """Raised when an update is aborted because destination is ambiguous"""
324
324
325
325
326 class ResponseExpected(Abort):
326 class ResponseExpected(Abort):
327 """Raised when an EOF is received for a prompt"""
327 """Raised when an EOF is received for a prompt"""
328
328
329 def __init__(self):
329 def __init__(self):
330 from .i18n import _
330 from .i18n import _
331
331
332 Abort.__init__(self, _(b'response expected'))
332 Abort.__init__(self, _(b'response expected'))
333
333
334
334
335 class RemoteError(Abort):
335 class RemoteError(Abort):
336 """Exception raised when interacting with a remote repo fails"""
336 """Exception raised when interacting with a remote repo fails"""
337
337
338 def __init__(self, message, hint=None):
338 def __init__(self, message, hint=None):
339 super(RemoteError, self).__init__(
339 super(RemoteError, self).__init__(
340 message, hint=hint, detailed_exit_code=100
340 message, hint=hint, detailed_exit_code=100
341 )
341 )
342
342
343
343
344 class OutOfBandError(RemoteError):
344 class OutOfBandError(RemoteError):
345 """Exception raised when a remote repo reports failure"""
345 """Exception raised when a remote repo reports failure"""
346
346
347 def __init__(self, message=None, hint=None):
347 def __init__(self, message=None, hint=None):
348 from .i18n import _
348 from .i18n import _
349
349
350 if message:
350 if message:
351 # Abort.format() adds a trailing newline
351 # Abort.format() adds a trailing newline
352 message = _(b"remote error:\n%s") % message.rstrip(b'\n')
352 message = _(b"remote error:\n%s") % message.rstrip(b'\n')
353 else:
353 else:
354 message = _(b"remote error")
354 message = _(b"remote error")
355 super(OutOfBandError, self).__init__(message, hint=hint)
355 super(OutOfBandError, self).__init__(message, hint=hint)
356
356
357
357
358 class ParseError(Abort):
358 class ParseError(Abort):
359 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
359 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
360
360
361 def __init__(self, message, location=None, hint=None):
361 def __init__(self, message, location=None, hint=None):
362 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
362 # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
363 super(ParseError, self).__init__(
363 super(ParseError, self).__init__(
364 message, hint=hint, detailed_exit_code=10
364 message, hint=hint, detailed_exit_code=10
365 )
365 )
366 self.location = location
366 self.location = location
367
367
368 def format(self):
368 def format(self):
369 # type: () -> bytes
369 # type: () -> bytes
370 from .i18n import _
370 from .i18n import _
371
371
372 if self.location is not None:
372 if self.location is not None:
373 message = _(b"hg: parse error at %s: %s\n") % (
373 message = _(b"hg: parse error at %s: %s\n") % (
374 pycompat.bytestr(self.location),
374 pycompat.bytestr(self.location),
375 self.message,
375 self.message,
376 )
376 )
377 else:
377 else:
378 message = _(b"hg: parse error: %s\n") % self.message
378 message = _(b"hg: parse error: %s\n") % self.message
379 if self.hint:
379 if self.hint:
380 message += _(b"(%s)\n") % self.hint
380 message += _(b"(%s)\n") % self.hint
381 return message
381 return message
382
382
383
383
384 class PatchError(Exception):
384 class PatchError(Exception):
385 __bytes__ = _tobytes
385 __bytes__ = _tobytes
386
386
387
387
388 def getsimilar(symbols, value):
388 def getsimilar(symbols, value):
389 # type: (Iterable[bytes], bytes) -> List[bytes]
389 # type: (Iterable[bytes], bytes) -> List[bytes]
390 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
390 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
391 # The cutoff for similarity here is pretty arbitrary. It should
391 # The cutoff for similarity here is pretty arbitrary. It should
392 # probably be investigated and tweaked.
392 # probably be investigated and tweaked.
393 return [s for s in symbols if sim(s) > 0.6]
393 return [s for s in symbols if sim(s) > 0.6]
394
394
395
395
396 def similarity_hint(similar):
396 def similarity_hint(similar):
397 # type: (List[bytes]) -> Optional[bytes]
397 # type: (List[bytes]) -> Optional[bytes]
398 from .i18n import _
398 from .i18n import _
399
399
400 if len(similar) == 1:
400 if len(similar) == 1:
401 return _(b"did you mean %s?") % similar[0]
401 return _(b"did you mean %s?") % similar[0]
402 elif similar:
402 elif similar:
403 ss = b", ".join(sorted(similar))
403 ss = b", ".join(sorted(similar))
404 return _(b"did you mean one of %s?") % ss
404 return _(b"did you mean one of %s?") % ss
405 else:
405 else:
406 return None
406 return None
407
407
408
408
409 class UnknownIdentifier(ParseError):
409 class UnknownIdentifier(ParseError):
410 """Exception raised when a {rev,file}set references an unknown identifier"""
410 """Exception raised when a {rev,file}set references an unknown identifier"""
411
411
412 def __init__(self, function, symbols):
412 def __init__(self, function, symbols):
413 # type: (bytes, Iterable[bytes]) -> None
413 # type: (bytes, Iterable[bytes]) -> None
414 from .i18n import _
414 from .i18n import _
415
415
416 similar = getsimilar(symbols, function)
416 similar = getsimilar(symbols, function)
417 hint = similarity_hint(similar)
417 hint = similarity_hint(similar)
418
418
419 ParseError.__init__(
419 ParseError.__init__(
420 self, _(b"unknown identifier: %s") % function, hint=hint
420 self, _(b"unknown identifier: %s") % function, hint=hint
421 )
421 )
422
422
423
423
424 class RepoError(Hint, Exception):
424 class RepoError(Hint, Exception):
425 __bytes__ = _tobytes
425 __bytes__ = _tobytes
426
426
427
427
428 class RepoLookupError(RepoError):
428 class RepoLookupError(RepoError):
429 pass
429 pass
430
430
431
431
432 class FilteredRepoLookupError(RepoLookupError):
432 class FilteredRepoLookupError(RepoLookupError):
433 pass
433 pass
434
434
435
435
436 class CapabilityError(RepoError):
436 class CapabilityError(RepoError):
437 pass
437 pass
438
438
439
439
440 class RequirementError(RepoError):
440 class RequirementError(RepoError):
441 """Exception raised if .hg/requires has an unknown entry."""
441 """Exception raised if .hg/requires has an unknown entry."""
442
442
443
443
444 class StdioError(IOError):
444 class StdioError(IOError):
445 """Raised if I/O to stdout or stderr fails"""
445 """Raised if I/O to stdout or stderr fails"""
446
446
447 def __init__(self, err):
447 def __init__(self, err):
448 # type: (IOError) -> None
448 # type: (IOError) -> None
449 IOError.__init__(self, err.errno, err.strerror)
449 IOError.__init__(self, err.errno, err.strerror)
450
450
451 # no __bytes__() because error message is derived from the standard IOError
451 # no __bytes__() because error message is derived from the standard IOError
452
452
453
453
454 class UnsupportedMergeRecords(Abort):
454 class UnsupportedMergeRecords(Abort):
455 def __init__(self, recordtypes):
455 def __init__(self, recordtypes):
456 # type: (Iterable[bytes]) -> None
456 # type: (Iterable[bytes]) -> None
457 from .i18n import _
457 from .i18n import _
458
458
459 self.recordtypes = sorted(recordtypes)
459 self.recordtypes = sorted(recordtypes)
460 s = b' '.join(self.recordtypes)
460 s = b' '.join(self.recordtypes)
461 Abort.__init__(
461 Abort.__init__(
462 self,
462 self,
463 _(b'unsupported merge state records: %s') % s,
463 _(b'unsupported merge state records: %s') % s,
464 hint=_(
464 hint=_(
465 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
465 b'see https://mercurial-scm.org/wiki/MergeStateRecords for '
466 b'more information'
466 b'more information'
467 ),
467 ),
468 )
468 )
469
469
470
470
471 class UnknownVersion(Abort):
471 class UnknownVersion(Abort):
472 """generic exception for aborting from an encounter with an unknown version"""
472 """generic exception for aborting from an encounter with an unknown version"""
473
473
474 def __init__(self, msg, hint=None, version=None):
474 def __init__(self, msg, hint=None, version=None):
475 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
475 # type: (bytes, Optional[bytes], Optional[bytes]) -> None
476 self.version = version
476 self.version = version
477 super(UnknownVersion, self).__init__(msg, hint=hint)
477 super(UnknownVersion, self).__init__(msg, hint=hint)
478
478
479
479
480 class LockError(IOError):
480 class LockError(IOError):
481 def __init__(self, errno, strerror, filename, desc):
481 def __init__(self, errno, strerror, filename, desc):
482 # TODO: figure out if this should be bytes or str
482 # TODO: figure out if this should be bytes or str
483 # _type: (int, str, str, bytes) -> None
483 # _type: (int, str, str, bytes) -> None
484 IOError.__init__(self, errno, strerror, filename)
484 IOError.__init__(self, errno, strerror, filename)
485 self.desc = desc
485 self.desc = desc
486
486
487 # no __bytes__() because error message is derived from the standard IOError
487 # no __bytes__() because error message is derived from the standard IOError
488
488
489
489
490 class LockHeld(LockError):
490 class LockHeld(LockError):
491 def __init__(self, errno, filename, desc, locker):
491 def __init__(self, errno, filename, desc, locker):
492 LockError.__init__(self, errno, b'Lock held', filename, desc)
492 LockError.__init__(self, errno, b'Lock held', filename, desc)
493 self.locker = locker
493 self.locker = locker
494
494
495
495
496 class LockUnavailable(LockError):
496 class LockUnavailable(LockError):
497 pass
497 pass
498
498
499
499
500 # LockError is for errors while acquiring the lock -- this is unrelated
500 # LockError is for errors while acquiring the lock -- this is unrelated
501 class LockInheritanceContractViolation(RuntimeError):
501 class LockInheritanceContractViolation(RuntimeError):
502 __bytes__ = _tobytes
502 __bytes__ = _tobytes
503
503
504
504
505 class ResponseError(Exception):
505 class ResponseError(Exception):
506 """Raised to print an error with part of output and exit."""
506 """Raised to print an error with part of output and exit."""
507
507
508 __bytes__ = _tobytes
508 __bytes__ = _tobytes
509
509
510
510
511 # derived from KeyboardInterrupt to simplify some breakout code
511 # derived from KeyboardInterrupt to simplify some breakout code
512 class SignalInterrupt(KeyboardInterrupt):
512 class SignalInterrupt(KeyboardInterrupt):
513 """Exception raised on SIGTERM and SIGHUP."""
513 """Exception raised on SIGTERM and SIGHUP."""
514
514
515
515
516 class SignatureError(Exception):
516 class SignatureError(Exception):
517 __bytes__ = _tobytes
517 __bytes__ = _tobytes
518
518
519
519
520 class PushRaced(RuntimeError):
520 class PushRaced(RuntimeError):
521 """An exception raised during unbundling that indicate a push race"""
521 """An exception raised during unbundling that indicate a push race"""
522
522
523 __bytes__ = _tobytes
523 __bytes__ = _tobytes
524
524
525
525
526 class ProgrammingError(Hint, RuntimeError):
526 class ProgrammingError(Hint, RuntimeError):
527 """Raised if a mercurial (core or extension) developer made a mistake"""
527 """Raised if a mercurial (core or extension) developer made a mistake"""
528
528
529 def __init__(self, msg, *args, **kwargs):
529 def __init__(self, msg, *args, **kwargs):
530 # type: (AnyStr, Any, Any) -> None
530 # type: (AnyStr, Any, Any) -> None
531 # On Python 3, turn the message back into a string since this is
531 # On Python 3, turn the message back into a string since this is
532 # an internal-only error that won't be printed except in a
532 # an internal-only error that won't be printed except in a
533 # stack traces.
533 # stack traces.
534 msg = pycompat.sysstr(msg)
534 msg = pycompat.sysstr(msg)
535 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
535 super(ProgrammingError, self).__init__(msg, *args, **kwargs)
536
536
537 __bytes__ = _tobytes
537 __bytes__ = _tobytes
538
538
539
539
540 class WdirUnsupported(Exception):
540 class WdirUnsupported(Exception):
541 """An exception which is raised when 'wdir()' is not supported"""
541 """An exception which is raised when 'wdir()' is not supported"""
542
542
543 __bytes__ = _tobytes
543 __bytes__ = _tobytes
544
544
545
545
546 # bundle2 related errors
546 # bundle2 related errors
547 class BundleValueError(ValueError):
547 class BundleValueError(ValueError):
548 """error raised when bundle2 cannot be processed"""
548 """error raised when bundle2 cannot be processed"""
549
549
550 __bytes__ = _tobytes
550 __bytes__ = _tobytes
551
551
552
552
553 class BundleUnknownFeatureError(BundleValueError):
553 class BundleUnknownFeatureError(BundleValueError):
554 def __init__(self, parttype=None, params=(), values=()):
554 def __init__(self, parttype=None, params=(), values=()):
555 self.parttype = parttype
555 self.parttype = parttype
556 self.params = params
556 self.params = params
557 self.values = values
557 self.values = values
558 if self.parttype is None:
558 if self.parttype is None:
559 msg = b'Stream Parameter'
559 msg = b'Stream Parameter'
560 else:
560 else:
561 msg = parttype
561 msg = parttype
562 entries = self.params
562 entries = self.params
563 if self.params and self.values:
563 if self.params and self.values:
564 assert len(self.params) == len(self.values)
564 assert len(self.params) == len(self.values)
565 entries = []
565 entries = []
566 for idx, par in enumerate(self.params):
566 for idx, par in enumerate(self.params):
567 val = self.values[idx]
567 val = self.values[idx]
568 if val is None:
568 if val is None:
569 entries.append(val)
569 entries.append(val)
570 else:
570 else:
571 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
571 entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val)))
572 if entries:
572 if entries:
573 msg = b'%s - %s' % (msg, b', '.join(entries))
573 msg = b'%s - %s' % (msg, b', '.join(entries))
574 ValueError.__init__(self, msg) # TODO: convert to str?
574 ValueError.__init__(self, msg) # TODO: convert to str?
575
575
576
576
577 class ReadOnlyPartError(RuntimeError):
577 class ReadOnlyPartError(RuntimeError):
578 """error raised when code tries to alter a part being generated"""
578 """error raised when code tries to alter a part being generated"""
579
579
580 __bytes__ = _tobytes
580 __bytes__ = _tobytes
581
581
582
582
583 class PushkeyFailed(Abort):
583 class PushkeyFailed(Abort):
584 """error raised when a pushkey part failed to update a value"""
584 """error raised when a pushkey part failed to update a value"""
585
585
586 def __init__(
586 def __init__(
587 self, partid, namespace=None, key=None, new=None, old=None, ret=None
587 self, partid, namespace=None, key=None, new=None, old=None, ret=None
588 ):
588 ):
589 self.partid = partid
589 self.partid = partid
590 self.namespace = namespace
590 self.namespace = namespace
591 self.key = key
591 self.key = key
592 self.new = new
592 self.new = new
593 self.old = old
593 self.old = old
594 self.ret = ret
594 self.ret = ret
595 # no i18n expected to be processed into a better message
595 # no i18n expected to be processed into a better message
596 Abort.__init__(
596 Abort.__init__(
597 self, b'failed to update value for "%s/%s"' % (namespace, key)
597 self, b'failed to update value for "%s/%s"' % (namespace, key)
598 )
598 )
599
599
600
600
601 class CensoredNodeError(StorageError):
601 class CensoredNodeError(StorageError):
602 """error raised when content verification fails on a censored node
602 """error raised when content verification fails on a censored node
603
603
604 Also contains the tombstone data substituted for the uncensored data.
604 Also contains the tombstone data substituted for the uncensored data.
605 """
605 """
606
606
607 def __init__(self, filename, node, tombstone):
607 def __init__(self, filename, node, tombstone):
608 # type: (bytes, bytes, bytes) -> None
608 # type: (bytes, bytes, bytes) -> None
609 from .node import short
609 from .node import short
610
610
611 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
611 StorageError.__init__(self, b'%s:%s' % (filename, short(node)))
612 self.tombstone = tombstone
612 self.tombstone = tombstone
613
613
614
614
615 class CensoredBaseError(StorageError):
615 class CensoredBaseError(StorageError):
616 """error raised when a delta is rejected because its base is censored
616 """error raised when a delta is rejected because its base is censored
617
617
618 A delta based on a censored revision must be formed as single patch
618 A delta based on a censored revision must be formed as single patch
619 operation which replaces the entire base with new content. This ensures
619 operation which replaces the entire base with new content. This ensures
620 the delta may be applied by clones which have not censored the base.
620 the delta may be applied by clones which have not censored the base.
621 """
621 """
622
622
623
623
624 class InvalidBundleSpecification(Exception):
624 class InvalidBundleSpecification(Exception):
625 """error raised when a bundle specification is invalid.
625 """error raised when a bundle specification is invalid.
626
626
627 This is used for syntax errors as opposed to support errors.
627 This is used for syntax errors as opposed to support errors.
628 """
628 """
629
629
630 __bytes__ = _tobytes
630 __bytes__ = _tobytes
631
631
632
632
633 class UnsupportedBundleSpecification(Exception):
633 class UnsupportedBundleSpecification(Exception):
634 """error raised when a bundle specification is not supported."""
634 """error raised when a bundle specification is not supported."""
635
635
636 __bytes__ = _tobytes
636 __bytes__ = _tobytes
637
637
638
638
639 class CorruptedState(Exception):
639 class CorruptedState(Exception):
640 """error raised when a command is not able to read its state from file"""
640 """error raised when a command is not able to read its state from file"""
641
641
642 __bytes__ = _tobytes
642 __bytes__ = _tobytes
643
643
644
644
645 class PeerTransportError(Abort):
645 class PeerTransportError(Abort):
646 """Transport-level I/O error when communicating with a peer repo."""
646 """Transport-level I/O error when communicating with a peer repo."""
647
647
648
648
649 class InMemoryMergeConflictsError(Exception):
649 class InMemoryMergeConflictsError(Exception):
650 """Exception raised when merge conflicts arose during an in-memory merge."""
650 """Exception raised when merge conflicts arose during an in-memory merge."""
651
651
652 __bytes__ = _tobytes
652 __bytes__ = _tobytes
653
653
654
654
655 class WireprotoCommandError(Exception):
655 class WireprotoCommandError(Exception):
656 """Represents an error during execution of a wire protocol command.
656 """Represents an error during execution of a wire protocol command.
657
657
658 Should only be thrown by wire protocol version 2 commands.
658 Should only be thrown by wire protocol version 2 commands.
659
659
660 The error is a formatter string and an optional iterable of arguments.
660 The error is a formatter string and an optional iterable of arguments.
661 """
661 """
662
662
663 def __init__(self, message, args=None):
663 def __init__(self, message, args=None):
664 # type: (bytes, Optional[Sequence[bytes]]) -> None
664 # type: (bytes, Optional[Sequence[bytes]]) -> None
665 self.message = message
665 self.message = message
666 self.messageargs = args
666 self.messageargs = args
General Comments 0
You need to be logged in to leave comments. Login now