Example #1
0
def emit_feed(app, exc):
    import os.path
    ordered_items = app.builder.env.feed_items.values()
    feed = app.builder.env.feed_feed
    ordered_items.sort(
      cmp=lambda x,y: cmp(x['pubDate'],y['pubDate']),
      reverse=True)
    for item in ordered_items:
        feed.items.append(item)
    
    path = os.path.join(app.builder.outdir,
                        app.config.feed_filename)
    feed.format_rss2_file(path)
    
    from os import path
    from sphinx.application import ENV_PICKLE_FILENAME
    from sphinx.util.console import bold
    # save the environment
    builder = app.builder
    builder.info(bold('pickling environment... '), nonl=True)
    builder.env.topickle(path.join(builder.doctreedir, ENV_PICKLE_FILENAME))
    builder.info('done')
    
    # global actions
    builder.info(bold('checking consistency... '), nonl=True)
    builder.env.check_consistency()
    builder.info('done')
Example #2
0
File: html.py Project: 89sos98/main
    def handle_finish(self):
        self.info(bold('dumping search index... '), nonl=True)
        self.indexer.prune(self.env.all_docs)
        searchindexfn = path.join(self.outdir, self.searchindex_filename)
        # first write to a temporary file, so that if dumping fails,
        # the existing index won't be overwritten
        f = open(searchindexfn + '.tmp', 'wb')
        try:
            self.indexer.dump(f, self.indexer_format)
        finally:
            f.close()
        movefile(searchindexfn + '.tmp', searchindexfn)
        self.info('done')

        self.info(bold('dumping object inventory... '), nonl=True)
        f = open(path.join(self.outdir, INVENTORY_FILENAME), 'w')
        try:
            f.write('# Sphinx inventory version 1\n')
            f.write('# Project: %s\n' % self.config.project.encode('utf-8'))
            f.write('# Version: %s\n' % self.config.version)
            for modname, info in self.env.modules.iteritems():
                f.write('%s mod %s\n' % (modname, self.get_target_uri(info[0])))
            for refname, (docname, desctype) in self.env.descrefs.iteritems():
                f.write('%s %s %s\n' % (refname, desctype,
                                        self.get_target_uri(docname)))
        finally:
            f.close()
        self.info('done')
Example #3
0
def emit_feed(app, exc):
    ordered_items = list(app.builder.env.feed_items.values())
    feed = app.builder.env.feed_feed
    ordered_items.sort(
        key=lambda x: x['pubDate'],
        reverse=True,
    )
    for item in ordered_items:
        feed.items.append(item)

    path = os.path.join(app.builder.outdir,
                        app.config.feed_filename)
    feed.format_rss2_file(path)

    # save the environment
    builder = app.builder
    LOG.info(bold('pickling environment... '), nonl=True)
    pickle_path = os.path.join(builder.doctreedir, ENV_PICKLE_FILENAME)
    with open(pickle_path, 'wb') as f:
        pickle.dump(builder.env, f)
    LOG.info('done')

    # global actions
    LOG.info(bold('checking consistency... '), nonl=True)
    builder.env.check_consistency()
    LOG.info('done')
def copy_media(app, exception):
    """ Move our dynamically generated files after build. """
    if app.builder.name in ["readthedocs", "readthedocsdirhtml"] and not exception:
        for file in ["readthedocs-dynamic-include.js_t", "readthedocs-data.js_t", "searchtools.js_t"]:
            app.info(bold("Copying %s... " % file), nonl=True)
            dest_dir = os.path.join(app.builder.outdir, "_static")
            source = os.path.join(os.path.abspath(os.path.dirname(__file__)), "_static", file)
            try:
                ctx = app.builder.globalcontext
            except AttributeError:
                ctx = {}
            if app.builder.indexer is not None:
                ctx.update(app.builder.indexer.context_for_searchtool())
            copy_static_entry(source, dest_dir, app.builder, ctx)
            app.info("done")

    if "comments" in app.builder.name and not exception:
        for file in STATIC_FILES:
            app.info(bold("Copying %s... " % file), nonl=True)
            dest_dir = os.path.join(app.builder.outdir, "_static")
            source = os.path.join(os.path.abspath(os.path.dirname(__file__)), "_static", file)
            try:
                ctx = app.builder.globalcontext
            except AttributeError:
                ctx = {}
            ctx["websupport2_base_url"] = app.builder.config.websupport2_base_url
            ctx["websupport2_static_url"] = app.builder.config.websupport2_static_url
            copy_static_entry(source, dest_dir, app.builder, ctx)
            app.info("done")
Example #5
0
def get_input(fields, argv):
    print bold('Welcome to the sffms quickstart utility!')
    print '''
Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).'''
    
    fields['path'] = get_path_from_cmdline(argv)
    if fields['path'] is None:
        print '''
Enter the directory in which to create your manuscript. The default
is this directory.'''
        do_prompt(fields, 'path', 'Path to your manuscript', '.', is_path)
    get_clear_path(fields)
        
    print '''
You can use this script to set up a novel or a short story.
For novels, sffms-quickstart creates a master story file and 
three chapter files, while for short stories, sffms-quickstart 
generates a single master story file. Short stories are also 
typeset a little differently from novels.'''
    do_prompt(fields, 'novel', 'Are you creating a novel? (y/N)', 'n', boolean)

    print ''
    do_prompt(fields, 'title', 'Enter your manuscript\'s title')
    fields['reST_title'] = generate_reST_title(fields['title'])
    # We sanitize the title after creating the 'reST_title' because we 
    # don't actually want to escape those characters in reST -- just in Python.
    fields['title'] = py_sanitize(fields['title'])
    
    print '''
Your title appears in a running header at the top of the page.
If you have a long title, consider supplying a shorter version
for inclusion in the running header. For example, for the story
'The Adventures of Sherlock Holmes: A Scandal in Bohemia,' the
short version could be 'A Scandal in Bohemia.' '''
    do_prompt(fields, 'runningtitle', 'Enter your manuscript\'s short title (optional)', validator=optional)
    
    print ''
    do_prompt(fields, 'author', 'Enter your full name', validator=required_string)
    
    print '''
Your full name (or surname, if specified) appears in the 
running header. Consider supplying your surname here.'''
    do_prompt(fields, 'surname', 'Enter your surname (optional)', validator=optional)
    
    print '''
You may enter a free-form multi-line address, including a postal 
address, telephone number, email address, or whatever contact info 
you wish to include. The address is displayed on the title page. 
When you are done entering the address, enter an empty (blank) line.'''
    prompt_address(fields)

    print '''
Your story source is contained in a master file. This file
either contains the entire story, or a table of contents
that points to separate chapter files.'''
    do_prompt(fields, 'master_doc', 'Name of your master source file (without suffix)', 'manuscript', validator=py_sanitize)
            
    fields['now'] = time.asctime()
    fields['copyright'] = time.strftime('%Y') + ', ' + fields['author']
Example #6
0
    def finish(self):
        # copy image files
        if self.images:
            self.info(bold("copying images..."), nonl=1)
            for src, dest in self.images.iteritems():
                self.info(" " + src, nonl=1)
                copyfile(path.join(self.srcdir, src), path.join(self.outdir, dest))
            self.info()

        # copy additional files
        if self.config.latex_additional_files:
            self.info(bold("copying additional files..."), nonl=1)
            for filename in self.config.latex_additional_files:
                self.info(" " + filename, nonl=1)
                copyfile(path.join(self.confdir, filename), path.join(self.outdir, path.basename(filename)))
            self.info()

        # the logo is handled differently
        if self.config.latex_logo:
            logobase = path.basename(self.config.latex_logo)
            copyfile(path.join(self.confdir, self.config.latex_logo), path.join(self.outdir, logobase))

        self.info(bold("copying TeX support files... "), nonl=True)
        staticdirname = path.join(package_dir, "texinputs")
        for filename in os.listdir(staticdirname):
            if not filename.startswith("."):
                copyfile(path.join(staticdirname, filename), path.join(self.outdir, filename))
        self.info("done")
Example #7
0
    def finish(self):
        # copy image files
        if self.images:
            self.info(bold('copying images...'), nonl=1)
            for src, dest in iteritems(self.images):
                self.info(' '+src, nonl=1)
                copyfile(path.join(self.srcdir, src),
                         path.join(self.outdir, dest))
            self.info()

        # copy TeX support files from texinputs
        self.info(bold('copying TeX support files...'))
        staticdirname = path.join(package_dir, 'texinputs')
        for filename in os.listdir(staticdirname):
            if not filename.startswith('.'):
                copyfile(path.join(staticdirname, filename),
                         path.join(self.outdir, filename))

        # copy additional files
        if self.config.latex_additional_files:
            self.info(bold('copying additional files...'), nonl=1)
            for filename in self.config.latex_additional_files:
                self.info(' '+filename, nonl=1)
                copyfile(path.join(self.confdir, filename),
                         path.join(self.outdir, path.basename(filename)))
            self.info()

        # the logo is handled differently
        if self.config.latex_logo:
            logobase = path.basename(self.config.latex_logo)
            copyfile(path.join(self.confdir, self.config.latex_logo),
                     path.join(self.outdir, logobase))
        self.info('done')
Example #8
0
    def finish(self):
        # copy image files
        if self.images:
            self.info(bold('copying images...'), nonl=1)
            for src, dest in iteritems(self.images):
                self.info(' '+src, nonl=1)
                copy_asset_file(path.join(self.srcdir, src),
                                path.join(self.outdir, dest))
            self.info()

        # copy TeX support files from texinputs
        context = {'latex_engine': self.config.latex_engine}
        self.info(bold('copying TeX support files...'))
        staticdirname = path.join(package_dir, 'texinputs')
        for filename in os.listdir(staticdirname):
            if not filename.startswith('.'):
                copy_asset_file(path.join(staticdirname, filename),
                                self.outdir, context=context)

        # copy additional files
        if self.config.latex_additional_files:
            self.info(bold('copying additional files...'), nonl=1)
            for filename in self.config.latex_additional_files:
                self.info(' '+filename, nonl=1)
                copy_asset_file(path.join(self.confdir, filename), self.outdir)
            self.info()

        # the logo is handled differently
        if self.config.latex_logo:
            if not path.isfile(path.join(self.confdir, self.config.latex_logo)):
                raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
            else:
                copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
        self.info('done')
