Georg Brandl avatar Georg Brandl committed 635df61

#62: There is now a ``-w`` option for sphinx-build that writes
warnings to a file, in addition to stderr.

Comments (0)

Files changed (5)

 
   - Quickstart can now generate a Windows ``make.bat`` file.
 
+  - #62: There is now a ``-w`` option for sphinx-build that writes
+    warnings to a file, in addition to stderr.
+
   - There is now a ``-W`` option for sphinx-build that turns warnings
     into errors.
 
    Do not output anything on standard output, also suppress warnings.  Only
    errors are written to standard error.
 
+**-w** *file*
+   Write warnings (and errors) to the given file, in addition to standard error.
+
 **-W**
    Turn warnings into errors.  This means that the build stops at the first
    warning and ``sphinx-build`` exits with exit status 1.

doc/sphinx-build.1

 \fB-Q\fR
 Very quiet operation, doesn't print anything except for errors.
 .TP
+\fB-w\fR <file>
+Write warnings and errors into the given file, in addition to stderr.
+.TP
+\fB-W\fR
+Turn warnings into errors.
+.TP
 \fB-P\fR
 Runs Pdb on exception.
 .SH "SEE ALSO"

sphinx/cmdline.py

 
 from sphinx import __version__
 from sphinx.application import Sphinx, SphinxError
-from sphinx.util import format_exception_cut_frames, save_traceback
+from sphinx.util import Tee, format_exception_cut_frames, save_traceback
 from sphinx.util.console import darkred, nocolor, color_terminal
 
 
          -N        -- do not do colored output
          -q        -- no output on stdout, just warnings on stderr
          -Q        -- no output at all, not even warnings
+         -w <file> -- write warnings (and errors) to given file
          -W        -- turn warnings into errors
          -P        -- run Pdb on exception
 Modi:
         nocolor()
 
     try:
-        opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:NEqQWP')
+        opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:NEqQWw:P')
         allopts = set(opt[0] for opt in opts)
         srcdir = confdir = path.abspath(args[0])
         if not path.isdir(srcdir):
     freshenv = warningiserror = use_pdb = False
     status = sys.stdout
     warning = sys.stderr
+    error = sys.stderr
+    warnfile = None
     confoverrides = {}
     htmlcontext = {}
     tags = []
             warning = None
         elif opt == '-W':
             warningiserror = True
+        elif opt == '-w':
+            warnfile = val
         elif opt == '-P':
             use_pdb = True
     confoverrides['html_context'] = htmlcontext
 
+    if warning and warnfile:
+        warnfp = open(warnfile, 'w')
+        warning = Tee(warning, warnfp)
+        error = warning
+
     try:
         app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername,
                      confoverrides, status, warning, freshenv,
     except KeyboardInterrupt:
         if use_pdb:
             import pdb
-            print >>sys.stderr, darkred('Interrupted while building, '
-                                        'starting debugger:')
+            print >>error, darkred('Interrupted while building, '
+                                   'starting debugger:')
             traceback.print_exc()
             pdb.post_mortem(sys.exc_info()[2])
         return 1
     except Exception, err:
         if use_pdb:
             import pdb
-            print >>sys.stderr, darkred('Exception occurred while building, '
-                                        'starting debugger:')
+            print >>error, 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, err.args[0].encode('ascii',
-                                                       'backslashreplace')
+                print >>error, darkred('reST markup error:')
+                print >>error, err.args[0].encode('ascii', 'backslashreplace')
             elif isinstance(err, SphinxError):
-                print >>sys.stderr, darkred('%s:' % err.category)
-                print >>sys.stderr, err
+                print >>error, darkred('%s:' % err.category)
+                print >>error, err
             else:
-                print >>sys.stderr, darkred('Exception occurred:')
-                print >>sys.stderr, format_exception_cut_frames().rstrip()
+                print >>error, darkred('Exception occurred:')
+                print >>error, 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 '
-                                     'sphinx-dev@googlegroups.com. Thanks!')
+                print >>error, darkred('The full traceback has been saved '
+                                       'in %s, if you want to report the '
+                                       'issue to the author.' % tbpath)
+                print >>error, ('Please also report this if it was a user '
+                                'error, so that a better error message '
+                                'can be provided next time.')
+                print >>error, ('Send reports to sphinx-dev@googlegroups.com. '
+                                'Thanks!')
             return 1

sphinx/util/__init__.py

     return time.strftime(unicode(format).encode('utf-8'), *args).decode('utf-8')
 
 
+class Tee(object):
+    """
+    File-like object writing to two streams.
+    """
+    def __init__(self, stream1, stream2):
+        self.stream1 = stream1
+        self.stream2 = stream2
+
+    def write(self, text):
+        self.stream1.write(text)
+        self.stream2.write(text)
+
+
 class FilenameUniqDict(dict):
     """
     A dictionary that automatically generates unique names for its keys,
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.