changeset 9851:9e7b2c49d25d

Make it possible to debug failed hook imports via use of --traceback Prior to this change, if a Python hook module failed to load (e.g. due to an import error or path problem), it was impossible to figure out why the error occurred, because the ImportErrors that got raised were caught but never displayed. If run with --traceback or ui.traceback=True, hg now prints tracebacks of both of the ImportError instances that get raised before it bails.
author Bryan O'Sullivan <bos@serpentine.com>
date Thu, 12 Nov 2009 14:05:52 -0800
parents 004bf1d6e6af
children a033929bd34e
files mercurial/hook.py mercurial/ui.py tests/test-hook tests/test-hook.out
diffstat 4 files changed, 39 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/hook.py	Thu Nov 12 14:34:07 2009 -0600
+++ b/mercurial/hook.py	Thu Nov 12 14:05:52 2009 -0800
@@ -37,10 +37,18 @@
         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))
--- a/mercurial/ui.py	Thu Nov 12 14:34:07 2009 -0600
+++ b/mercurial/ui.py	Thu Nov 12 14:05:52 2009 -0800
@@ -15,7 +15,7 @@
 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 @@
         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 @@
 
         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'''
--- a/tests/test-hook	Thu Nov 12 14:34:07 2009 -0600
+++ b/tests/test-hook	Thu Nov 12 14:05:52 2009 -0800
@@ -248,4 +248,18 @@
 cd ../repo
 hg commit
 
+cd ../../b
+echo '# make sure --traceback works on hook import failure'
+cat > importfail.py <<EOF
+import somebogusmodule
+# dereference something in the module to force demandimport to load it
+somebogusmodule.whatever
+EOF
+
+echo '[hooks]' > .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
--- a/tests/test-hook.out	Thu Nov 12 14:34:07 2009 -0600
+++ b/tests/test-hook.out	Thu Nov 12 14:05:52 2009 -0800
@@ -163,3 +163,11 @@
 # 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):