Example #9
0
    def finish(self):
        # type: () -> None
        self.copy_image_files()

        # copy TeX support files from texinputs
        context = {'latex_engine': self.config.latex_engine}
        logger.info(bold('copying TeX support files...'))
        staticdirname = path.join(package_dir, 'texinputs')
        for filename in os.listdir(staticdirname):
            if not filename.startswith('.'):
                copy_asset_file(path.join(staticdirname, filename),
                                self.outdir, context=context)

        # use pre-1.6.x Makefile for make latexpdf on Windows
        if os.name == 'nt':
            staticdirname = path.join(package_dir, 'texinputs_win')
            copy_asset_file(path.join(staticdirname, 'Makefile_t'),
                            self.outdir, context=context)

        # copy additional files
        if self.config.latex_additional_files:
            logger.info(bold('copying additional files...'), nonl=1)
            for filename in self.config.latex_additional_files:
                logger.info(' ' + filename, nonl=1)
                copy_asset_file(path.join(self.confdir, filename), self.outdir)
            logger.info('')

        # the logo is handled differently
        if self.config.latex_logo:
            if not path.isfile(path.join(self.confdir, self.config.latex_logo)):
                raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
            else:
                copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
        logger.info('done')
Example #10
0
def emit_feed(app, exc):
    ordered_items = list(app.builder.env.feed_items.values())
    feed = app.builder.env.feed_feed
    # ordered_items.sort(key=lambda x: x['pubDate'], reverse=True)
    ordered_items.sort(key=lambda x: x.published())
    for item in ordered_items:
        feed.add_entry(item)  # prepends the item
        # for k, v in item.items():
        #     getattr(e, k)(v)
    
    path = os.path.join(app.builder.outdir,
                        app.config.feed_filename)
    # print(20190315, path)
    feed.rss_file(path)
    
    return
    # LS 20180204 The following code (pickle the environment and check
    # consistency at this point) caused an error when also bibtex was
    # installed. I deactivated it since I don't know why it's needed.
    
    from os import path
    from sphinx.application import ENV_PICKLE_FILENAME
    from sphinx.util.console import bold
    # save the environment
    builder = app.builder
    builder.info(bold('pickling environment... '), nonl=True)
    builder.env.topickle(path.join(builder.doctreedir, ENV_PICKLE_FILENAME))
    builder.info('done')
    
    # global actions
    builder.info(bold('checking consistency... '), nonl=True)
    builder.env.check_consistency()
    builder.info('done')
Example #11
0
    def build(self, force_all=False, filenames=None):
        # type: (bool, List[unicode]) -> None
        try:
            if force_all:
                self.builder.compile_all_catalogs()
                self.builder.build_all()
            elif filenames:
                self.builder.compile_specific_catalogs(filenames)
                self.builder.build_specific(filenames)
            else:
                self.builder.compile_update_catalogs()
                self.builder.build_update()

            status = (self.statuscode == 0 and
                      __('succeeded') or __('finished with problems'))
            if self._warncount:
                logger.info(bold(__('build %s, %s warning%s.') %
                                 (status, self._warncount,
                                  self._warncount != 1 and 's' or '')))
            else:
                logger.info(bold(__('build %s.') % status))
        except Exception as err:
            # delete the saved env to force a fresh build next time
            envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
            if path.isfile(envfile):
                os.unlink(envfile)
            self.emit('build-finished', err)
            raise
        else:
            self.emit('build-finished', None)
        self.builder.cleanup()
Example #12
0
def merge_js_index(app):
    """
    Merge the JS indexes of the sub-docs into the main JS index
    """
    app.info('')
    app.info(bold('Merging js index files...'))
    mapping = app.builder.indexer._mapping
    for curdoc in app.env.config.multidocs_subdoc_list:
        app.info("    %s:"%curdoc, nonl=1)
        fixpath = lambda path: os.path.join(curdoc, path)
        index = get_js_index(app, curdoc)
        if index is not None:
            # merge the mappings
            app.info(" %s js index entries"%(len(index._mapping)))
            for (ref, locs) in index._mapping.iteritems():
                newmapping = set(map(fixpath, locs))
                if ref in mapping:
                    newmapping = mapping[ref] | newmapping
                mapping[unicode(ref)] = newmapping
            # merge the titles
            titles = app.builder.indexer._titles
            for (res, title) in index._titles.iteritems():
                titles[fixpath(res)] = title
            # TODO: merge indexer._objtypes, indexer._objnames as well

            # Setup source symbolic links
            dest = os.path.join(app.outdir, "_sources", curdoc)
            if not os.path.exists(dest):
                os.symlink(os.path.join("..", curdoc, "_sources"), dest)
    app.info('... done (%s js index entries)'%(len(mapping)))
    app.info(bold('Writing js search indexes...'), nonl=1)
    return [] # no extra page to setup
    def build(self, force_all=False, filenames=None):
        try:
            if force_all:
                self.builder.compile_all_catalogs()
                self.builder.build_all()
            elif filenames:
                self.builder.compile_specific_catalogs(filenames)
                self.builder.build_specific(filenames)
            else:
                self.builder.compile_update_catalogs()
                self.builder.build_update()

            status = self.statuscode == 0 and "succeeded" or "finished with problems"
            if self._warncount:
                self.info(
                    bold("build %s, %s warning%s." % (status, self._warncount, self._warncount != 1 and "s" or ""))
                )
            else:
                self.info(bold("build %s." % status))
        except Exception as err:
            # delete the saved env to force a fresh build next time
            envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
            if path.isfile(envfile):
                os.unlink(envfile)
            self.emit("build-finished", err)
            raise
        else:
            self.emit("build-finished", None)
        self.builder.cleanup()
Example #14
0
def get_clear_path(fields):
    while os.path.isfile(os.path.join(fields['path'], 'conf.py')):
        print bold('\nError: your path already has a conf.py.')
        print 'sffms-quickstart will not overwrite existing projects.\n'
        do_prompt(fields, 'path', 'Please enter a new path (or just Enter to exit)', '', is_path)
        if not fields['path']:
            sys.exit(1)
Example #15
0
    def write(self, *ignored):
        global logger
        if logger is None: # Sphinx 1.2.3 compatibility, I know it's bad
            logger = self
        mastername = self.config.master_doc
        mastertree = self.env.get_doctree(mastername)
        mastertitle = u'%(project)s v%(release)s documentation' % \
                {'project': self.config.project, 'release': self.config.release}
        if hasattr(self.config, 'text_title') and self.config.text_title is not None:
            mastertitle = self.config.text_title

        logger.info(bold('preparing documents... '), nonl=True)
        self.prepare_writing(self.env.found_docs)
        logger.info('done')

        logger.info(bold('assembling single document... '), nonl=True)
        tree = None
        try:
            tree = inline_all_toctrees(self, set(), mastername,
                    mastertree, darkgreen)
        except TypeError:
            tree = inline_all_toctrees(self, set(), mastername,
                    mastertree, darkgreen, [mastername])
        tree['docname'] = mastername
        toctree = getTocTree(self, mastername, self, False)
        tree.insert(0, nodes.section() + nodes.title(mastertitle, mastertitle))
        tree.insert(1, toctree)
        self.env.resolve_references(tree, mastername, self)
        logger.info('done')

        logger.info(bold('writing... '), nonl=True)
        if hasattr(self, "write_doc_serialized"):
            self.write_doc_serialized(mastername, tree)
        self.write_doc(mastername, tree)
        logger.info('done')
Example #16
0
def ask_user(d):
    """Wrap sphinx_quickstart.ask_user, and add additional questions."""

    # Print welcome message
    msg = bold('Welcome to the Hieroglyph %s quickstart utility.') % (
        version(),
    )
    print(msg)
    msg = """
This will ask questions for creating a Hieroglyph project, and then ask
some basic Sphinx questions.
"""
    print(msg)

    # set a few defaults that we don't usually care about for Hieroglyph
    d.update({
        'version': datetime.date.today().strftime('%Y.%m.%d'),
        'release': datetime.date.today().strftime('%Y.%m.%d'),
        'ext_autodoc': False,
        'ext_doctest': True,
        'ext_intersphinx': True,
        'ext_todo': True,
        'ext_coverage': True,
        'ext_pngmath': True,
        'ext_mathjax': False,
        'ext_ifconfig': True,
        'ext_viewcode': False,
    })

    if 'project' not in d:
        print('''
The presentation title will be included on the title slide.''')
        sphinx_quickstart.do_prompt(d, 'project', 'Presentation title')
    if 'author' not in d:
        sphinx_quickstart.do_prompt(d, 'author', 'Author name(s)')

    # slide_theme
    msg = """
Hieroglyph includes two themes:

* """ + bold("slides") + """
  The default theme, with different styling for first, second, and third
  level headings.

* """ + bold("single-level") + """
  All slides are styled the same, with the heading at the top.

Which theme would you like to use?"""
    print(msg)

    # XXX make a themes dict that has the keys/descriptions
    sphinx_quickstart.do_prompt(
        d, 'slide_theme', 'Slide Theme', 'slides',
        sphinx_quickstart.choice('slides', 'single-level',),
    )

    # Ask original questions
    print("")
    sphinx_ask_user(d)
