diff options
Diffstat (limited to 'sphinx/cmdline.py')
-rw-r--r-- | sphinx/cmdline.py | 398 |
1 files changed, 195 insertions, 203 deletions
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py index ec24d902..6486e64b 100644 --- a/sphinx/cmdline.py +++ b/sphinx/cmdline.py @@ -8,13 +8,15 @@ :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ +from __future__ import print_function import os import sys -import getopt +import optparse import traceback from os import path +from six import text_type, binary_type from docutils.utils import SystemMessage from sphinx import __version__ @@ -23,106 +25,138 @@ from sphinx.application import Sphinx from sphinx.util import Tee, format_exception_cut_frames, save_traceback from sphinx.util.console import red, nocolor, color_terminal from sphinx.util.osutil import abspath, fs_encoding -from sphinx.util.pycompat import terminal_safe, bytes +from sphinx.util.pycompat import terminal_safe def usage(argv, msg=None): if msg: - print >>sys.stderr, msg - print >>sys.stderr - print >>sys.stderr, """\ + print(msg, file=sys.stderr) + print(file=sys.stderr) + +USAGE = """\ Sphinx v%s -Usage: %s [options] sourcedir outdir [filenames...] - -General options -^^^^^^^^^^^^^^^ --b <builder> 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> path for the cached environment and doctree files - (default: outdir/.doctrees) --j <N> build in parallel with N processes where possible --M <builder> "make" mode -- used by Makefile, like "sphinx-build -M html" - -Build configuration options -^^^^^^^^^^^^^^^^^^^^^^^^^^^ --c <path> path where configuration file (conf.py) is located - (default: same as sourcedir) --C use no config file at all, only -D options --D <setting=value> override a setting in configuration file --t <tag> define tag: include "only" blocks with <tag> --A <name=value> pass a value into the templates, for HTML builder --n nit-picky mode, warn about all missing references - -Console output options -^^^^^^^^^^^^^^^^^^^^^^ --v increase verbosity (can be repeated) --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 --T show full traceback on exception --N do not emit colored output --P run Pdb on exception - -Filename arguments -^^^^^^^^^^^^^^^^^^ -* without -a and without filenames, write new and changed files. -* with -a, write all files. -* with filenames, write these. - -Standard options -^^^^^^^^^^^^^^^^ --h, --help show this help and exit ---version show version information and exit -""" % (__version__, argv[0]) +Usage: %%prog [options] sourcedir outdir [filenames...] + +Filename arguments: + without -a and without filenames, write new and changed files. + with -a, write all files. + with filenames, write these. +""" % __version__ + +EPILOG = """\ +For more information, visit <http://sphinx-doc.org/>. +""" + + +class MyFormatter(optparse.IndentedHelpFormatter): + def format_usage(self, usage): + return usage + + def format_help(self, formatter): + result = [] + if self.description: + result.append(self.format_description(formatter)) + if self.option_list: + result.append(self.format_option_help(formatter)) + return "\n".join(result) def main(argv): if not color_terminal(): - # Windows' poor cmd box doesn't understand ANSI sequences nocolor() + parser = optparse.OptionParser(USAGE, epilog=EPILOG, formatter=MyFormatter()) + parser.add_option('--version', action='store_true', dest='version', + help='show version information and exit') + + group = parser.add_option_group('General options') + group.add_option('-b', metavar='BUILDER', dest='builder', default='html', + help='builder to use; default is html') + group.add_option('-a', action='store_true', dest='force_all', + help='write all files; default is to only write new and ' + 'changed files') + group.add_option('-E', action='store_true', dest='freshenv', + help='don\'t use a saved environment, always read ' + 'all files') + group.add_option('-d', metavar='PATH', default=None, dest='doctreedir', + help='path for the cached environment and doctree files ' + '(default: outdir/.doctrees)') + group.add_option('-j', metavar='N', default=1, type='int', dest='jobs', + help='build in parallel with N processes where possible') + # this option never gets through to this point (it is intercepted earlier) + # group.add_option('-M', metavar='BUILDER', dest='make_mode', + # help='"make" mode -- as used by Makefile, like ' + # '"sphinx-build -M html"') + + group = parser.add_option_group('Build configuration options') + group.add_option('-c', metavar='PATH', dest='confdir', + help='path where configuration file (conf.py) is located ' + '(default: same as sourcedir)') + group.add_option('-C', action='store_true', dest='noconfig', + help='use no config file at all, only -D options') + group.add_option('-D', metavar='setting=value', action='append', + dest='define', default=[], + help='override a setting in configuration file') + group.add_option('-A', metavar='name=value', action='append', + dest='htmldefine', default=[], + help='pass a value into HTML templates') + group.add_option('-t', metavar='TAG', action='append', + dest='tags', default=[], + help='define tag: include "only" blocks with TAG') + group.add_option('-n', action='store_true', dest='nitpicky', + help='nit-picky mode, warn about all missing references') + + group = parser.add_option_group('Console output options') + group.add_option('-v', action='count', dest='verbosity', default=0, + help='increase verbosity (can be repeated)') + group.add_option('-q', action='store_true', dest='quiet', + help='no output on stdout, just warnings on stderr') + group.add_option('-Q', action='store_true', dest='really_quiet', + help='no output at all, not even warnings') + group.add_option('-N', action='store_true', dest='nocolor', + help='do not emit colored output') + group.add_option('-w', metavar='FILE', dest='warnfile', + help='write warnings (and errors) to given file') + group.add_option('-W', action='store_true', dest='warningiserror', + help='turn warnings into errors') + group.add_option('-T', action='store_true', dest='traceback', + help='show full traceback on exception') + group.add_option('-P', action='store_true', dest='pdb', + help='run Pdb on exception') + # parse options try: - opts, args = getopt.getopt(argv[1:], 'ab:t:d:c:CD:A:nNEqQWw:PThvj:', - ['help', 'version']) - except getopt.error, err: - usage(argv, 'Error: %s' % err) - return 1 + opts, args = parser.parse_args(argv[1:]) + except SystemExit as err: + return err.code # handle basic options - allopts = set(opt[0] for opt in opts) - # help and version options - if '-h' in allopts or '--help' in allopts: - usage(argv) - print >>sys.stderr - print >>sys.stderr, 'For more information, see <http://sphinx-doc.org/>.' - return 0 - if '--version' in allopts: - print 'Sphinx (sphinx-build) %s' % __version__ + if opts.version: + print('Sphinx (sphinx-build) %s' % __version__) return 0 # get paths (first and second positional argument) try: - srcdir = confdir = abspath(args[0]) + srcdir = abspath(args[0]) + confdir = abspath(opts.confdir or srcdir) + if opts.noconfig: + confdir = None if not path.isdir(srcdir): - print >>sys.stderr, 'Error: Cannot find source directory `%s\'.' % ( - srcdir,) + print('Error: Cannot find source directory `%s\'.' % srcdir, + file=sys.stderr) return 1 - if not path.isfile(path.join(srcdir, 'conf.py')) and \ - '-c' not in allopts and '-C' not in allopts: - print >>sys.stderr, ('Error: Source directory doesn\'t ' - 'contain a conf.py file.') + if not opts.noconfig and not path.isfile(path.join(confdir, 'conf.py')): + print('Error: Config directory doesn\'t contain a conf.py file.', + file=sys.stderr) return 1 outdir = abspath(args[1]) except IndexError: usage(argv, 'Error: Insufficient arguments.') return 1 except UnicodeError: - print >>sys.stderr, ( + print( 'Error: Multibyte filename not supported on this filesystem ' - 'encoding (%r).' % fs_encoding) + 'encoding (%r).' % fs_encoding, file=sys.stderr) return 1 # handle remaining filename arguments @@ -130,7 +164,7 @@ def main(argv): err = 0 for filename in filenames: if not path.isfile(filename): - print >>sys.stderr, 'Error: Cannot find file %r.' % filename + print('Error: Cannot find file %r.' % filename, file=sys.stderr) err = 1 if err: return 1 @@ -142,155 +176,113 @@ def main(argv): except Exception: likely_encoding = None - buildername = None - force_all = freshenv = warningiserror = use_pdb = False - show_traceback = False - verbosity = 0 - parallel = 0 + if opts.force_all and filenames: + print('Error: Cannot combine -a option and filenames.', file=sys.stderr) + return 1 + + if opts.nocolor: + nocolor() + + doctreedir = abspath(opts.doctreedir or path.join(outdir, '.doctrees')) + status = sys.stdout warning = sys.stderr error = sys.stderr - warnfile = None - confoverrides = {} - tags = [] - doctreedir = path.join(outdir, '.doctrees') - for opt, val in opts: - if opt == '-b': - buildername = val - elif opt == '-a': - if filenames: - usage(argv, 'Error: Cannot combine -a option and filenames.') - return 1 - force_all = True - elif opt == '-t': - tags.append(val) - elif opt == '-d': - doctreedir = abspath(val) - elif opt == '-c': - confdir = abspath(val) - if not path.isfile(path.join(confdir, 'conf.py')): - print >>sys.stderr, ('Error: Configuration directory ' - 'doesn\'t contain conf.py file.') - return 1 - elif opt == '-C': - confdir = None - elif opt == '-D': - try: - key, val = val.split('=') - except ValueError: - print >>sys.stderr, ('Error: -D option argument must be ' - 'in the form name=value.') - return 1 - try: - val = int(val) - except ValueError: - if likely_encoding and isinstance(val, bytes): - try: - val = val.decode(likely_encoding) - except UnicodeError: - pass - confoverrides[key] = val - elif opt == '-A': - try: - key, val = val.split('=') - except ValueError: - print >>sys.stderr, ('Error: -A option argument must be ' - 'in the form name=value.') - return 1 - try: - val = int(val) - except ValueError: - if likely_encoding and isinstance(val, bytes): - try: - val = val.decode(likely_encoding) - except UnicodeError: - pass - confoverrides['html_context.%s' % key] = val - elif opt == '-n': - confoverrides['nitpicky'] = True - elif opt == '-N': - nocolor() - elif opt == '-E': - freshenv = True - elif opt == '-q': - status = None - elif opt == '-Q': - status = None - warning = None - elif opt == '-W': - warningiserror = True - elif opt == '-w': - warnfile = val - elif opt == '-P': - use_pdb = True - elif opt == '-T': - show_traceback = True - elif opt == '-v': - verbosity += 1 - show_traceback = True - elif opt == '-j': - try: - parallel = int(val) - except ValueError: - print >>sys.stderr, ('Error: -j option argument must be an ' - 'integer.') - return 1 - - if warning and warnfile: - warnfp = open(warnfile, 'w') + + if opts.quiet: + status = None + if opts.really_quiet: + status = warning = None + if warning and opts.warnfile: + try: + warnfp = open(opts.warnfile, 'w') + except Exception as exc: + print('Error: Cannot open warning file %r: %s' % + (opts.warnfile, exc), file=sys.stderr) + sys.exit(1) warning = Tee(warning, warnfp) error = warning - if not path.isdir(outdir): - if status: - print >>status, 'Making output directory...' - os.makedirs(outdir) + confoverrides = {} + for val in opts.define: + try: + key, val = val.split('=') + except ValueError: + print('Error: -D option argument must be in the form name=value.', + file=sys.stderr) + return 1 + if likely_encoding and isinstance(val, binary_type): + try: + val = val.decode(likely_encoding) + except UnicodeError: + pass + confoverrides[key] = val + + for val in opts.htmldefine: + try: + key, val = val.split('=') + except ValueError: + print('Error: -A option argument must be in the form name=value.', + file=sys.stderr) + return 1 + try: + val = int(val) + except ValueError: + if likely_encoding and isinstance(val, binary_type): + try: + val = val.decode(likely_encoding) + except UnicodeError: + pass + confoverrides['html_context.%s' % key] = val + + if opts.nitpicky: + confoverrides['nitpicky'] = True app = None try: - app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername, - confoverrides, status, warning, freshenv, - warningiserror, tags, verbosity, parallel) - app.build(force_all, filenames) + app = Sphinx(srcdir, confdir, outdir, doctreedir, opts.builder, + confoverrides, status, warning, opts.freshenv, + opts.warningiserror, opts.tags, opts.verbosity, opts.jobs) + app.build(opts.force_all, filenames) return app.statuscode - except (Exception, KeyboardInterrupt), err: - if use_pdb: + except (Exception, KeyboardInterrupt) as err: + if opts.pdb: import pdb - print >>error, red('Exception occurred while building, ' - 'starting debugger:') + print(red('Exception occurred while building, starting debugger:'), + file=error) traceback.print_exc() pdb.post_mortem(sys.exc_info()[2]) else: - print >>error - if show_traceback: + print(file=error) + if opts.verbosity or opts.traceback: traceback.print_exc(None, error) - print >>error + print(file=error) if isinstance(err, KeyboardInterrupt): - print >>error, 'interrupted!' + print('interrupted!', file=error) elif isinstance(err, SystemMessage): - print >>error, red('reST markup error:') - print >>error, terminal_safe(err.args[0]) + print(red('reST markup error:'), file=error) + print(terminal_safe(err.args[0]), file=error) elif isinstance(err, SphinxError): - print >>error, red('%s:' % err.category) - print >>error, terminal_safe(unicode(err)) + print(red('%s:' % err.category), file=error) + print(terminal_safe(text_type(err)), file=error) elif isinstance(err, UnicodeError): - print >>error, red('Encoding error:') - print >>error, terminal_safe(unicode(err)) + print(red('Encoding error:'), file=error) + print(terminal_safe(text_type(err)), file=error) tbpath = save_traceback(app) - print >>error, red('The full traceback has been saved ' - 'in %s, if you want to report the ' - 'issue to the developers.' % tbpath) + print(red('The full traceback has been saved in %s, if you want ' + 'to report the issue to the developers.' % tbpath), + file=error) else: - print >>error, red('Exception occurred:') - print >>error, format_exception_cut_frames().rstrip() + print(red('Exception occurred:'), file=error) + print(format_exception_cut_frames().rstrip(), file=error) tbpath = save_traceback(app) - print >>error, red('The full traceback has been saved ' - 'in %s, if you want to report the ' - 'issue to the developers.' % 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, ( - 'A bug report can be filed in the tracker at ' - '<https://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!') + print(red('The full traceback has been saved in %s, if you ' + 'want to report the issue to the developers.' % tbpath), + file=error) + print('Please also report this if it was a user error, so ' + 'that a better error message can be provided next time.', + file=error) + print('A bug report can be filed in the tracker at ' + '<https://bitbucket.org/birkenfeld/sphinx/issues/>. Thanks!', + file=error) return 1 |