Patchwork D10735: errors: let each Abort subclass define its error code

login
register
mail settings
Submitter phabricator
Date May 19, 2021, 12:30 a.m.
Message ID <differential-rev-PHID-DREV-iopoxgmfizjsbrezb45k-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49055/
State Superseded
Headers show

Comments

phabricator - May 19, 2021, 12:30 a.m.
martinvonz created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  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()`.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10735

AFFECTED FILES
  mercurial/chgserver.py
  mercurial/error.py
  mercurial/scmutil.py

CHANGE DETAILS




To: martinvonz, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -212,20 +212,8 @@ 
     except error.WdirUnsupported:
         ui.error(_(b"abort: working directory revision cannot be specified\n"))
     except error.Abort as inst:
-        if isinstance(inst, (error.InputError, error.ParseError)):
-            detailed_exit_code = 10
-        elif isinstance(inst, error.StateError):
-            detailed_exit_code = 20
-        elif isinstance(inst, error.ConfigError):
-            detailed_exit_code = 30
-        elif isinstance(inst, error.HookAbort):
-            detailed_exit_code = 40
-        elif isinstance(inst, error.RemoteError):
-            detailed_exit_code = 100
-        elif isinstance(inst, error.SecurityError):
-            detailed_exit_code = 150
-        elif isinstance(inst, error.CanceledError):
-            detailed_exit_code = 250
+        if inst.detailed_exit_code is not None:
+            detailed_exit_code = inst.detailed_exit_code
         ui.error(inst.format())
     except error.WorkerError as inst:
         # Don't print a message -- the worker already should have
diff --git a/mercurial/error.py b/mercurial/error.py
--- a/mercurial/error.py
+++ b/mercurial/error.py
@@ -185,10 +185,11 @@ 
 class Abort(Hint, Exception):
     """Raised if a command needs to print an error and exit."""
 
-    def __init__(self, message, hint=None):
+    def __init__(self, message, hint=None, detailed_exit_code=None):
         # type: (bytes, Optional[bytes]) -> None
         self.message = message
         self.hint = hint
+        self.detailed_exit_code = detailed_exit_code
         # Pass the message into the Exception constructor to help extensions
         # that look for exc.args[0].
         Exception.__init__(self, message)
@@ -220,6 +221,11 @@ 
     Examples: Invalid command, invalid flags, invalid revision.
     """
 
+    def __init__(self, message, hint=None):
+        super(InputError, self).__init__(
+            message, hint=hint, detailed_exit_code=10
+        )
+
 
 class StateError(Abort):
     """Indicates that the operation might work if retried in a different state.
@@ -227,6 +233,11 @@ 
     Examples: Unresolved merge conflicts, unfinished operations.
     """
 
+    def __init__(self, message, hint=None):
+        super(StateError, self).__init__(
+            message, hint=hint, detailed_exit_code=20
+        )
+
 
 class CanceledError(Abort):
     """Indicates that the user canceled the operation.
@@ -234,6 +245,11 @@ 
     Examples: Close commit editor with error status, quit chistedit.
     """
 
+    def __init__(self, message, hint=None):
+        super(CanceledError, self).__init__(
+            message, hint=hint, detailed_exit_code=250
+        )
+
 
 class SecurityError(Abort):
     """Indicates that some aspect of security failed.
@@ -242,6 +258,11 @@ 
     filesystem, mismatched GPG signature, DoS protection.
     """
 
+    def __init__(self, message, hint=None):
+        super(SecurityError, self).__init__(
+            message, hint=hint, detailed_exit_code=150
+        )
+
 
 class HookLoadError(Abort):
     """raised when loading a hook fails, aborting an operation
@@ -254,13 +275,20 @@ 
 
     Exists to allow more specialized catching."""
 
+    def __init__(self, message, hint=None):
+        super(HookAbort, self).__init__(
+            message, hint=hint, detailed_exit_code=40
+        )
+
 
 class ConfigError(Abort):
     """Exception raised when parsing config files"""
 
     def __init__(self, message, location=None, hint=None):
         # type: (bytes, Optional[bytes], Optional[bytes]) -> None
-        super(ConfigError, self).__init__(message, hint=hint)
+        super(ConfigError, self).__init__(
+            message, hint=hint, detailed_exit_code=30
+        )
         self.location = location
 
     def format(self):
@@ -307,6 +335,11 @@ 
 class RemoteError(Abort):
     """Exception raised when interacting with a remote repo fails"""
 
+    def __init__(self, message, hint=None):
+        super(RemoteError, self).__init__(
+            message, hint=hint, detailed_exit_code=100
+        )
+
 
 class OutOfBandError(RemoteError):
     """Exception raised when a remote repo reports failure"""
@@ -327,7 +360,9 @@ 
 
     def __init__(self, message, location=None, hint=None):
         # type: (bytes, Optional[Union[bytes, int]], Optional[bytes]) -> None
-        super(ParseError, self).__init__(message, hint=hint)
+        super(ParseError, self).__init__(
+            message, hint=hint, detailed_exit_code=10
+        )
         self.location = location
 
     def format(self):
diff --git a/mercurial/chgserver.py b/mercurial/chgserver.py
--- a/mercurial/chgserver.py
+++ b/mercurial/chgserver.py
@@ -516,10 +516,8 @@ 
                 self.ui.error(_(b"(%s)\n") % inst.hint)
             errorraised = True
         except error.Abort as inst:
-            if isinstance(inst, error.InputError):
-                detailed_exit_code = 10
-            elif isinstance(inst, error.ConfigError):
-                detailed_exit_code = 30
+            if inst.detailed_exit_code is not None:
+                detailed_exit_code = inst.detailed_exit_code
             self.ui.error(inst.format())
             errorraised = True