Example #17
0
    def write(self, *ignored):
        if self.config.man_pages:
            # build manpages from config.man_pages as usual
            ManualPageBuilder.write(self, *ignored)

        self.info(bold("scan master tree for kernel-doc man-pages ... ") + darkgreen("{"), nonl=True)

        master_tree = self.env.get_doctree(self.config.master_doc)
        master_tree = inline_all_toctrees(
            self, set(), self.config.master_doc, master_tree, darkgreen, [self.config.master_doc])
        self.info(darkgreen("}"))
        man_nodes   = master_tree.traverse(condition=self.is_manpage)
        if not man_nodes and not self.config.man_pages:
            self.warn('no "man_pages" config value nor manual section found; no manual pages '
                      'will be written')
            return

        self.info(bold('writing man pages ... '), nonl=True)

        for man_parent in man_nodes:

            doc_tree = self.get_partial_document(man_parent)
            Section2Manpage(doc_tree).apply()

            if not doc_tree.man_info["authors"] and self.config.author:
                doc_tree.man_info["authors"].append(self.config.author)

            doc_writer   = ManualPageWriter(self)
            doc_settings = OptionParser(
                defaults            = self.env.settings
                , components        = (doc_writer,)
                , read_config_files = True
                , ).get_default_values()

            doc_settings.__dict__.update(doc_tree.man_info)
            doc_tree.settings = doc_settings
            targetname  = '%s.%s' % (doc_tree.man_info.title, doc_tree.man_info.section)
            if doc_tree.man_info.decl_type in [
                    "struct", "enum", "union", "typedef"]:
                targetname = "%s_%s" % (doc_tree.man_info.decl_type, targetname)

            destination = FileOutput(
                destination_path = path.join(self.outdir, targetname)
                , encoding='utf-8')

            self.info(darkgreen(targetname) + " ", nonl=True)
            self.env.resolve_references(doc_tree, doc_tree.man_info.manpage, self)

            # remove pending_xref nodes
            for pendingnode in doc_tree.traverse(addnodes.pending_xref):
                pendingnode.replace_self(pendingnode.children)
            doc_writer.write(doc_tree, destination)
        self.info()
Example #18
0
    def write(self, *ignored):
        docnames = self.env.all_docs

        self.info(bold('preparing documents... '), nonl=True)
        self.prepare_writing(docnames)
        self.info('done')

        self.info(bold('assembling single document... '), nonl=True)
        doctree = self.assemble_doctree()
        self.info()
        self.info(bold('writing... '), nonl=True)
        self.write_doc(self.config.master_doc, doctree)
        self.info('done')
Example #19
0
    def finish(self):
        # type: () -> None
        self.copy_image_files()
        self.write_message_catalog()

        # copy TeX support files from texinputs
        # configure usage of xindy (impacts Makefile and latexmkrc)
        # FIXME: convert this rather to a confval with suitable default
        #        according to language ? but would require extra documentation
        if self.config.language:
            xindy_lang_option = \
                XINDY_LANG_OPTIONS.get(self.config.language[:2],
                                       '-L general -C utf8 ')
            xindy_cyrillic = self.config.language[:2] in XINDY_CYRILLIC_SCRIPTS
        else:
            xindy_lang_option = '-L english -C utf8 '
            xindy_cyrillic = False
        context = {
            'latex_engine':      self.config.latex_engine,
            'xindy_use':         self.config.latex_use_xindy,
            'xindy_lang_option': xindy_lang_option,
            'xindy_cyrillic':    xindy_cyrillic,
        }
        logger.info(bold(__('copying TeX support files...')))
        staticdirname = path.join(package_dir, 'texinputs')
        for filename in os.listdir(staticdirname):
            if not filename.startswith('.'):
                copy_asset_file(path.join(staticdirname, filename),
                                self.outdir, context=context)

        # use pre-1.6.x Makefile for make latexpdf on Windows
        if os.name == 'nt':
            staticdirname = path.join(package_dir, 'texinputs_win')
            copy_asset_file(path.join(staticdirname, 'Makefile_t'),
                            self.outdir, context=context)

        # copy additional files
        if self.config.latex_additional_files:
            logger.info(bold(__('copying additional files...')), nonl=1)
            for filename in self.config.latex_additional_files:
                logger.info(' ' + filename, nonl=1)
                copy_asset_file(path.join(self.confdir, filename), self.outdir)
            logger.info('')

        # the logo is handled differently
        if self.config.latex_logo:
            if not path.isfile(path.join(self.confdir, self.config.latex_logo)):
                raise SphinxError(__('logo file %r does not exist') % self.config.latex_logo)
            else:
                copy_asset_file(path.join(self.confdir, self.config.latex_logo), self.outdir)
        logger.info(__('done'))
Example #20
0
    def write(self, *ignored):
        docnames = self.env.all_docs

        self.info(bold('preparing documents... '), nonl=True)
        self.prepare_writing(docnames)
        self.info('done')

        self.info(bold('assembling single document... '), nonl=True)
        doctree = self.assemble_doctree()
        doctree.settings = self.docsettings

        self.env.toc_secnumbers = self.assemble_toc_secnumbers()
        self.secnumbers = self.env.toc_secnumbers.get(self.config.master_doc,
                                                      {})
        self.fignumbers = self.env.toc_fignumbers.get(self.config.master_doc,
                                                      {})

        target_uri = self.get_target_uri(self.config.master_doc)
        self.imgpath = relative_uri(target_uri, '_images')
        self.dlpath = relative_uri(target_uri, '_downloads')
        self.current_docname = self.config.master_doc

        if self.should_submit:
            self.post_process_images(doctree)

        meta = self.env.metadata.get(self.config.master_doc)

        title = self.env.longtitles.get(self.config.master_doc)
        toc = self.env.get_toctree_for(self.config.master_doc, self, False)

        self.fix_refuris(toc)

        rendered_title = self.render_partial(title)['title']
        rendered_toc = self.render_partial(toc)['fragment']
        layout_key = meta.get('deconstlayout',
                              self.config.deconst_default_layout)

        rendered_body = self.write_body(doctree)

        envelope = {
            "title": meta.get('deconsttitle', rendered_title),
            "body": rendered_body,
            "toc": rendered_toc,
            "layout_key": layout_key,
            "meta": dict(meta)
        }

        outfile = os.path.join(self.outdir, self.config.master_doc + '.json')

        with open(outfile, 'w', encoding="utf-8") as dumpfile:
            json.dump(envelope, dumpfile)
Example #21
0
    def write(self, *ignored):
        docnames = self.env.all_docs

        self.info(bold("preparing documents... "), nonl=True)
        self.prepare_writing(docnames)
        self.info("done")

        self.info(bold("assembling single document... "), nonl=True)
        doctree = self.assemble_doctree()
        self.info()
        self.info(bold("writing... "), nonl=True)
        self.write_doc_serialized(self.config.master_doc, doctree)
        self.write_doc(self.config.master_doc, doctree)
        self.info("done")
    def write(self, *ignored):
        docnames = self.env.all_docs

        self.info(bold('preparing documents... '), nonl=True)
        self.prepare_writing(docnames)
        self.info('done')

        self.info(bold('assembling single document... '), nonl=True)
        doctree = self.assemble_doctree()
        self.info()
        self.info(bold('writing... '), nonl=True)
        docname = "%s-%s" % (self.config.project, self.config.version)
        self.write_doc(docname, doctree)
        self.info('done')
Example #23
0
def print_success(fields):
    print 
    print bold('Finished: Initial manuscript files created in directory \n%s.' % os.path.abspath(fields['path']))
    print
    if fields['novel'] is True:
        print 'You should now begin adding material to your chapter .txt files.'
        print 'To add new chapters or change their filenames, edit %s.txt.' % fields['master_doc']
    else:
        print 'You should now begin adding material to %s.txt.' % fields['master_doc']
    print 'To generate PDF, run the command ' + bold('make sffmspdf') + ' in the directory.'
    print 'Happy writing!'
    print 
    
    
Example #24
0
    def _write_parallel(self, docnames, nproc):
        # type: (Sequence[unicode], int) -> None
        def write_process(docs):
            # type: (List[Tuple[unicode, nodes.Node]]) -> None
            self.app.phase = BuildPhase.WRITING
            for docname, doctree in docs:
                self.write_doc(docname, doctree)

        # warm up caches/compile templates using the first document
        firstname, docnames = docnames[0], docnames[1:]
        self.app.phase = BuildPhase.RESOLVING
        doctree = self.env.get_and_resolve_doctree(firstname, self)
        self.app.phase = BuildPhase.WRITING
        self.write_doc_serialized(firstname, doctree)
        self.write_doc(firstname, doctree)

        tasks = ParallelTasks(nproc)
        chunks = make_chunks(docnames, nproc)

        self.app.phase = BuildPhase.RESOLVING
        for chunk in status_iterator(chunks, __('writing output... '), "darkgreen",
                                     len(chunks), self.app.verbosity):
            arg = []
            for i, docname in enumerate(chunk):
                doctree = self.env.get_and_resolve_doctree(docname, self)
                self.write_doc_serialized(docname, doctree)
                arg.append((docname, doctree))
            tasks.add_task(write_process, arg)

        # make sure all threads have finished
        logger.info(bold(__('waiting for workers...')))
        tasks.join()
Example #25
0
    def _read_parallel(self, docnames, nproc):
        # type: (List[unicode], int) -> None
        # clear all outdated docs at once
        for docname in docnames:
            self.app.emit('env-purge-doc', self.env, docname)
            self.env.clear_doc(docname)

        def read_process(docs):
            # type: (List[unicode]) -> bytes
            self.env.app = self.app
            for docname in docs:
                self.read_doc(docname)
            # allow pickling self to send it back
            return pickle.dumps(self.env, pickle.HIGHEST_PROTOCOL)

        def merge(docs, otherenv):
            # type: (List[unicode], bytes) -> None
            env = pickle.loads(otherenv)
            self.env.merge_info_from(docs, env, self.app)

        tasks = ParallelTasks(nproc)
        chunks = make_chunks(docnames, nproc)

        for chunk in status_iterator(chunks, 'reading sources... ', "purple",
                                     len(chunks), self.app.verbosity):
            tasks.add_task(read_process, chunk, merge)

        # make sure all threads have finished
        logger.info(bold('waiting for workers...'))
        tasks.join()
