diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py --- a/mercurial/dispatch.py +++ b/mercurial/dispatch.py @@ -88,6 +88,20 @@ err = None try: status = dispatch(req) or 0 + + # dispatch() should return an int or None. Python allows the + # value to sys.exit() to be special. We don't want to fall back to + # this handling, so we normalize to an int. + if not isinstance(status, int): + if util.safehasattr(req.ui, 'ferr'): + # If this raises, things are *really* messed up. We're + # OK with a possibly uncaught exception in this case + # because we're already in an exceptional code path. + req.ui.ferr.write('error: received non-integer status ' + 'code: %r\n' % status) + + status = -1 + except error.StdioError as e: err = e status = -1 diff --git a/tests/test-dispatch.t b/tests/test-dispatch.t --- a/tests/test-dispatch.t +++ b/tests/test-dispatch.t @@ -263,48 +263,28 @@ [42] $ hg exit returnstring 'some message' - Traceback (most recent call last): - File "*/hg", line *, in (glob) - dispatch.run() - File "*/mercurial/dispatch.py", line *, in run (glob) - sys.exit(status & 255) - TypeError: unsupported operand type(s) for &: 'str' and 'int' - [1] + error: received non-integer status code: 'some message' + [255] $ hg exit returnnone $ hg exit returnempty $ hg exit returndict - Traceback (most recent call last): - File "*/hg", line *, in (glob) - dispatch.run() - File "*/mercurial/dispatch.py", line *, in run (glob) - sys.exit(status & 255) - TypeError: unsupported operand type(s) for &: 'dict' and 'int' - [1] + error: received non-integer status code: {'key1': 'value1'} + [255] $ hg exit systemexitint 42 [42] $ hg exit systemexitstring 'failure message' - Traceback (most recent call last): - File "*/hg", line *, in (glob) - dispatch.run() - File "*/mercurial/dispatch.py", line *, in run (glob) - sys.exit(status & 255) - TypeError: unsupported operand type(s) for &: 'str' and 'int' - [1] + error: received non-integer status code: 'failure message' + [255] $ hg exit systemexitnoarg $ hg exit systemexitnone $ hg exit systemexitdict - Traceback (most recent call last): - File "*/hg", line *, in (glob) - dispatch.run() - File "*/mercurial/dispatch.py", line *, in run (glob) - sys.exit(status & 255) - TypeError: unsupported operand type(s) for &: 'dict' and 'int' - [1] + error: received non-integer status code: {'key1': 'value1'} + [255]