errors.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # errors.py -- errors for dulwich
  2. # Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
  3. # Copyright (C) 2009-2012 Jelmer Vernooij <jelmer@jelmer.uk>
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  6. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  7. # General Public License as published by the Free Software Foundation; version 2.0
  8. # or (at your option) any later version. You can redistribute it and/or
  9. # modify it under the terms of either of these two licenses.
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. # You should have received a copy of the licenses; if not, see
  18. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  19. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  20. # License, Version 2.0.
  21. #
  22. """Dulwich-related exception classes and utility functions."""
  23. # Please do not add more errors here, but instead add them close to the code
  24. # that raises the error.
  25. import binascii
  26. from collections.abc import Sequence
  27. from typing import Optional, Union
  28. class ChecksumMismatch(Exception):
  29. """A checksum didn't match the expected contents."""
  30. def __init__(
  31. self,
  32. expected: Union[bytes, str],
  33. got: Union[bytes, str],
  34. extra: Optional[str] = None,
  35. ) -> None:
  36. """Initialize a ChecksumMismatch exception.
  37. Args:
  38. expected: The expected checksum value (bytes or hex string).
  39. got: The actual checksum value (bytes or hex string).
  40. extra: Optional additional error information.
  41. """
  42. if isinstance(expected, bytes) and len(expected) == 20:
  43. expected_str = binascii.hexlify(expected).decode("ascii")
  44. else:
  45. expected_str = (
  46. expected if isinstance(expected, str) else expected.decode("ascii")
  47. )
  48. if isinstance(got, bytes) and len(got) == 20:
  49. got_str = binascii.hexlify(got).decode("ascii")
  50. else:
  51. got_str = got if isinstance(got, str) else got.decode("ascii")
  52. self.expected = expected_str
  53. self.got = got_str
  54. self.extra = extra
  55. message = f"Checksum mismatch: Expected {expected_str}, got {got_str}"
  56. if self.extra is not None:
  57. message += f"; {extra}"
  58. Exception.__init__(self, message)
  59. class WrongObjectException(Exception):
  60. """Baseclass for all the _ is not a _ exceptions on objects.
  61. Do not instantiate directly.
  62. Subclasses should define a type_name attribute that indicates what
  63. was expected if they were raised.
  64. """
  65. type_name: str
  66. def __init__(self, sha: bytes, *args: object, **kwargs: object) -> None:
  67. """Initialize a WrongObjectException.
  68. Args:
  69. sha: The SHA of the object that was not of the expected type.
  70. *args: Additional positional arguments.
  71. **kwargs: Additional keyword arguments.
  72. """
  73. Exception.__init__(self, f"{sha.decode('ascii')} is not a {self.type_name}")
  74. class NotCommitError(WrongObjectException):
  75. """Indicates that the sha requested does not point to a commit."""
  76. type_name = "commit"
  77. class NotTreeError(WrongObjectException):
  78. """Indicates that the sha requested does not point to a tree."""
  79. type_name = "tree"
  80. class NotTagError(WrongObjectException):
  81. """Indicates that the sha requested does not point to a tag."""
  82. type_name = "tag"
  83. class NotBlobError(WrongObjectException):
  84. """Indicates that the sha requested does not point to a blob."""
  85. type_name = "blob"
  86. class MissingCommitError(Exception):
  87. """Indicates that a commit was not found in the repository."""
  88. def __init__(self, sha: bytes, *args: object, **kwargs: object) -> None:
  89. """Initialize a MissingCommitError.
  90. Args:
  91. sha: The SHA of the missing commit.
  92. *args: Additional positional arguments.
  93. **kwargs: Additional keyword arguments.
  94. """
  95. self.sha = sha
  96. Exception.__init__(self, f"{sha.decode('ascii')} is not in the revision store")
  97. class ObjectMissing(Exception):
  98. """Indicates that a requested object is missing."""
  99. def __init__(self, sha: bytes, *args: object, **kwargs: object) -> None:
  100. """Initialize an ObjectMissing exception.
  101. Args:
  102. sha: The SHA of the missing object.
  103. *args: Additional positional arguments.
  104. **kwargs: Additional keyword arguments.
  105. """
  106. Exception.__init__(self, f"{sha.decode('ascii')} is not in the pack")
  107. class ApplyDeltaError(Exception):
  108. """Indicates that applying a delta failed."""
  109. def __init__(self, *args: object, **kwargs: object) -> None:
  110. """Initialize an ApplyDeltaError.
  111. Args:
  112. *args: Error message and additional positional arguments.
  113. **kwargs: Additional keyword arguments.
  114. """
  115. Exception.__init__(self, *args, **kwargs)
  116. class NotGitRepository(Exception):
  117. """Indicates that no Git repository was found."""
  118. def __init__(self, *args: object, **kwargs: object) -> None:
  119. """Initialize a NotGitRepository exception.
  120. Args:
  121. *args: Error message and additional positional arguments.
  122. **kwargs: Additional keyword arguments.
  123. """
  124. Exception.__init__(self, *args, **kwargs)
  125. class GitProtocolError(Exception):
  126. """Git protocol exception."""
  127. def __init__(self, *args: object, **kwargs: object) -> None:
  128. """Initialize a GitProtocolError.
  129. Args:
  130. *args: Error message and additional positional arguments.
  131. **kwargs: Additional keyword arguments.
  132. """
  133. Exception.__init__(self, *args, **kwargs)
  134. def __eq__(self, other: object) -> bool:
  135. """Check equality between GitProtocolError instances.
  136. Args:
  137. other: The object to compare with.
  138. Returns:
  139. True if both are GitProtocolError instances with same args, False otherwise.
  140. """
  141. return isinstance(other, GitProtocolError) and self.args == other.args
  142. class SendPackError(GitProtocolError):
  143. """An error occurred during send_pack."""
  144. class HangupException(GitProtocolError):
  145. """Hangup exception."""
  146. def __init__(self, stderr_lines: Optional[Sequence[bytes]] = None) -> None:
  147. """Initialize a HangupException.
  148. Args:
  149. stderr_lines: Optional list of stderr output lines from the remote server.
  150. """
  151. if stderr_lines:
  152. super().__init__(
  153. "\n".join(
  154. line.decode("utf-8", "surrogateescape") for line in stderr_lines
  155. )
  156. )
  157. else:
  158. super().__init__("The remote server unexpectedly closed the connection.")
  159. self.stderr_lines = stderr_lines
  160. def __eq__(self, other: object) -> bool:
  161. """Check equality between HangupException instances.
  162. Args:
  163. other: The object to compare with.
  164. Returns:
  165. True if both are HangupException instances with same stderr_lines, False otherwise.
  166. """
  167. return (
  168. isinstance(other, HangupException)
  169. and self.stderr_lines == other.stderr_lines
  170. )
  171. class UnexpectedCommandError(GitProtocolError):
  172. """Unexpected command received in a proto line."""
  173. def __init__(self, command: Optional[str]) -> None:
  174. """Initialize an UnexpectedCommandError.
  175. Args:
  176. command: The unexpected command received, or None for flush-pkt.
  177. """
  178. command_str = "flush-pkt" if command is None else f"command {command}"
  179. super().__init__(f"Protocol got unexpected {command_str}")
  180. class FileFormatException(Exception):
  181. """Base class for exceptions relating to reading git file formats."""
  182. class PackedRefsException(FileFormatException):
  183. """Indicates an error parsing a packed-refs file."""
  184. class ObjectFormatException(FileFormatException):
  185. """Indicates an error parsing an object."""
  186. class NoIndexPresent(Exception):
  187. """No index is present."""
  188. class CommitError(Exception):
  189. """An error occurred while performing a commit."""
  190. class RefFormatError(Exception):
  191. """Indicates an invalid ref name."""
  192. class HookError(Exception):
  193. """An error occurred while executing a hook."""
  194. class WorkingTreeModifiedError(Exception):
  195. """Indicates that the working tree has modifications that would be overwritten."""