Example #26
0
    def write(self, build_docnames, updated_docnames, method='update'):
        # type: (Iterable[unicode], Sequence[unicode], unicode) -> None
        if build_docnames is None or build_docnames == ['__all__']:
            # build_all
            build_docnames = self.env.found_docs
        if method == 'update':
            # build updated ones as well
            docnames = set(build_docnames) | set(updated_docnames)
        else:
            docnames = set(build_docnames)
        logger.debug(__('docnames to write: %s'), ', '.join(sorted(docnames)))

        # add all toctree-containing files that may have changed
        for docname in list(docnames):
            for tocdocname in self.env.files_to_rebuild.get(docname, set()):
                if tocdocname in self.env.found_docs:
                    docnames.add(tocdocname)
        docnames.add(self.config.master_doc)

        logger.info(bold(__('preparing documents... ')), nonl=True)
        self.prepare_writing(docnames)
        logger.info(__('done'))

        if self.parallel_ok:
            # number of subprocesses is parallel-1 because the main process
            # is busy loading doctrees and doing write_doc_serialized()
            self._write_parallel(sorted(docnames),
                                 nproc=self.app.parallel - 1)
        else:
            self._write_serial(sorted(docnames))
Example #27
0
    def write(self, build_docnames, updated_docnames, method="update"):
        if build_docnames is None or build_docnames == ["__all__"]:
            # build_all
            build_docnames = self.env.found_docs
        if method == "update":
            # build updated ones as well
            docnames = set(build_docnames) | set(updated_docnames)
        else:
            docnames = set(build_docnames)

        # add all toctree-containing files that may have changed
        for docname in list(docnames):
            for tocdocname in self.env.files_to_rebuild.get(docname, []):
                if tocdocname in self.env.found_docs:
                    docnames.add(tocdocname)
        docnames.add(self.config.master_doc)

        self.info(bold("preparing documents... "), nonl=True)
        self.prepare_writing(docnames)
        self.info("done")

        warnings = []
        self.env.set_warnfunc(lambda *args: warnings.append(args))
        # check for prerequisites to parallel build
        # (parallel only works on POSIX, because the forking impl of
        # multiprocessing is required)
        if not (multiprocessing and self.app.parallel > 1 and self.allow_parallel and os.name == "posix"):
            self._write_serial(sorted(docnames), warnings)
        else:
            # number of subprocesses is parallel-1 because the main process
            # is busy loading doctrees and doing write_doc_serialized()
            self._write_parallel(sorted(docnames), warnings, nproc=self.app.parallel - 1)
        self.env.set_warnfunc(self.warn)
Example #28
0
    def _init_env(self, freshenv):
        if freshenv:
            self.env = BuildEnvironment(self.srcdir, self.doctreedir,
                                        self.config)
            self.env.find_files(self.config)
            for domain in self.domains.keys():
                self.env.domains[domain] = self.domains[domain](self.env)
        else:
            try:
                self.info(bold('loading pickled environment... '), nonl=True)
                self.env = BuildEnvironment.frompickle(self.config,
                    path.join(self.doctreedir, ENV_PICKLE_FILENAME))
                self.env.domains = {}
                for domain in self.domains.keys():
                    # this can raise if the data version doesn't fit
                    self.env.domains[domain] = self.domains[domain](self.env)
                self.info('done')
            except Exception as err:
                if type(err) is IOError and err.errno == ENOENT:
                    self.info('not yet created')
                else:
                    self.info('failed: %s' % err)
                return self._init_env(freshenv=True)

        self.env.set_warnfunc(self.warn)
Example #29
0
    def write(self, *ignored):
        # build_all
        docnames = set([doc for doc in self.env.found_docs if doc.startswith("stdlib")])

        self.info(bold('preparing documents... '), nonl=True)
        self.prepare_writing(docnames)
        self.info('done')

        # write target files
        warnings = []
        self.env.set_warnfunc(lambda *args: warnings.append(args))

        outfilename = path.join(self.outdir, self.name + self.out_suffix)
        ensuredir(path.dirname(outfilename))
        try:
            f = codecs.open(outfilename, 'w', 'utf-8')
            try:
                f.write('# automatically generated from files in doc/stdlib/ -- do not edit here\n\n' +
                        '{\n\n')

                for docname in self.status_iterator(
                    sorted(docnames), 'processing... ', darkgreen, len(docnames)):
                    doctree = self.env.get_and_resolve_doctree(docname, self)
                    self.writer.write(doctree, f)
                    f.write("\n")

                f.write('\n}\n')
            finally:
                f.close()
        except (IOError, OSError) as err:
            self.warn("error writing file %s: %s" % (outfilename, err))

        for warning in warnings:
            self.warn(*warning)
        self.env.set_warnfunc(self.warn)
Example #30
0
 def copy_static_readthedocs_files(self):
     log.info(bold('copying readthedocs static files... '), nonl=True)
     for filename in self.static_readthedocs_files:
         path_dest = os.path.join(self.outdir, '_static')
         path_src = os.path.join(
             os.path.abspath(os.path.dirname(__file__)),
             '_static',
             filename
         )
         ctx = self.get_static_readthedocs_context()
         if sphinx.version_info < (1, 5):
             copy_static_entry(
                 path_src,
                 path_dest,
                 self,
                 context=ctx,
             )
         else:
             copy_asset(
                 path_src,
                 path_dest,
                 context=ctx,
                 renderer=self.templates
             )
     log.info('done')
Example #31
0
def generate(d: Dict,
             overwrite: bool = True,
             silent: bool = False,
             templatedir: str = None) -> None:
    """Generate project based on values in *d*."""
    template = QuickstartRenderer(templatedir=templatedir)

    if 'mastertoctree' not in d:
        d['mastertoctree'] = ''
    if 'mastertocmaxdepth' not in d:
        d['mastertocmaxdepth'] = 2

    d['root_doc'] = d['master']
    d['now'] = time.asctime()
    d['project_underline'] = column_width(d['project']) * '='
    d.setdefault('extensions', [])
    d['copyright'] = time.strftime('%Y') + ', ' + d['author']

    d["path"] = os.path.abspath(d['path'])
    ensuredir(d['path'])

    srcdir = path.join(d['path'], 'source') if d['sep'] else d['path']

    ensuredir(srcdir)
    if d['sep']:
        builddir = path.join(d['path'], 'build')
        d['exclude_patterns'] = ''
    else:
        builddir = path.join(srcdir, d['dot'] + 'build')
        exclude_patterns = map(repr, [
            d['dot'] + 'build',
            'Thumbs.db',
            '.DS_Store',
        ])
        d['exclude_patterns'] = ', '.join(exclude_patterns)
    ensuredir(builddir)
    ensuredir(path.join(srcdir, d['dot'] + 'templates'))
    ensuredir(path.join(srcdir, d['dot'] + 'static'))

    def write_file(fpath: str, content: str, newline: str = None) -> None:
        if overwrite or not path.isfile(fpath):
            if 'quiet' not in d:
                print(__('Creating file %s.') % fpath)
            with open(fpath, 'wt', encoding='utf-8', newline=newline) as f:
                f.write(content)
        else:
            if 'quiet' not in d:
                print(__('File %s already exists, skipping.') % fpath)

    conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None
    if not conf_path or not path.isfile(conf_path):
        conf_path = os.path.join(package_dir, 'templates', 'quickstart',
                                 'conf.py_t')
    with open(conf_path) as f:
        conf_text = f.read()

    write_file(path.join(srcdir, 'conf.py'),
               template.render_string(conf_text, d))

    masterfile = path.join(srcdir, d['master'] + d['suffix'])
    if template._has_custom_template('quickstart/master_doc.rst_t'):
        msg = (
            'A custom template `master_doc.rst_t` found. It has been renamed to '
            '`root_doc.rst_t`.  Please rename it on your project too.')
        print(colorize('red', msg))  # RemovedInSphinx60Warning
        write_file(masterfile, template.render('quickstart/master_doc.rst_t',
                                               d))
    else:
        write_file(masterfile, template.render('quickstart/root_doc.rst_t', d))

    if d.get('make_mode') is True:
        makefile_template = 'quickstart/Makefile.new_t'
        batchfile_template = 'quickstart/make.bat.new_t'
    else:
        makefile_template = 'quickstart/Makefile_t'
        batchfile_template = 'quickstart/make.bat_t'

    if d['makefile'] is True:
        d['rsrcdir'] = 'source' if d['sep'] else '.'
        d['rbuilddir'] = 'build' if d['sep'] else d['dot'] + 'build'
        # use binary mode, to avoid writing \r\n on Windows
        write_file(path.join(d['path'], 'Makefile'),
                   template.render(makefile_template, d), '\n')

    if d['batchfile'] is True:
        d['rsrcdir'] = 'source' if d['sep'] else '.'
        d['rbuilddir'] = 'build' if d['sep'] else d['dot'] + 'build'
        write_file(path.join(d['path'], 'make.bat'),
                   template.render(batchfile_template, d), '\r\n')

    if silent:
        return
    print()
    print(
        bold(__('Finished: An initial directory structure has been created.')))
    print()
    print(__(
        'You should now populate your master file %s and create other documentation\n'
        'source files. ') % masterfile,
          end='')
    if d['makefile'] or d['batchfile']:
        print(
            __('Use the Makefile to build the docs, like so:\n'
               '   make builder'))
    else:
        print(
            __('Use the sphinx-build command to build the docs, like so:\n'
               '   sphinx-build -b builder %s %s') % (srcdir, builddir))
    print(
        __('where "builder" is one of the supported builders, '
           'e.g. html, latex or linkcheck.'))
    print()
