diff --git a/sphinx/__init__.py b/sphinx/__init__.py index e77470300..1496e24b5 100644 --- a/sphinx/__init__.py +++ b/sphinx/__init__.py @@ -12,11 +12,15 @@ import os import sys import getopt +import traceback from os import path from cStringIO import StringIO +from docutils.utils import SystemMessage + +from sphinx.util import format_exception_cut_frames, save_traceback from sphinx.application import Sphinx -from sphinx.util.console import nocolor +from sphinx.util.console import darkred, nocolor __revision__ = '$Revision$' __version__ = '0.1.' + __revision__[11:-2] @@ -27,8 +31,9 @@ def usage(argv, msg=None): print >>sys.stderr, msg print >>sys.stderr print >>sys.stderr, """\ -usage: %s [options] sourcedir outdir [filenames...]" -options: -b -- builder to use; default is html +Sphinx v%s +Usage: %s [options] sourcedir outdir [filenames...]" +Options: -b -- builder to use; default is html -a -- write all files; default is to only write new and changed files -E -- don't use a saved environment, always read all files -d -- path for the cached environment and doctree files @@ -37,10 +42,10 @@ options: -b -- builder to use; default is html -N -- do not do colored output -q -- no output on stdout, just warnings on stderr -P -- run Pdb on exception -modi: +Modi: * without -a and without filenames, write new and changed files. * with -a, write all files. -* with filenames, write these.""" % (argv[0],) +* with filenames, write these.""" % (__version__, argv[0]) def main(argv=sys.argv): @@ -104,24 +109,43 @@ def main(argv=sys.argv): elif opt == '-P': use_pdb = True - app = Sphinx(srcdir, outdir, doctreedir, buildername, - confoverrides, status, sys.stderr, freshenv) - if not app.builder: - return 1 - try: + app = Sphinx(srcdir, outdir, doctreedir, buildername, + confoverrides, status, sys.stderr, freshenv) + if not app.builder: + return 1 + if all_files: app.builder.build_all() elif filenames: app.builder.build_specific(filenames) else: app.builder.build_update() + except Exception, err: + if use_pdb: + import pdb + print >>sys.stderr, darkred('Exception occurred while building, ' + 'starting debugger:') + traceback.print_exc() + pdb.post_mortem(sys.exc_info()[2]) + else: + if isinstance(err, SystemMessage): + print >>sys.stderr, darkred('reST markup error:') + print >>sys.stderr, str(err) + else: + print >>sys.stderr, darkred('Exception occurred:') + print >>sys.stderr, format_exception_cut_frames().rstrip() + tbpath = save_traceback() + print >>sys.stderr, darkred('The full traceback has been saved ' + 'in %s, if you want to report the ' + 'issue to the author.' % tbpath) + print >>sys.stderr, ('Please also report this if it was a user ' + 'error, so that a better error message ' + 'can be provided next time.') + print >>sys.stderr, 'Send reports to georg@python.org. Thanks!' except: - if not use_pdb: - raise - import pdb, traceback - traceback.print_exc() - pdb.post_mortem(sys.exc_info()[2]) + # catches BaseExceptions in 2.5 -- SystemExit, KeyboardInterrupt + pass if __name__ == '__main__': diff --git a/sphinx/builder.py b/sphinx/builder.py index 99bd3333a..1837e5728 100644 --- a/sphinx/builder.py +++ b/sphinx/builder.py @@ -56,6 +56,7 @@ class Builder(object): self.warn = app.warn self.info = app.info self.config = app.config + 1/0 # if None, this is set in load_env() self.env = env @@ -240,11 +241,7 @@ class Builder(object): self.env.set_warnfunc(warnings.append) for docname in self.status_iterator(sorted(docnames), 'writing output... ', darkgreen): - try: - doctree = self.env.get_and_resolve_doctree(docname, self) - except Exception, err: - warnings.append('%s:: doctree not found!' % docname) - continue + doctree = self.env.get_and_resolve_doctree(docname, self) self.write_doc(docname, doctree) for warning in warnings: if warning.strip(): diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index c470eaa8a..1252d4c81 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -12,6 +12,7 @@ import os import sys import fnmatch +import tempfile import traceback from os import path @@ -120,3 +121,27 @@ def rpartition(s, t): if i != -1: return s[:i], s[i+len(t):] return '', s + + +def format_exception_cut_frames(x=1): + """ + Format an exception with traceback, but only the last x frames. + """ + typ, val, tb = sys.exc_info() + #res = ['Traceback (most recent call last):\n'] + res = [] + tbres = traceback.format_tb(tb) + res += tbres[-x:] + res += traceback.format_exception_only(typ, val) + return ''.join(res) + + +def save_traceback(): + """ + Save the current exception's traceback in a temporary file. + """ + exc = traceback.format_exc() + fd, path = tempfile.mkstemp('.log', 'sphinx-err-') + os.write(fd, exc) + os.close(fd) + return path