worker: raise exception instead of calling sys.exit() with child's code
When a worker process returns an error code, we would call
`sys.exit()` with that exit code on the main process. The `SystemExit`
exception would then get caught in `scmutil.callcatch()`, which would
return that error code. The comment there says "Commands shouldn't
sys.exit directly", which I agree with. This patch changes it so we
raise a specific exception when a worker fails so we can catch
instead. I think that means that `SystemExit` is now always an
internal error.
(I had earlier thought that this call to `sys.exit()` was from within
the child process until Matt Harbison made me look again, so thanks
for that!)
Differential Revision: https://phab.mercurial-scm.org/D9287
--- a/mercurial/error.py Tue Nov 03 09:56:02 2020 -0800
+++ b/mercurial/error.py Sat Nov 07 21:50:28 2020 -0800
@@ -130,6 +130,13 @@
__bytes__ = _tobytes
+class WorkerError(Exception):
+ """Exception raised when a worker process dies."""
+
+ def __init__(self, status_code):
+ self.status_code = status_code
+
+
class InterventionRequired(Hint, Exception):
"""Exception raised when a command requires human intervention."""
--- a/mercurial/scmutil.py Tue Nov 03 09:56:02 2020 -0800
+++ b/mercurial/scmutil.py Sat Nov 07 21:50:28 2020 -0800
@@ -219,6 +219,9 @@
ui.error(_(b"abort: %s\n") % inst.message)
if inst.hint:
ui.error(_(b"(%s)\n") % inst.hint)
+ except error.WorkerError as inst:
+ # Don't print a message -- the worker already should have
+ return inst.status_code
except ImportError as inst:
ui.error(_(b"abort: %s!\n") % stringutil.forcebytestr(inst))
m = stringutil.forcebytestr(inst).split()[-1]
--- a/mercurial/worker.py Tue Nov 03 09:56:02 2020 -0800
+++ b/mercurial/worker.py Sat Nov 07 21:50:28 2020 -0800
@@ -300,7 +300,7 @@
if status:
if status < 0:
os.kill(os.getpid(), -status)
- sys.exit(status)
+ raise error.WorkerError(status)
if hasretval:
yield True, retval
--- a/tests/test-worker.t Tue Nov 03 09:56:02 2020 -0800
+++ b/tests/test-worker.t Sat Nov 07 21:50:28 2020 -0800
@@ -85,11 +85,12 @@
[255]
$ hg --config "extensions.t=$abspath" --config 'worker.numcpus=8' \
- > test 100000.0 abort --traceback 2>&1 | egrep '(SystemExit|Abort)'
+ > test 100000.0 abort --traceback 2>&1 | egrep '(WorkerError|Abort)'
raise error.Abort(b'known exception')
mercurial.error.Abort: known exception (py3 !)
Abort: known exception (no-py3 !)
- SystemExit: 255
+ raise error.WorkerError(status)
+ mercurial.error.WorkerError: 255
Traceback must be printed for unknown exceptions