Example #32
0
 def set_translator(self, name, translator_class):
     self.info(bold('A Translator for the %s builder is changed.' % name))
     self._translators[name] = translator_class
Example #33
0
    def __init__(self,
                 srcdir,
                 confdir,
                 outdir,
                 doctreedir,
                 buildername,
                 confoverrides=None,
                 status=sys.stdout,
                 warning=sys.stderr,
                 freshenv=False,
                 warningiserror=False,
                 tags=None,
                 verbosity=0,
                 parallel=0):
        self.verbosity = verbosity
        self.next_listener_id = 0
        self._extensions = {}
        self._extension_metadata = {}
        self._additional_source_parsers = {}
        self._listeners = {}
        self._setting_up_extension = ['?']
        self.domains = {}
        self.buildername = buildername
        self.builderclasses = {}
        self.builder = None
        self.env = None
        self.enumerable_nodes = {}

        self.srcdir = srcdir
        self.confdir = confdir
        self.outdir = outdir
        self.doctreedir = doctreedir

        self.parallel = parallel

        if status is None:
            self._status = cStringIO()
            self.quiet = True
        else:
            self._status = status
            self.quiet = False

        if warning is None:
            self._warning = cStringIO()
        else:
            self._warning = warning
        self._warncount = 0
        self.warningiserror = warningiserror

        self._events = events.copy()
        self._translators = {}

        # keep last few messages for traceback
        self.messagelog = deque(maxlen=10)

        # say hello to the world
        self.info(bold('Running Sphinx v%s' % sphinx.__display_version__))

        # status code for command-line application
        self.statuscode = 0

        if not path.isdir(outdir):
            self.info('making output directory...')
            os.makedirs(outdir)

        # read config
        self.tags = Tags(tags)
        self.config = Config(confdir, CONFIG_FILENAME, confoverrides or {},
                             self.tags)
        self.config.check_unicode(self.warn)
        # defer checking types until i18n has been initialized

        # initialize some limited config variables before loading extensions
        self.config.pre_init_values(self.warn)

        # check the Sphinx version if requested
        if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
            raise VersionRequirementError(
                'This project needs at least Sphinx v%s and therefore cannot '
                'be built with this version.' % self.config.needs_sphinx)

        # force preload html_translator_class
        if self.config.html_translator_class:
            translator_class = self.import_object(
                self.config.html_translator_class,
                'html_translator_class setting')
            self.set_translator('html', translator_class)

        # set confdir to srcdir if -C given (!= no confdir); a few pieces
        # of code expect a confdir to be set
        if self.confdir is None:
            self.confdir = self.srcdir

        # load all built-in extension modules
        for extension in builtin_extensions:
            self.setup_extension(extension)

        # extension loading support for alabaster theme
        # self.config.html_theme is not set from conf.py at here
        # for now, sphinx always load a 'alabaster' extension.
        if 'alabaster' not in self.config.extensions:
            self.config.extensions.append('alabaster')

        # load all user-given extension modules
        for extension in self.config.extensions:
            self.setup_extension(extension)
        # the config file itself can be an extension
        if self.config.setup:
            self._setting_up_extension = ['conf.py']
            # py31 doesn't have 'callable' function for below check
            if hasattr(self.config.setup, '__call__'):
                self.config.setup(self)
            else:
                raise ConfigError(
                    "'setup' that is specified in the conf.py has not been " +
                    "callable. Please provide a callable `setup` function " +
                    "in order to behave as a sphinx extension conf.py itself.")

        # now that we know all config values, collect them from conf.py
        self.config.init_values(self.warn)

        # check extension versions if requested
        if self.config.needs_extensions:
            for extname, needs_ver in self.config.needs_extensions.items():
                if extname not in self._extensions:
                    self.warn(
                        'needs_extensions config value specifies a '
                        'version requirement for extension %s, but it is '
                        'not loaded' % extname)
                    continue
                has_ver = self._extension_metadata[extname]['version']
                if has_ver == 'unknown version' or needs_ver > has_ver:
                    raise VersionRequirementError(
                        'This project needs the extension %s at least in '
                        'version %s and therefore cannot be built with the '
                        'loaded version (%s).' % (extname, needs_ver, has_ver))

        # check primary_domain if requested
        if self.config.primary_domain and self.config.primary_domain not in self.domains:
            self.warn('primary_domain %r not found, ignored.' %
                      self.config.primary_domain)

        # set up translation infrastructure
        self._init_i18n()
        # check all configuration values for permissible types
        self.config.check_types(self.warn)
        # set up source_parsers
        self._init_source_parsers()
        # set up the build environment
        self._init_env(freshenv)
        # set up the builder
        self._init_builder(self.buildername)
        # set up the enumerable nodes
        self._init_enumerable_nodes()
Example #34
0
def generate(d, overwrite=True, silent=False, templatedir=None):
    # type: (Dict, bool, bool, unicode) -> None
    """Generate project based on values in *d*."""
    template = QuickstartRenderer(templatedir=templatedir)

    texescape.init()

    if 'mastertoctree' not in d:
        d['mastertoctree'] = ''
    if 'mastertocmaxdepth' not in d:
        d['mastertocmaxdepth'] = 2

    d['PY3'] = True
    d['project_fn'] = make_filename(d['project'])
    d['project_url'] = quote(d['project'].encode('idna'))
    d['project_manpage'] = d['project_fn'].lower()
    d['now'] = time.asctime()
    d['project_underline'] = column_width(d['project']) * '='
    d.setdefault('extensions', [])
    d['copyright'] = time.strftime('%Y') + ', ' + d['author']
    d['author_texescaped'] = text_type(d['author']).\
        translate(texescape.tex_escape_map)
    d['project_doc'] = d['project'] + ' Documentation'
    d['project_doc_texescaped'] = text_type(d['project'] + ' Documentation').\
        translate(texescape.tex_escape_map)

    # escape backslashes and single quotes in strings that are put into
    # a Python string literal
    for key in ('project', 'project_doc', 'project_doc_texescaped', 'author',
                'author_texescaped', 'copyright', 'version', 'release',
                'master'):
        d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'")

    if not path.isdir(d['path']):
        ensuredir(d['path'])

    srcdir = d['sep'] and path.join(d['path'], 'source') or d['path']

    ensuredir(srcdir)
    if d['sep']:
        builddir = path.join(d['path'], 'build')
        d['exclude_patterns'] = ''
    else:
        builddir = path.join(srcdir, d['dot'] + 'build')
        exclude_patterns = map(repr, [
            d['dot'] + 'build',
            'Thumbs.db',
            '.DS_Store',
        ])
        d['exclude_patterns'] = ', '.join(exclude_patterns)
    ensuredir(builddir)
    ensuredir(path.join(srcdir, d['dot'] + 'templates'))
    ensuredir(path.join(srcdir, d['dot'] + 'static'))

    def write_file(fpath, content, newline=None):
        # type: (unicode, unicode, unicode) -> None
        if overwrite or not path.isfile(fpath):
            if 'quiet' not in d:
                print(__('Creating file %s.') % fpath)
            with open(fpath, 'wt', encoding='utf-8',
                      newline=newline) as f:  # type: ignore
                f.write(content)
        else:
            if 'quiet' not in d:
                print(__('File %s already exists, skipping.') % fpath)

    conf_path = os.path.join(templatedir, 'conf.py_t') if templatedir else None
    if not conf_path or not path.isfile(conf_path):
        conf_path = os.path.join(package_dir, 'templates', 'quickstart',
                                 'conf.py_t')
    with open(conf_path) as f:
        conf_text = f.read()

    write_file(path.join(srcdir, 'conf.py'),
               template.render_string(conf_text, d))

    masterfile = path.join(srcdir, d['master'] + d['suffix'])
    write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))

    if d.get('make_mode') is True:
        makefile_template = 'quickstart/Makefile.new_t'
        batchfile_template = 'quickstart/make.bat.new_t'
    else:
        makefile_template = 'quickstart/Makefile_t'
        batchfile_template = 'quickstart/make.bat_t'

    if d['makefile'] is True:
        d['rsrcdir'] = d['sep'] and 'source' or '.'
        d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
        # use binary mode, to avoid writing \r\n on Windows
        write_file(path.join(d['path'], 'Makefile'),
                   template.render(makefile_template, d), u'\n')

    if d['batchfile'] is True:
        d['rsrcdir'] = d['sep'] and 'source' or '.'
        d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
        write_file(path.join(d['path'], 'make.bat'),
                   template.render(batchfile_template, d), u'\r\n')

    if silent:
        return
    print()
    print(
        bold(__('Finished: An initial directory structure has been created.')))
    print(
        __('''
You should now populate your master file %s and create other documentation
source files. ''') % masterfile +
        ((d['makefile'] or d['batchfile']) and __('''\
Use the Makefile to build the docs, like so:
   make builder
''') or __('''\
Use the sphinx-build command to build the docs, like so:
   sphinx-build -b builder %s %s
''') % (srcdir, builddir)) + __('''\
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.
'''))
Example #35
0
def ask_user(d):
    # type: (Dict) -> None
    """Ask the user for quickstart values missing from *d*.

    Values are:

    * path:      root path
    * sep:       separate source and build dirs (bool)
    * dot:       replacement for dot in _templates etc.
    * project:   project name
    * author:    author names
    * version:   version of project
    * release:   release of project
    * language:  document language
    * suffix:    source file suffix
    * master:    master document name
    * extensions:  extensions to use (list)
    * makefile:  make Makefile
    * batchfile: make command file
    """

    print(
        bold(__('Welcome to the Sphinx %s quickstart utility.')) %
        __display_version__)
    print(
        __('''
Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).'''))

    if 'path' in d:
        print(bold(__('''
Selected root path: %s''') % d['path']))
    else:
        print(__('''
Enter the root path for documentation.'''))
        d['path'] = do_prompt(__('Root path for the documentation'), '.',
                              is_path)

    while path.isfile(path.join(d['path'], 'conf.py')) or \
            path.isfile(path.join(d['path'], 'source', 'conf.py')):
        print()
        print(
            bold(
                __('Error: an existing conf.py has been found in the '
                   'selected root path.')))
        print(
            __('sphinx-quickstart will not overwrite existing Sphinx projects.'
               ))
        print()
        d['path'] = do_prompt(
            __('Please enter a new root path (or just Enter '
               'to exit)'), '', is_path)
        if not d['path']:
            sys.exit(1)

    if 'sep' not in d:
        print(
            __('''
You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.'''))
        d['sep'] = do_prompt(__('Separate source and build directories (y/n)'),
                             'n', boolean)

    if 'dot' not in d:
        print(
            __('''
Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.'''
               ))
        d['dot'] = do_prompt(__('Name prefix for templates and static dir'),
                             '_', ok)

    if 'project' not in d:
        print(
            __('''
The project name will occur in several places in the built documentation.'''))
        d['project'] = do_prompt(__('Project name'))
    if 'author' not in d:
        d['author'] = do_prompt(__('Author name(s)'))

    if 'version' not in d:
        print(
            __('''
Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
just set both to the same value.'''))
        d['version'] = do_prompt(__('Project version'), '', allow_empty)
    if 'release' not in d:
        d['release'] = do_prompt(__('Project release'), d['version'],
                                 allow_empty)

    if 'language' not in d:
        print(
            __('''
If the documents are to be written in a language other than English,
you can select a language here by its language code. Sphinx will then
translate text that it generates into that language.

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.'''))
        d['language'] = do_prompt(__('Project language'), 'en')
        if d['language'] == 'en':
            d['language'] = None

    if 'suffix' not in d:
        print(
            __('''
The file name suffix for source files. Commonly, this is either ".txt"
or ".rst".  Only files with this suffix are considered documents.'''))
        d['suffix'] = do_prompt(__('Source file suffix'), '.rst', suffix)

    if 'master' not in d:
        print(
            __('''
One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
document is a custom template, you can also set this to another filename.'''))
        d['master'] = do_prompt(
            __('Name of your master document (without suffix)'), 'index')

    while path.isfile(path.join(d['path'], d['master'] + d['suffix'])) or \
            path.isfile(path.join(d['path'], 'source', d['master'] + d['suffix'])):
        print()
        print(
            bold(
                __('Error: the master file %s has already been found in the '
                   'selected root path.') % (d['master'] + d['suffix'])))
        print(__('sphinx-quickstart will not overwrite the existing file.'))
        print()
        d['master'] = do_prompt(
            __('Please enter a new file name, or rename the '
               'existing file and press Enter'), d['master'])

    if 'extensions' not in d:
        print(
            __('Indicate which of the following Sphinx extensions should be '
               'enabled:'))
        d['extensions'] = []
        for name, description in EXTENSIONS.items():
            if do_prompt('%s: %s (y/n)' % (name, description), 'n', boolean):
                d['extensions'].append('sphinx.ext.%s' % name)

        # Handle conflicting options
        if set(['sphinx.ext.imgmath',
                'sphinx.ext.mathjax']).issubset(d['extensions']):
            print(
                __('Note: imgmath and mathjax cannot be enabled at the same '
                   'time. imgmath has been deselected.'))
            d['extensions'].remove('sphinx.ext.imgmath')

    if 'makefile' not in d:
        print(
            __('''
A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.'''))
        d['makefile'] = do_prompt(__('Create Makefile? (y/n)'), 'y', boolean)

    if 'batchfile' not in d:
        d['batchfile'] = do_prompt(__('Create Windows command file? (y/n)'),
                                   'y', boolean)
    print()
