error.py
457 lines
| 11.7 KiB
| text/x-python
|
PythonLexer
/ mercurial / error.py
|
r8226 | # error.py - Mercurial exceptions | ||
# | ||||
# Copyright 2005-2008 Matt Mackall <mpm@selenic.com> | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
|
r10263 | # GNU General Public License version 2 or any later version. | ||
|
r7633 | |||
|
r8227 | """Mercurial exceptions. | ||
This allows us to catch exceptions at higher levels without forcing | ||||
imports. | ||||
""" | ||||
|
r25945 | from __future__ import absolute_import | ||
|
r32616 | # Do not import anything but pycompat here, please | ||
from . import pycompat | ||||
|
r43346 | |||
|
r32616 | def _tobytes(exc): | ||
"""Byte-stringify exception in the same way as BaseException_str()""" | ||||
if not exc.args: | ||||
return b'' | ||||
if len(exc.args) == 1: | ||||
return pycompat.bytestr(exc.args[0]) | ||||
return b'(%s)' % b', '.join(b"'%s'" % pycompat.bytestr(a) for a in exc.args) | ||||
|
r7633 | |||
|
r43346 | |||
|
r29509 | class Hint(object): | ||
"""Mix-in to provide a hint of an error | ||||
|
r29510 | This should come first in the inheritance list to consume a hint and | ||
pass remaining arguments to the exception class. | ||||
|
r29509 | """ | ||
|
r43346 | |||
|
r25248 | def __init__(self, *args, **kw): | ||
|
r43906 | self.hint = kw.pop('hint', None) | ||
|
r29510 | super(Hint, self).__init__(*args, **kw) | ||
|
r25248 | |||
|
r43346 | |||
|
r39812 | class StorageError(Hint, Exception): | ||
"""Raised when an error occurs in a storage layer. | ||||
Usually subclassed by a storage-specific exception. | ||||
""" | ||||
|
r43346 | |||
|
r39812 | __bytes__ = _tobytes | ||
|
r43346 | |||
|
r39812 | class RevlogError(StorageError): | ||
|
r32616 | __bytes__ = _tobytes | ||
|
r7633 | |||
|
r43346 | |||
r43302 | class SidedataHashError(RevlogError): | |||
def __init__(self, key, expected, got): | ||||
self.sidedatakey = key | ||||
self.expecteddigest = expected | ||||
self.actualdigest = got | ||||
|
r43346 | |||
|
r23014 | class FilteredIndexError(IndexError): | ||
|
r32616 | __bytes__ = _tobytes | ||
|
r23014 | |||
|
r43346 | |||
|
r7633 | class LookupError(RevlogError, KeyError): | ||
def __init__(self, name, index, message): | ||||
self.name = name | ||||
|
r24038 | self.index = index | ||
|
r24137 | # this can't be called 'message' because at least some installs of | ||
# Python 2.6+ complain about the 'message' property being deprecated | ||||
self.lookupmessage = message | ||||
|
r36559 | if isinstance(name, bytes) and len(name) == 20: | ||
|
r25945 | from .node import short | ||
|
r43346 | |||
|
r7633 | name = short(name) | ||
|
r46075 | # if name is a binary node, it can be None | ||
RevlogError.__init__( | ||||
self, b'%s@%s: %s' % (index, pycompat.bytestr(name), message) | ||||
) | ||||
|
r7633 | |||
|
r32616 | def __bytes__(self): | ||
return RevlogError.__bytes__(self) | ||||
|
r7633 | def __str__(self): | ||
return RevlogError.__str__(self) | ||||
|
r7636 | |||
|
r43346 | |||
|
r38877 | class AmbiguousPrefixLookupError(LookupError): | ||
pass | ||||
|
r43346 | |||
|
r23015 | class FilteredLookupError(LookupError): | ||
pass | ||||
|
r43346 | |||
|
r18855 | class ManifestLookupError(LookupError): | ||
pass | ||||
|
r43346 | |||
|
r11287 | class CommandError(Exception): | ||
|
r7636 | """Exception raised on errors in parsing the command line.""" | ||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r7637 | |||
|
r43346 | |||
|
r29509 | class InterventionRequired(Hint, Exception): | ||
|
r18931 | """Exception raised when a command requires human intervention.""" | ||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r18931 | |||
|
r43346 | |||
|
r45711 | class ConflictResolutionRequired(InterventionRequired): | ||
"""Exception raised when a continuable command required merge conflict resolution.""" | ||||
def __init__(self, opname): | ||||
from .i18n import _ | ||||
self.opname = opname | ||||
InterventionRequired.__init__( | ||||
self, | ||||
_( | ||||
b"unresolved conflicts (see 'hg resolve', then 'hg %s --continue')" | ||||
) | ||||
% opname, | ||||
) | ||||
|
r29509 | class Abort(Hint, Exception): | ||
|
r11288 | """Raised if a command needs to print an error and exit.""" | ||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r11288 | |||
|
r43735 | if pycompat.ispy3: | ||
def __str__(self): | ||||
|
r43736 | # the output would be unreadable if the message was translated, | ||
# but do not replace it with encoding.strfromlocal(), which | ||||
# may raise another exception. | ||||
|
r43735 | return pycompat.sysstr(self.__bytes__()) | ||
|
r43720 | |||
|
r43346 | |||
|
r26692 | class HookLoadError(Abort): | ||
"""raised when loading a hook fails, aborting an operation | ||||
Exists to allow more specialized catching.""" | ||||
|
r43346 | |||
|
r23415 | class HookAbort(Abort): | ||
"""raised when a validation hook fails, aborting an operation | ||||
Exists to allow more specialized catching.""" | ||||
|
r43346 | |||
|
r11288 | class ConfigError(Abort): | ||
|
r22359 | """Exception raised when parsing config files""" | ||
|
r8144 | |||
|
r43346 | |||
|
r26683 | class UpdateAbort(Abort): | ||
"""Raised when an update is aborted for destination issue""" | ||||
|
r43346 | |||
|
r28141 | class MergeDestAbort(Abort): | ||
"""Raised when an update is aborted for destination issues""" | ||||
|
r43346 | |||
|
r28141 | class NoMergeDestAbort(MergeDestAbort): | ||
"""Raised when an update is aborted because there is nothing to merge""" | ||||
|
r43346 | |||
|
r28141 | class ManyMergeDestAbort(MergeDestAbort): | ||
|
r30332 | """Raised when an update is aborted because destination is ambiguous""" | ||
|
r28141 | |||
|
r43346 | |||
|
r26896 | class ResponseExpected(Abort): | ||
"""Raised when an EOF is received for a prompt""" | ||||
|
r43346 | |||
|
r26896 | def __init__(self): | ||
from .i18n import _ | ||||
|
r43346 | |||
|
r43347 | Abort.__init__(self, _(b'response expected')) | ||
|
r26896 | |||
|
r43346 | |||
|
r29509 | class OutOfBandError(Hint, Exception): | ||
|
r22359 | """Exception raised when a remote repo reports failure""" | ||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r15017 | |||
|
r43346 | |||
|
r29509 | class ParseError(Hint, Exception): | ||
|
r24040 | """Raised when parsing config files and {rev,file}sets (msg[, pos])""" | ||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r11288 | |||
|
r43346 | |||
|
r34252 | class PatchError(Exception): | ||
__bytes__ = _tobytes | ||||
|
r43346 | |||
|
r24217 | class UnknownIdentifier(ParseError): | ||
"""Exception raised when a {rev,file}set references an unknown identifier""" | ||||
def __init__(self, function, symbols): | ||||
|
r25945 | from .i18n import _ | ||
|
r43346 | |||
|
r43347 | ParseError.__init__(self, _(b"unknown identifier: %s") % function) | ||
|
r24217 | self.function = function | ||
self.symbols = symbols | ||||
|
r43346 | |||
|
r29509 | class RepoError(Hint, Exception): | ||
|
r32616 | __bytes__ = _tobytes | ||
|
r7637 | |||
|
r43346 | |||
|
r9423 | class RepoLookupError(RepoError): | ||
pass | ||||
|
r43346 | |||
|
r23016 | class FilteredRepoLookupError(RepoLookupError): | ||
pass | ||||
|
r43346 | |||
|
r7637 | class CapabilityError(RepoError): | ||
pass | ||||
|
r7640 | |||
|
r43346 | |||
|
r13447 | class RequirementError(RepoError): | ||
"""Exception raised if .hg/requires has an unknown entry.""" | ||||
|
r43346 | |||
|
r31959 | class StdioError(IOError): | ||
"""Raised if I/O to stdout or stderr fails""" | ||||
def __init__(self, err): | ||||
IOError.__init__(self, err.errno, err.strerror) | ||||
|
r32616 | # no __bytes__() because error message is derived from the standard IOError | ||
|
r43346 | |||
|
r26985 | class UnsupportedMergeRecords(Abort): | ||
def __init__(self, recordtypes): | ||||
from .i18n import _ | ||||
|
r43346 | |||
|
r26985 | self.recordtypes = sorted(recordtypes) | ||
|
r43347 | s = b' '.join(self.recordtypes) | ||
|
r26985 | Abort.__init__( | ||
|
r43346 | self, | ||
|
r43347 | _(b'unsupported merge state records: %s') % s, | ||
|
r43346 | hint=_( | ||
|
r43347 | b'see https://mercurial-scm.org/wiki/MergeStateRecords for ' | ||
b'more information' | ||||
|
r43346 | ), | ||
) | ||||
|
r26985 | |||
r32591 | class UnknownVersion(Abort): | |||
"""generic exception for aborting from an encounter with an unknown version | ||||
""" | ||||
def __init__(self, msg, hint=None, version=None): | ||||
self.version = version | ||||
super(UnknownVersion, self).__init__(msg, hint=hint) | ||||
|
r43346 | |||
|
r7640 | class LockError(IOError): | ||
def __init__(self, errno, strerror, filename, desc): | ||||
IOError.__init__(self, errno, strerror, filename) | ||||
self.desc = desc | ||||
|
r32616 | # no __bytes__() because error message is derived from the standard IOError | ||
|
r43346 | |||
|
r7640 | class LockHeld(LockError): | ||
def __init__(self, errno, filename, desc, locker): | ||||
|
r43347 | LockError.__init__(self, errno, b'Lock held', filename, desc) | ||
|
r7640 | self.locker = locker | ||
|
r43346 | |||
|
r7640 | class LockUnavailable(LockError): | ||
pass | ||||
|
r7641 | |||
|
r43346 | |||
|
r26355 | # LockError is for errors while acquiring the lock -- this is unrelated | ||
|
r26438 | class LockInheritanceContractViolation(RuntimeError): | ||
|
r32616 | __bytes__ = _tobytes | ||
|
r26355 | |||
|
r43346 | |||
|
r7641 | class ResponseError(Exception): | ||
"""Raised to print an error with part of output and exit.""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r7641 | |||
|
r43346 | |||
|
r7643 | class UnknownCommand(Exception): | ||
"""Exception raised if command is not in the command table.""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r7643 | |||
|
r43346 | |||
|
r7643 | class AmbiguousCommand(Exception): | ||
"""Exception raised if command shortcut matches more than one command.""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r7643 | |||
|
r43346 | |||
|
r7644 | # derived from KeyboardInterrupt to simplify some breakout code | ||
class SignalInterrupt(KeyboardInterrupt): | ||||
"""Exception raised on SIGTERM and SIGHUP.""" | ||||
|
r7646 | |||
|
r43346 | |||
|
r7646 | class SignatureError(Exception): | ||
|
r32616 | __bytes__ = _tobytes | ||
|
r21184 | |||
|
r43346 | |||
|
r21184 | class PushRaced(RuntimeError): | ||
"""An exception raised during unbundling that indicate a push race""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r21184 | |||
|
r43346 | |||
|
r32340 | class ProgrammingError(Hint, RuntimeError): | ||
|
r30585 | """Raised if a mercurial (core or extension) developer made a mistake""" | ||
|
r39615 | |||
def __init__(self, msg, *args, **kwargs): | ||||
|
r39632 | # On Python 3, turn the message back into a string since this is | ||
# an internal-only error that won't be printed except in a | ||||
# stack traces. | ||||
msg = pycompat.sysstr(msg) | ||||
|
r39615 | super(ProgrammingError, self).__init__(msg, *args, **kwargs) | ||
|
r32616 | __bytes__ = _tobytes | ||
|
r30573 | |||
|
r43346 | |||
|
r32401 | class WdirUnsupported(Exception): | ||
"""An exception which is raised when 'wdir()' is not supported""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r32401 | |||
|
r43346 | |||
|
r21618 | # bundle2 related errors | ||
class BundleValueError(ValueError): | ||||
|
r21621 | """error raised when bundle2 cannot be processed""" | ||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r21620 | |||
|
r43346 | |||
|
r26393 | class BundleUnknownFeatureError(BundleValueError): | ||
|
r26394 | def __init__(self, parttype=None, params=(), values=()): | ||
|
r21620 | self.parttype = parttype | ||
|
r21621 | self.params = params | ||
|
r26394 | self.values = values | ||
|
r21627 | if self.parttype is None: | ||
|
r43347 | msg = b'Stream Parameter' | ||
|
r21627 | else: | ||
msg = parttype | ||||
|
r26394 | entries = self.params | ||
if self.params and self.values: | ||||
assert len(self.params) == len(self.values) | ||||
entries = [] | ||||
for idx, par in enumerate(self.params): | ||||
val = self.values[idx] | ||||
if val is None: | ||||
entries.append(val) | ||||
else: | ||||
|
r43347 | entries.append(b"%s=%r" % (par, pycompat.maybebytestr(val))) | ||
|
r26394 | if entries: | ||
|
r43347 | msg = b'%s - %s' % (msg, b', '.join(entries)) | ||
|
r21747 | ValueError.__init__(self, msg) | ||
|
r21618 | |||
|
r43346 | |||
|
r21618 | class ReadOnlyPartError(RuntimeError): | ||
"""error raised when code tries to alter a part being generated""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r21618 | |||
|
r43346 | |||
|
r25484 | class PushkeyFailed(Abort): | ||
"""error raised when a pushkey part failed to update a value""" | ||||
|
r43346 | def __init__( | ||
self, partid, namespace=None, key=None, new=None, old=None, ret=None | ||||
): | ||||
|
r25484 | self.partid = partid | ||
self.namespace = namespace | ||||
self.key = key | ||||
self.new = new | ||||
self.old = old | ||||
self.ret = ret | ||||
# no i18n expected to be processed into a better message | ||||
|
r43346 | Abort.__init__( | ||
|
r43347 | self, b'failed to update value for "%s/%s"' % (namespace, key) | ||
|
r43346 | ) | ||
|
r25484 | |||
|
r39813 | class CensoredNodeError(StorageError): | ||
|
r24190 | """error raised when content verification fails on a censored node | ||
|
r22595 | |||
|
r24190 | Also contains the tombstone data substituted for the uncensored data. | ||
""" | ||||
def __init__(self, filename, node, tombstone): | ||||
|
r25945 | from .node import short | ||
|
r43346 | |||
|
r43347 | StorageError.__init__(self, b'%s:%s' % (filename, short(node))) | ||
|
r24190 | self.tombstone = tombstone | ||
|
r24120 | |||
|
r43346 | |||
|
r39813 | class CensoredBaseError(StorageError): | ||
|
r24120 | """error raised when a delta is rejected because its base is censored | ||
A delta based on a censored revision must be formed as single patch | ||||
operation which replaces the entire base with new content. This ensures | ||||
the delta may be applied by clones which have not censored the base. | ||||
""" | ||||
|
r26640 | |||
|
r43346 | |||
|
r26640 | class InvalidBundleSpecification(Exception): | ||
"""error raised when a bundle specification is invalid. | ||||
This is used for syntax errors as opposed to support errors. | ||||
""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r26640 | |||
|
r43346 | |||
|
r26640 | class UnsupportedBundleSpecification(Exception): | ||
"""error raised when a bundle specification is not supported.""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r29536 | |||
|
r43346 | |||
|
r29536 | class CorruptedState(Exception): | ||
"""error raised when a command is not able to read its state from file""" | ||||
|
r43346 | |||
|
r32616 | __bytes__ = _tobytes | ||
|
r32002 | |||
|
r43346 | |||
|
r32023 | class PeerTransportError(Abort): | ||
"""Transport-level I/O error when communicating with a peer repo.""" | ||||
|
r35104 | |||
|
r43346 | |||
|
r35104 | class InMemoryMergeConflictsError(Exception): | ||
"""Exception raised when merge conflicts arose during an in-memory merge.""" | ||||
|
r43346 | |||
|
r35104 | __bytes__ = _tobytes | ||
|
r39595 | |||
|
r43346 | |||
|
r39595 | class WireprotoCommandError(Exception): | ||
"""Represents an error during execution of a wire protocol command. | ||||
Should only be thrown by wire protocol version 2 commands. | ||||
The error is a formatter string and an optional iterable of arguments. | ||||
""" | ||||
|
r43346 | |||
|
r39595 | def __init__(self, message, args=None): | ||
self.message = message | ||||
self.messageargs = args | ||||