diff --git a/mercurial/hook.py b/mercurial/hook.py --- a/mercurial/hook.py +++ b/mercurial/hook.py @@ -37,10 +37,18 @@ def _pythonhook(ui, repo, name, hname, f try: obj = __import__(modname) except ImportError: + e1 = sys.exc_type, sys.exc_value, sys.exc_traceback try: # extensions are loaded with hgext_ prefix obj = __import__("hgext_%s" % modname) except ImportError: + e2 = sys.exc_type, sys.exc_value, sys.exc_traceback + if ui.tracebackflag: + ui.warn(_('exception from first failed import attempt:\n')) + ui.traceback(e1) + if ui.tracebackflag: + ui.warn(_('exception from second failed import attempt:\n')) + ui.traceback(e2) raise util.Abort(_('%s hook is invalid ' '(import of "%s" failed)') % (hname, modname)) diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -15,7 +15,7 @@ import config, util, error class ui(object): def __init__(self, src=None): self._buffers = [] - self.quiet = self.verbose = self.debugflag = self._traceback = False + self.quiet = self.verbose = self.debugflag = self.tracebackflag = False self._reportuntrusted = True self._ocfg = config.config() # overlay self._tcfg = config.config() # trusted @@ -101,7 +101,7 @@ class ui(object): if self.verbose and self.quiet: self.quiet = self.verbose = False self._reportuntrusted = self.configbool("ui", "report_untrusted", True) - self._traceback = self.configbool('ui', 'traceback', False) + self.tracebackflag = self.configbool('ui', 'traceback', False) # update trust information self._trustusers.update(self.configlist('trusted', 'users')) @@ -337,13 +337,16 @@ class ui(object): return t - def traceback(self): + def traceback(self, exc=None): '''print exception traceback if traceback printing enabled. only to call in exception handler. returns true if traceback printed.''' - if self._traceback: - traceback.print_exc() - return self._traceback + if self.tracebackflag: + if exc: + traceback.print_exception(exc[0], exc[1], exc[2]) + else: + traceback.print_exc() + return self.tracebackflag def geteditor(self): '''return editor to use''' diff --git a/tests/test-hook b/tests/test-hook --- a/tests/test-hook +++ b/tests/test-hook @@ -248,4 +248,18 @@ echo "pre-commit.test = python:`pwd`/tes cd ../repo hg commit +cd ../../b +echo '# make sure --traceback works on hook import failure' +cat > importfail.py < .hg/hgrc +echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc + +echo a >> a +hg --traceback commit -Ama 2>&1 | grep '^\(exception\|Traceback\|ImportError\)' + exit 0 diff --git a/tests/test-hook.out b/tests/test-hook.out --- a/tests/test-hook.out +++ b/tests/test-hook.out @@ -163,3 +163,11 @@ hooks.commit.auto= # test python hook configured with python:[file]:[hook] syntax hook works nothing changed +# make sure --traceback works on hook import failure +exception from first failed import attempt: +Traceback (most recent call last): +ImportError: No module named somebogusmodule +exception from second failed import attempt: +Traceback (most recent call last): +ImportError: No module named hgext_importfail +Traceback (most recent call last):