Example #36
0
def main(argv=sys.argv[1:]):
    # type: (List[str]) -> int
    locale.setlocale(locale.LC_ALL, '')
    sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx')

    if not color_terminal():
        nocolor()

    # parse options
    parser = get_parser()
    try:
        args = parser.parse_args(argv)
    except SystemExit as err:
        return err.code

    d = vars(args)
    # delete None or False value
    d = dict((k, v) for k, v in d.items() if v is not None)

    try:
        if 'quiet' in d:
            if not set(['project', 'author']).issubset(d):
                print(
                    __('''"quiet" is specified, but any of "project" or \
"author" is not specified.'''))
                return 1

        if set(['quiet', 'project', 'author']).issubset(d):
            # quiet mode with all required params satisfied, use default
            d.setdefault('version', '')
            d.setdefault('release', d['version'])
            d2 = DEFAULTS.copy()
            d2.update(d)
            d = d2

            if not valid_dir(d):
                print()
                print(
                    bold(
                        __('Error: specified path is not a directory, or sphinx'
                           ' files already exist.')))
                print(
                    __('sphinx-quickstart only generate into a empty directory.'
                       ' Please specify a new root path.'))
                return 1
        else:
            ask_user(d)
    except (KeyboardInterrupt, EOFError):
        print()
        print('[Interrupted.]')
        return 130  # 128 + SIGINT

    # handle use of CSV-style extension values
    d.setdefault('extensions', [])
    for ext in d['extensions'][:]:
        if ',' in ext:
            d['extensions'].remove(ext)
            d['extensions'].extend(ext.split(','))

    for variable in d.get('variables', []):
        try:
            name, value = variable.split('=')
            d[name] = value
        except ValueError:
            print(__('Invalid template variable: %s') % variable)

    generate(d, overwrite=False, templatedir=args.templatedir)
    return 0
Example #37
0
    def write(self, *ignored):
        version = self.config.version
        libchanges = {}
        apichanges = []
        otherchanges = {}
        if version not in self.env.versionchanges:
            self.info(bold('no changes in version %s.' % version))
            return
        self.info(bold('writing summary file...'))
        for type, docname, lineno, module, descname, content in \
                self.env.versionchanges[version]:
            if isinstance(descname, tuple):
                descname = descname[0]
            ttext = self.typemap[type]
            context = content.replace('\n', ' ')
            if descname and docname.startswith('c-api'):
                if not descname:
                    continue
                if context:
                    entry = '<b>%s</b>: <i>%s:</i> %s' % (descname, ttext,
                                                          context)
                else:
                    entry = '<b>%s</b>: <i>%s</i>.' % (descname, ttext)
                apichanges.append((entry, docname, lineno))
            elif descname or module:
                if not module:
                    module = _('Builtins')
                if not descname:
                    descname = _('Module level')
                if context:
                    entry = '<b>%s</b>: <i>%s:</i> %s' % (descname, ttext,
                                                          context)
                else:
                    entry = '<b>%s</b>: <i>%s</i>.' % (descname, ttext)
                libchanges.setdefault(module, []).append(
                    (entry, docname, lineno))
            else:
                if not context:
                    continue
                entry = '<i>%s:</i> %s' % (ttext.capitalize(), context)
                title = self.env.titles[docname].astext()
                otherchanges.setdefault((docname, title), []).append(
                    (entry, docname, lineno))

        ctx = {
            'project': self.config.project,
            'version': version,
            'docstitle': self.config.html_title,
            'shorttitle': self.config.html_short_title,
            'libchanges': sorted(libchanges.iteritems()),
            'apichanges': sorted(apichanges),
            'otherchanges': sorted(otherchanges.iteritems()),
            'show_sphinx': self.config.html_show_sphinx,
        }
        f = codecs.open(path.join(self.outdir, 'index.html'), 'w', 'utf8')
        try:
            f.write(self.templates.render('changes/frameset.html', ctx))
        finally:
            f.close()
        f = codecs.open(path.join(self.outdir, 'changes.html'), 'w', 'utf8')
        try:
            f.write(self.templates.render('changes/versionchanges.html', ctx))
        finally:
            f.close()

        hltext = [
            '.. versionadded:: %s' % version,
            '.. versionchanged:: %s' % version,
            '.. deprecated:: %s' % version
        ]

        def hl(no, line):
            line = '<a name="L%s"> </a>' % no + escape(line)
            for x in hltext:
                if x in line:
                    line = '<span class="hl">%s</span>' % line
                    break
            return line

        self.info(bold('copying source files...'))
        for docname in self.env.all_docs:
            f = codecs.open(self.env.doc2path(docname), 'r', 'latin1')
            lines = f.readlines()
            targetfn = path.join(self.outdir, 'rst',
                                 os_path(docname)) + '.html'
            ensuredir(path.dirname(targetfn))
            f = codecs.open(targetfn, 'w', 'latin1')
            try:
                text = ''.join(
                    hl(i + 1, line) for (i, line) in enumerate(lines))
                ctx = {
                    'filename': self.env.doc2path(docname, None),
                    'text': text
                }
                f.write(self.templates.render('changes/rstsource.html', ctx))
            finally:
                f.close()
        themectx = dict(
            ('theme_' + key, val)
            for (key, val) in self.theme.get_options({}).iteritems())
        copy_static_entry(
            path.join(package_dir, 'themes', 'default',
                      'static', 'default.css_t'),
            path.join(self.outdir, 'default.css_t'), self, themectx)
        copy_static_entry(
            path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'),
            path.join(self.outdir, 'basic.css'), self)
Example #38
0
 def __enter__(self) -> None:
     logger.info(bold(self.message + '... '), nonl=True)
