Comments
Patch
@@ -59,6 +59,23 @@ class request(object):
self.fout = fout
self.ferr = ferr
+ def _runexithandlers(self):
+ exc = None
+ handlers = self.ui._exithandlers
+ try:
+ while handlers:
+ func, args, kwargs = handlers.pop()
+ try:
+ func(*args, **kwargs)
+ except: # re-raises below
+ if exc is None:
+ exc = sys.exc_info()[1]
+ self.ui.warn(('error in exit handlers:\n'))
+ self.ui.traceback(force=True)
+ finally:
+ if exc is not None:
+ raise exc
+
def run():
"run the command in sys.argv"
sys.exit((dispatch(request(pycompat.sysargv[1:])) or 0) & 255)
@@ -146,6 +163,10 @@ def dispatch(req):
req.ui.log('uiblocked', 'ui blocked ms', **req.ui._blockedtimes)
req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
msg, ret or 0, duration)
+ try:
+ req._runexithandlers()
+ except: # exiting, so no re-raises
+ ret = ret or -1
return ret
def _runcatch(req):
@@ -139,6 +139,8 @@ class ui(object):
"""
# _buffers: used for temporary capture of output
self._buffers = []
+ # _exithandlers: callbacks run at the end of a request
+ self._exithandlers = []
# 3-tuple describing how each buffer in the stack behaves.
# Values are (capture stderr, capture subprocesses, apply labels).
self._bufferstates = []
@@ -163,6 +165,7 @@ class ui(object):
self._styles = {}
if src:
+ self._exithandlers = src._exithandlers
self.fout = src.fout
self.ferr = src.ferr
self.fin = src.fin
@@ -940,6 +943,13 @@ class ui(object):
return True
+ def atexit(self, func, *args, **kwargs):
+ '''register a function to run after dispatching a request
+
+ Handlers do not stay registered across request boundaries.'''
+ self._exithandlers.append((func, args, kwargs))
+ return func
+
def interface(self, feature):
"""what interface to use for interactive console features?