Example #39
0
    def build_helpbook(self):
        contents_dir = path.join(self.bundle_path, 'Contents')
        resources_dir = path.join(contents_dir, 'Resources')
        language_dir = path.join(resources_dir,
                                 self.config.applehelp_locale + '.lproj')

        for d in [contents_dir, resources_dir, language_dir]:
            ensuredir(d)

        # Construct the Info.plist file
        toc = self.config.master_doc + self.out_suffix

        info_plist = {
            'CFBundleDevelopmentRegion': self.config.applehelp_dev_region,
            'CFBundleIdentifier': self.config.applehelp_bundle_id,
            'CFBundleInfoDictionaryVersion': '6.0',
            'CFBundlePackageType': 'BNDL',
            'CFBundleShortVersionString': self.config.release,
            'CFBundleSignature': 'hbwr',
            'CFBundleVersion': self.config.applehelp_bundle_version,
            'HPDBookAccessPath': '_access.html',
            'HPDBookIndexPath': 'search.helpindex',
            'HPDBookTitle': self.config.applehelp_title,
            'HPDBookType': '3',
            'HPDBookUsesExternalViewer': False,
        }

        if self.config.applehelp_icon is not None:
            info_plist['HPDBookIconPath'] \
                = path.basename(self.config.applehelp_icon)

        if self.config.applehelp_kb_url is not None:
            info_plist['HPDBookKBProduct'] = self.config.applehelp_kb_product
            info_plist['HPDBookKBURL'] = self.config.applehelp_kb_url

        if self.config.applehelp_remote_url is not None:
            info_plist['HPDBookRemoteURL'] = self.config.applehelp_remote_url

        self.info(bold('writing Info.plist... '), nonl=True)
        with open(path.join(contents_dir, 'Info.plist'), 'wb') as f:
            write_plist(info_plist, f)
        self.info('done')

        # Copy the icon, if one is supplied
        if self.config.applehelp_icon:
            self.info(bold('copying icon... '), nonl=True)

            try:
                copyfile(
                    path.join(self.srcdir, self.config.applehelp_icon),
                    path.join(resources_dir, info_plist['HPDBookIconPath']))

                self.info('done')
            except Exception as err:
                self.warn(
                    'cannot copy icon file %r: %s' %
                    (path.join(self.srcdir, self.config.applehelp_icon), err))
                del info_plist['HPDBookIconPath']

        # Build the access page
        self.info(bold('building access page...'), nonl=True)
        f = codecs.open(path.join(language_dir, '_access.html'), 'w')
        try:
            f.write(
                access_page_template % {
                    'toc': htmlescape(toc, quote=True),
                    'title': htmlescape(self.config.applehelp_title)
                })
        finally:
            f.close()
        self.info('done')

        # Generate the help index
        self.info(bold('generating help index... '), nonl=True)

        args = [
            self.config.applehelp_indexer_path, '-Cf',
            path.join(language_dir, 'search.helpindex'), language_dir
        ]

        if self.config.applehelp_index_anchors is not None:
            args.append('-a')

        if self.config.applehelp_min_term_length is not None:
            args += ['-m', '%s' % self.config.applehelp_min_term_length]

        if self.config.applehelp_stopwords is not None:
            args += ['-s', self.config.applehelp_stopwords]

        if self.config.applehelp_locale is not None:
            args += ['-l', self.config.applehelp_locale]

        if self.config.applehelp_disable_external_tools:
            self.info('skipping')

            self.warn('you will need to index this help book with:\n  %s' %
                      (' '.join([pipes.quote(arg) for arg in args])))
        else:
            p = subprocess.Popen(args,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)

            output = p.communicate()[0]

            if p.returncode != 0:
                raise AppleHelpIndexerFailed(output)
            else:
                self.info('done')

        # If we've been asked to, sign the bundle
        if self.config.applehelp_codesign_identity:
            self.info(bold('signing help book... '), nonl=True)

            args = [
                self.config.applehelp_codesign_path, '-s',
                self.config.applehelp_codesign_identity, '-f'
            ]

            args += self.config.applehelp_codesign_flags

            args.append(self.bundle_path)

            if self.config.applehelp_disable_external_tools:
                self.info('skipping')

                self.warn('you will need to sign this help book with:\n  %s' %
                          (' '.join([pipes.quote(arg) for arg in args])))
            else:
                p = subprocess.Popen(args,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT)

                output = p.communicate()[0]

                if p.returncode != 0:
                    raise AppleHelpCodeSigningFailed(output)
                else:
                    self.info('done')
Example #40
0
def main(argv=sys.argv):
    if not color_terminal():
        nocolor()

    parser = optparse.OptionParser(USAGE,
                                   epilog=EPILOG,
                                   version='Sphinx v%s' % __display_version__,
                                   formatter=MyFormatter())
    parser.add_option('-q',
                      '--quiet',
                      action='store_true',
                      dest='quiet',
                      default=False,
                      help='quiet mode')

    group = parser.add_option_group('Structure options')
    group.add_option('--sep',
                     action='store_true',
                     dest='sep',
                     help='if specified, separate source and build dirs')
    group.add_option('--dot',
                     metavar='DOT',
                     dest='dot',
                     help='replacement for dot in _templates etc.')

    group = parser.add_option_group('Project basic options')
    group.add_option('-p',
                     '--project',
                     metavar='PROJECT',
                     dest='project',
                     help='project name')
    group.add_option('-a',
                     '--author',
                     metavar='AUTHOR',
                     dest='author',
                     help='author names')
    group.add_option('-v',
                     metavar='VERSION',
                     dest='version',
                     help='version of project')
    group.add_option('-r',
                     '--release',
                     metavar='RELEASE',
                     dest='release',
                     help='release of project')
    group.add_option('-l',
                     '--language',
                     metavar='LANGUAGE',
                     dest='language',
                     help='document language')
    group.add_option('--suffix',
                     metavar='SUFFIX',
                     dest='suffix',
                     help='source file suffix')
    group.add_option('--master',
                     metavar='MASTER',
                     dest='master',
                     help='master document name')
    group.add_option('--epub',
                     action='store_true',
                     dest='epub',
                     default=False,
                     help='use epub')

    group = parser.add_option_group('Extension options')
    for ext in EXTENSIONS:
        group.add_option('--ext-' + ext,
                         action='store_true',
                         dest='ext_' + ext,
                         default=False,
                         help='enable %s extension' % ext)

    group = parser.add_option_group('Makefile and Batchfile creation')
    group.add_option('--makefile',
                     action='store_true',
                     dest='makefile',
                     default=False,
                     help='create makefile')
    group.add_option('--no-makefile',
                     action='store_true',
                     dest='no_makefile',
                     default=False,
                     help='not create makefile')
    group.add_option('--batchfile',
                     action='store_true',
                     dest='batchfile',
                     default=False,
                     help='create batchfile')
    group.add_option('--no-batchfile',
                     action='store_true',
                     dest='no_batchfile',
                     default=False,
                     help='not create batchfile')
    group.add_option('-M',
                     '--no-use-make-mode',
                     action='store_false',
                     dest='make_mode',
                     help='not use make-mode for Makefile/make.bat')
    group.add_option('-m',
                     '--use-make-mode',
                     action='store_true',
                     dest='make_mode',
                     default=True,
                     help='use make-mode for Makefile/make.bat')

    # parse options
    try:
        opts, args = parser.parse_args(argv[1:])
    except SystemExit as err:
        return err.code

    if len(args) > 0:
        opts.ensure_value('path', args[0])

    d = vars(opts)
    # delete None or False value
    d = dict((k, v) for k, v in d.items() if not (v is None or v is False))

    try:
        if 'quiet' in d:
            if not set(['project', 'author']).issubset(d):
                print('''"quiet" is specified, but any of "project" or \
"author" is not specified.''')
                return 1

        if set(['quiet', 'project', 'author']).issubset(d):
            # quiet mode with all required params satisfied, use default
            d.setdefault('version', '')
            d.setdefault('release', d['version'])
            d2 = DEFAULT_VALUE.copy()
            d2.update(dict(("ext_" + ext, False) for ext in EXTENSIONS))
            d2.update(d)
            d = d2
            if 'no_makefile' in d:
                d['makefile'] = False
            if 'no_batchfile' in d:
                d['batchfile'] = False

            if not valid_dir(d):
                print()
                print(
                    bold('Error: specified path is not a directory, or sphinx'
                         ' files already exist.'))
                print('sphinx-quickstart only generate into a empty directory.'
                      ' Please specify a new root path.')
                return 1
        else:
            ask_user(d)
    except (KeyboardInterrupt, EOFError):
        print()
        print('[Interrupted.]')
        return 130  # 128 + SIGINT

    # decode values in d if value is a Python string literal
    for key, value in d.items():
        if isinstance(value, binary_type):
            d[key] = term_decode(value)

    generate(d)
    def __init__(self, srcdir: str, confdir: str, outdir: str, doctreedir: str,
                 buildername: str, confoverrides: Dict = None,
                 status: IO = sys.stdout, warning: IO = sys.stderr,
                 freshenv: bool = False, warningiserror: bool = False, tags: List[str] = None,
                 verbosity: int = 0, parallel: int = 0, keep_going: bool = False) -> None:
        self.phase = BuildPhase.INITIALIZATION
        self.verbosity = verbosity
        self.extensions = {}                    # type: Dict[str, Extension]
        self.builder = None                     # type: Builder
        self.env = None                         # type: BuildEnvironment
        self.project = None                     # type: Project
        self.registry = SphinxComponentRegistry()
        self.html_themes = {}                   # type: Dict[str, str]

        # validate provided directories
        self.srcdir = abspath(srcdir)
        self.outdir = abspath(outdir)
        self.doctreedir = abspath(doctreedir)
        self.confdir = confdir
        if self.confdir:  # confdir is optional
            self.confdir = abspath(self.confdir)
            if not path.isfile(path.join(self.confdir, 'conf.py')):
                raise ApplicationError(__("config directory doesn't contain a "
                                          "conf.py file (%s)") % confdir)

        if not path.isdir(self.srcdir):
            raise ApplicationError(__('Cannot find source directory (%s)') %
                                   self.srcdir)

        if path.exists(self.outdir) and not path.isdir(self.outdir):
            raise ApplicationError(__('Output directory (%s) is not a directory') %
                                   self.outdir)

        if self.srcdir == self.outdir:
            raise ApplicationError(__('Source directory and destination '
                                      'directory cannot be identical'))

        self.parallel = parallel

        if status is None:
            self._status = StringIO()      # type: IO
            self.quiet = True
        else:
            self._status = status
            self.quiet = False

        if warning is None:
            self._warning = StringIO()     # type: IO
        else:
            self._warning = warning
        self._warncount = 0
        self.keep_going = warningiserror and keep_going
        if self.keep_going:
            self.warningiserror = False
        else:
            self.warningiserror = warningiserror
        logging.setup(self, self._status, self._warning)

        self.events = EventManager(self)

        # keep last few messages for traceback
        # This will be filled by sphinx.util.logging.LastMessagesWriter
        self.messagelog = deque(maxlen=10)  # type: deque

        # say hello to the world
        logger.info(bold(__('Running Sphinx v%s') % sphinx.__display_version__))

        # notice for parallel build on macOS and py38+
        if sys.version_info > (3, 8) and platform.system() == 'Darwin' and parallel > 1:
            logger.info(bold(__("For security reason, parallel mode is disabled on macOS and "
                                "python3.8 and above. For more details, please read "
                                "https://github.com/sphinx-doc/sphinx/issues/6803")))

        # status code for command-line application
        self.statuscode = 0

        # read config
        self.tags = Tags(tags)
        if self.confdir is None:
            self.config = Config({}, confoverrides or {})
        else:
            self.config = Config.read(self.confdir, confoverrides or {}, self.tags)

        # initialize some limited config variables before initialize i18n and loading
        # extensions
        self.config.pre_init_values()

        # set up translation infrastructure
        self._init_i18n()

        # check the Sphinx version if requested
        if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
            raise VersionRequirementError(
                __('This project needs at least Sphinx v%s and therefore cannot '
                   'be built with this version.') % self.config.needs_sphinx)

        # set confdir to srcdir if -C given (!= no confdir); a few pieces
        # of code expect a confdir to be set
        if self.confdir is None:
            self.confdir = self.srcdir

        # load all built-in extension modules
        for extension in builtin_extensions:
            self.setup_extension(extension)

        # load all user-given extension modules
        for extension in self.config.extensions:
            self.setup_extension(extension)

        # preload builder module (before init config values)
        self.preload_builder(buildername)

        if not path.isdir(outdir):
            with progress_message(__('making output directory')):
                ensuredir(outdir)

        # the config file itself can be an extension
        if self.config.setup:
            prefix = __('while setting up extension %s:') % "conf.py"
            with prefixed_warnings(prefix):
                if callable(self.config.setup):
                    self.config.setup(self)
                else:
                    raise ConfigError(
                        __("'setup' as currently defined in conf.py isn't a Python callable. "
                           "Please modify its definition to make it a callable function. "
                           "This is needed for conf.py to behave as a Sphinx extension.")
                    )

        # now that we know all config values, collect them from conf.py
        self.config.init_values()
        self.events.emit('config-inited', self.config)

        # create the project
        self.project = Project(self.srcdir, self.config.source_suffix)
        # create the builder
        self.builder = self.create_builder(buildername)
        # set up the build environment
        self._init_env(freshenv)
        # set up the builder
        self._init_builder()
Example #42
0
def ask_user(d):
    """Ask the user for quickstart values missing from *d*.

    Values are:

    * path:      root path
    * sep:       separate source and build dirs (bool)
    * dot:       replacement for dot in _templates etc.
    * project:   project name
    * author:    author names
    * version:   version of project
    * release:   release of project
    * language:  document language
    * suffix:    source file suffix
    * master:    master document name
    * epub:      use epub (bool)
    * ext_*:     extensions to use (bools)
    * makefile:  make Makefile
    * batchfile: make command file
    """

    print(
        bold('Welcome to the Sphinx %s quickstart utility.') %
        __display_version__)
    print('''
Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).''')

    if 'path' in d:
        print(bold('''
Selected root path: %s''' % d['path']))
    else:
        print('''
Enter the root path for documentation.''')
        do_prompt(d, 'path', 'Root path for the documentation', '.', is_path)

    while path.isfile(path.join(d['path'], 'conf.py')) or \
            path.isfile(path.join(d['path'], 'source', 'conf.py')):
        print()
        print(
            bold('Error: an existing conf.py has been found in the '
                 'selected root path.'))
        print('sphinx-quickstart will not overwrite existing Sphinx projects.')
        print()
        do_prompt(d, 'path', 'Please enter a new root path (or just Enter '
                  'to exit)', '', is_path)
        if not d['path']:
            sys.exit(1)

    if 'sep' not in d:
        print('''
You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.''')
        do_prompt(d, 'sep', 'Separate source and build directories (y/n)', 'n',
                  boolean)

    if 'dot' not in d:
        print('''
Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.'''
              )
        do_prompt(d, 'dot', 'Name prefix for templates and static dir', '_',
                  ok)

    if 'project' not in d:
        print('''
The project name will occur in several places in the built documentation.''')
        do_prompt(d, 'project', 'Project name')
    if 'author' not in d:
        do_prompt(d, 'author', 'Author name(s)')

    if 'version' not in d:
        print('''
Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
just set both to the same value.''')
        do_prompt(d, 'version', 'Project version', '', allow_empty)
    if 'release' not in d:
        do_prompt(d, 'release', 'Project release', d['version'], allow_empty)

    if 'language' not in d:
        print('''
If the documents are to be written in a language other than English,
you can select a language here by its language code. Sphinx will then
translate text that it generates into that language.

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.''')
        do_prompt(d, 'language', 'Project language', 'en')
        if d['language'] == 'en':
            d['language'] = None

    if 'suffix' not in d:
        print('''
The file name suffix for source files. Commonly, this is either ".txt"
or ".rst".  Only files with this suffix are considered documents.''')
        do_prompt(d, 'suffix', 'Source file suffix', '.rst', suffix)

    if 'master' not in d:
        print('''
One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
document is a custom template, you can also set this to another filename.''')
        do_prompt(d, 'master', 'Name of your master document (without suffix)',
                  'index')

    while path.isfile(path.join(d['path'], d['master']+d['suffix'])) or \
            path.isfile(path.join(d['path'], 'source', d['master']+d['suffix'])):
        print()
        print(
            bold('Error: the master file %s has already been found in the '
                 'selected root path.' % (d['master'] + d['suffix'])))
        print('sphinx-quickstart will not overwrite the existing file.')
        print()
        do_prompt(
            d, 'master', 'Please enter a new file name, or rename the '
            'existing file and press Enter', d['master'])

    if 'epub' not in d:
        print('''
Sphinx can also add configuration for epub output:''')
        do_prompt(d, 'epub', 'Do you want to use the epub builder (y/n)', 'n',
                  boolean)

    if 'ext_autodoc' not in d:
        print('''
Please indicate if you want to use one of the following Sphinx extensions:''')
        do_prompt(
            d, 'ext_autodoc', 'autodoc: automatically insert docstrings '
            'from modules (y/n)', 'n', boolean)
    if 'ext_doctest' not in d:
        do_prompt(
            d, 'ext_doctest', 'doctest: automatically test code snippets '
            'in doctest blocks (y/n)', 'n', boolean)
    if 'ext_intersphinx' not in d:
        do_prompt(
            d, 'ext_intersphinx', 'intersphinx: link between Sphinx '
            'documentation of different projects (y/n)', 'n', boolean)
    if 'ext_todo' not in d:
        do_prompt(
            d, 'ext_todo', 'todo: write "todo" entries '
            'that can be shown or hidden on build (y/n)', 'n', boolean)
    if 'ext_coverage' not in d:
        do_prompt(d, 'ext_coverage', 'coverage: checks for documentation '
                  'coverage (y/n)', 'n', boolean)
    if 'ext_imgmath' not in d:
        do_prompt(
            d, 'ext_imgmath', 'imgmath: include math, rendered '
            'as PNG or SVG images (y/n)', 'n', boolean)
    if 'ext_mathjax' not in d:
        do_prompt(
            d, 'ext_mathjax', 'mathjax: include math, rendered in the '
            'browser by MathJax (y/n)', 'n', boolean)
    if d['ext_imgmath'] and d['ext_mathjax']:
        print('''Note: imgmath and mathjax cannot be enabled at the same time.
imgmath has been deselected.''')
        d['ext_imgmath'] = False
    if 'ext_ifconfig' not in d:
        do_prompt(
            d, 'ext_ifconfig', 'ifconfig: conditional inclusion of '
            'content based on config values (y/n)', 'n', boolean)
    if 'ext_viewcode' not in d:
        do_prompt(
            d, 'ext_viewcode', 'viewcode: include links to the source '
            'code of documented Python objects (y/n)', 'n', boolean)
    if 'ext_githubpages' not in d:
        do_prompt(
            d, 'ext_githubpages', 'githubpages: create .nojekyll file '
            'to publish the document on GitHub pages (y/n)', 'n', boolean)

    if 'no_makefile' in d:
        d['makefile'] = False
    elif 'makefile' not in d:
        print('''
A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.''')
        do_prompt(d, 'makefile', 'Create Makefile? (y/n)', 'y', boolean)
    if 'no_batchfile' in d:
        d['batchfile'] = False
    elif 'batchfile' not in d:
        do_prompt(d, 'batchfile', 'Create Windows command file? (y/n)', 'y',
                  boolean)
    print()