mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
The HTML builder now stores a small file named `.buildinfo
` in
its output directory. It stores a hash of config values that can be used to determine if a full rebuild needs to be done (e.g. after changing ``html_theme``).
This commit is contained in:
parent
2dff2e3bfa
commit
d4f5796f3b
5
CHANGES
5
CHANGES
@ -96,6 +96,11 @@ New features added
|
||||
|
||||
* Builders:
|
||||
|
||||
- The HTML builder now stores a small file named ``.buildinfo`` in
|
||||
its output directory. It stores a hash of config values that
|
||||
can be used to determine if a full rebuild needs to be done (e.g.
|
||||
after changing ``html_theme``).
|
||||
|
||||
- New builder for Qt help collections, by Antonio Valentino.
|
||||
|
||||
- The new ``DirectoryHTMLBuilder`` (short name ``dirhtml``) creates
|
||||
|
@ -31,7 +31,7 @@ release = version
|
||||
show_authors = True
|
||||
|
||||
# The HTML template theme.
|
||||
html_theme = 'sphinxdoc'
|
||||
html_theme = 'default'
|
||||
|
||||
# A list of ignored prefixes names for module index sorting.
|
||||
modindex_common_prefix = ['sphinx.']
|
||||
|
@ -15,20 +15,29 @@ the following public API:
|
||||
Register a new builder. *builder* must be a class that inherits from
|
||||
:class:`~sphinx.builders.Builder`.
|
||||
|
||||
.. method:: Sphinx.add_config_value(name, default, rebuild_env)
|
||||
.. method:: Sphinx.add_config_value(name, default, rebuild)
|
||||
|
||||
Register a configuration value. This is necessary for Sphinx to recognize
|
||||
new values and set default values accordingly. The *name* should be prefixed
|
||||
with the extension name, to avoid clashes. The *default* value can be any
|
||||
Python object. The boolean value *rebuild_env* must be ``True`` if a change
|
||||
in the setting only takes effect when a document is parsed -- this means that
|
||||
the whole environment must be rebuilt.
|
||||
Python object. The string value *rebuild* must be one of those values:
|
||||
|
||||
* ``'env'`` if a change in the setting only takes effect when a document is
|
||||
parsed -- this means that the whole environment must be rebuilt.
|
||||
* ``'html'`` if a change in the setting needs a full rebuild of HTML
|
||||
documents.
|
||||
* ``''`` if a change in the setting will not need any special rebuild.
|
||||
|
||||
.. versionchanged:: 0.4
|
||||
If the *default* value is a callable, it will be called with the config
|
||||
object as its argument in order to get the default value. This can be
|
||||
used to implement config values whose default depends on other values.
|
||||
|
||||
.. versionchanged:: 0.6
|
||||
Changed *rebuild* from a simple boolean (equivalent to ``''`` or
|
||||
``'env'``) to a string. However, booleans are still accepted and
|
||||
converted internally.
|
||||
|
||||
.. method:: Sphinx.add_event(name)
|
||||
|
||||
Register an event called *name*.
|
||||
|
@ -260,10 +260,12 @@ class Sphinx(object):
|
||||
builder.name, self.builderclasses[builder.name].__module__))
|
||||
self.builderclasses[builder.name] = builder
|
||||
|
||||
def add_config_value(self, name, default, rebuild_env):
|
||||
def add_config_value(self, name, default, rebuild):
|
||||
if name in self.config.values:
|
||||
raise ExtensionError('Config value %r already present' % name)
|
||||
self.config.values[name] = (default, rebuild_env)
|
||||
if rebuild in (False, True):
|
||||
rebuild = rebuild and 'env' or ''
|
||||
self.config.values[name] = (default, rebuild)
|
||||
|
||||
def add_event(self, name):
|
||||
if name in self._events:
|
||||
|
@ -15,6 +15,13 @@ import shutil
|
||||
import posixpath
|
||||
import cPickle as pickle
|
||||
from os import path
|
||||
try:
|
||||
import hashlib
|
||||
md5 = hashlib.md5
|
||||
except ImportError:
|
||||
# 2.4 compatibility
|
||||
import md5
|
||||
md5 = md5.new
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.io import DocTreeInput, StringOutput
|
||||
@ -67,6 +74,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
script_files = ['_static/jquery.js', '_static/doctools.js']
|
||||
|
||||
def init(self):
|
||||
# a hash of all config values that, if changed, cause a full rebuild
|
||||
self.config_hash = ''
|
||||
self.init_templates()
|
||||
self.init_highlighter()
|
||||
self.init_translator_class()
|
||||
@ -102,6 +111,55 @@ class StandaloneHTMLBuilder(Builder):
|
||||
else:
|
||||
self.translator_class = HTMLTranslator
|
||||
|
||||
def get_outdated_docs(self):
|
||||
cfgdict = dict((name, self.config[name])
|
||||
for (name, desc) in self.config.values.iteritems()
|
||||
if desc[1] == 'html')
|
||||
self.config_hash = md5(str(cfgdict)).hexdigest()
|
||||
try:
|
||||
fp = open(path.join(self.outdir, '.buildinfo'))
|
||||
version = fp.readline()
|
||||
if version.rstrip() != '# Sphinx build info version 1':
|
||||
raise ValueError
|
||||
fp.readline() # skip commentary
|
||||
cfg, old_hash = fp.readline().strip().split(': ')
|
||||
if cfg != 'config':
|
||||
raise ValueError
|
||||
fp.close()
|
||||
except ValueError:
|
||||
self.warn('unsupported build info format in %r, building all' %
|
||||
path.join(self.outdir, '.buildinfo'))
|
||||
old_hash = ''
|
||||
except Exception:
|
||||
old_hash = ''
|
||||
if old_hash != self.config_hash:
|
||||
for docname in self.env.found_docs:
|
||||
yield docname
|
||||
return
|
||||
|
||||
if self.templates:
|
||||
template_mtime = self.templates.newest_template_mtime()
|
||||
else:
|
||||
template_mtime = 0
|
||||
for docname in self.env.found_docs:
|
||||
if docname not in self.env.all_docs:
|
||||
yield docname
|
||||
continue
|
||||
targetname = self.env.doc2path(docname, self.outdir,
|
||||
self.out_suffix)
|
||||
try:
|
||||
targetmtime = path.getmtime(targetname)
|
||||
except Exception:
|
||||
targetmtime = 0
|
||||
try:
|
||||
srcmtime = max(path.getmtime(self.env.doc2path(docname)),
|
||||
template_mtime)
|
||||
if srcmtime > targetmtime:
|
||||
yield docname
|
||||
except EnvironmentError:
|
||||
# source doesn't exist anymore
|
||||
pass
|
||||
|
||||
def render_partial(self, node):
|
||||
"""Utility: Render a lone doctree node."""
|
||||
doc = new_document('<partial node>')
|
||||
@ -479,6 +537,17 @@ class StandaloneHTMLBuilder(Builder):
|
||||
logobase = path.basename(self.config.html_logo)
|
||||
shutil.copyfile(path.join(self.confdir, self.config.html_logo),
|
||||
path.join(self.outdir, '_static', logobase))
|
||||
|
||||
# write build info file
|
||||
fp = open(path.join(self.outdir, '.buildinfo'), 'w')
|
||||
try:
|
||||
fp.write('# Sphinx build info version 1\n'
|
||||
'# This file hashes the configuration used when building'
|
||||
' these files. When it is not found, a full rebuild will'
|
||||
' be done.\nconfig: %s\n' % self.config_hash)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
self.info('done')
|
||||
|
||||
# dump the search index
|
||||
@ -511,30 +580,6 @@ class StandaloneHTMLBuilder(Builder):
|
||||
node.replace_self(reference)
|
||||
reference.append(node)
|
||||
|
||||
def get_outdated_docs(self):
|
||||
if self.templates:
|
||||
template_mtime = self.templates.newest_template_mtime()
|
||||
else:
|
||||
template_mtime = 0
|
||||
for docname in self.env.found_docs:
|
||||
if docname not in self.env.all_docs:
|
||||
yield docname
|
||||
continue
|
||||
targetname = self.env.doc2path(docname, self.outdir,
|
||||
self.out_suffix)
|
||||
try:
|
||||
targetmtime = path.getmtime(targetname)
|
||||
except Exception:
|
||||
targetmtime = 0
|
||||
try:
|
||||
srcmtime = max(path.getmtime(self.env.doc2path(docname)),
|
||||
template_mtime)
|
||||
if srcmtime > targetmtime:
|
||||
yield docname
|
||||
except EnvironmentError:
|
||||
# source doesn't exist anymore
|
||||
pass
|
||||
|
||||
def load_indexer(self, docnames):
|
||||
keep = set(self.env.all_docs) - set(docnames)
|
||||
try:
|
||||
|
128
sphinx/config.py
128
sphinx/config.py
@ -18,92 +18,92 @@ from sphinx.util import make_filename
|
||||
class Config(object):
|
||||
"""Configuration file abstraction."""
|
||||
|
||||
# the values are: (default, needs fresh doctrees if changed)
|
||||
# the values are: (default, what needs to be rebuilt if changed)
|
||||
|
||||
# If you add a value here, don't forget to include it in the
|
||||
# quickstart.py file template as well as in the docs!
|
||||
|
||||
config_values = dict(
|
||||
# general options
|
||||
project = ('Python', True),
|
||||
copyright = ('', False),
|
||||
version = ('', True),
|
||||
release = ('', True),
|
||||
today = ('', True),
|
||||
today_fmt = (None, True), # the real default is locale-dependent
|
||||
project = ('Python', 'env'),
|
||||
copyright = ('', 'html'),
|
||||
version = ('', 'env'),
|
||||
release = ('', 'env'),
|
||||
today = ('', 'env'),
|
||||
today_fmt = (None, 'env'), # the real default is locale-dependent
|
||||
|
||||
language = (None, True),
|
||||
locale_dirs = ([], True),
|
||||
language = (None, 'env'),
|
||||
locale_dirs = ([], 'env'),
|
||||
|
||||
master_doc = ('contents', True),
|
||||
source_suffix = ('.rst', True),
|
||||
source_encoding = ('utf-8', True),
|
||||
unused_docs = ([], True),
|
||||
exclude_dirs = ([], True),
|
||||
exclude_trees = ([], True),
|
||||
exclude_dirnames = ([], True),
|
||||
default_role = (None, True),
|
||||
add_function_parentheses = (True, True),
|
||||
add_module_names = (True, True),
|
||||
trim_footnote_reference_space = (False, True),
|
||||
show_authors = (False, True),
|
||||
pygments_style = (None, False),
|
||||
highlight_language = ('python', False),
|
||||
templates_path = ([], False),
|
||||
template_bridge = (None, False),
|
||||
keep_warnings = (False, True),
|
||||
modindex_common_prefix = ([], False),
|
||||
rst_epilog = (None, True),
|
||||
master_doc = ('contents', 'env'),
|
||||
source_suffix = ('.rst', 'env'),
|
||||
source_encoding = ('utf-8', 'env'),
|
||||
unused_docs = ([], 'env'),
|
||||
exclude_dirs = ([], 'env'),
|
||||
exclude_trees = ([], 'env'),
|
||||
exclude_dirnames = ([], 'env'),
|
||||
default_role = (None, 'env'),
|
||||
add_function_parentheses = (True, 'env'),
|
||||
add_module_names = (True, 'env'),
|
||||
trim_footnote_reference_space = (False, 'env'),
|
||||
show_authors = (False, 'env'),
|
||||
pygments_style = (None, 'html'),
|
||||
highlight_language = ('python', 'env'),
|
||||
templates_path = ([], 'html'),
|
||||
template_bridge = (None, 'html'),
|
||||
keep_warnings = (False, 'env'),
|
||||
modindex_common_prefix = ([], 'html'),
|
||||
rst_epilog = (None, 'env'),
|
||||
|
||||
# HTML options
|
||||
html_theme = ('default', False),
|
||||
html_theme_path = ([], False),
|
||||
html_theme_options = ({}, False),
|
||||
html_theme = ('default', 'html'),
|
||||
html_theme_path = ([], 'html'),
|
||||
html_theme_options = ({}, 'html'),
|
||||
html_title = (lambda self: '%s v%s documentation' %
|
||||
(self.project, self.release),
|
||||
False),
|
||||
html_short_title = (lambda self: self.html_title, False),
|
||||
html_style = (None, False),
|
||||
html_logo = (None, False),
|
||||
html_favicon = (None, False),
|
||||
html_static_path = ([], False),
|
||||
'html'),
|
||||
html_short_title = (lambda self: self.html_title, 'html'),
|
||||
html_style = (None, 'html'),
|
||||
html_logo = (None, 'html'),
|
||||
html_favicon = (None, 'html'),
|
||||
html_static_path = ([], 'html'),
|
||||
# the real default is locale-dependent
|
||||
html_last_updated_fmt = (None, False),
|
||||
html_use_smartypants = (True, False),
|
||||
html_translator_class = (None, False),
|
||||
html_sidebars = ({}, False),
|
||||
html_additional_pages = ({}, False),
|
||||
html_use_modindex = (True, False),
|
||||
html_add_permalinks = (True, False),
|
||||
html_use_index = (True, False),
|
||||
html_split_index = (False, False),
|
||||
html_copy_source = (True, False),
|
||||
html_show_sourcelink = (True, False),
|
||||
html_use_opensearch = ('', False),
|
||||
html_file_suffix = (None, False),
|
||||
html_link_suffix = (None, False),
|
||||
html_show_sphinx = (True, False),
|
||||
html_context = ({}, False),
|
||||
html_last_updated_fmt = (None, 'html'),
|
||||
html_use_smartypants = (True, 'html'),
|
||||
html_translator_class = (None, 'html'),
|
||||
html_sidebars = ({}, 'html'),
|
||||
html_additional_pages = ({}, 'html'),
|
||||
html_use_modindex = (True, 'html'),
|
||||
html_add_permalinks = (True, 'html'),
|
||||
html_use_index = (True, 'html'),
|
||||
html_split_index = (False, 'html'),
|
||||
html_copy_source = (True, 'html'),
|
||||
html_show_sourcelink = (True, 'html'),
|
||||
html_use_opensearch = ('', 'html'),
|
||||
html_file_suffix = (None, 'html'),
|
||||
html_link_suffix = (None, 'html'),
|
||||
html_show_sphinx = (True, 'html'),
|
||||
html_context = ({}, 'html'),
|
||||
|
||||
# HTML help only options
|
||||
htmlhelp_basename = (lambda self: make_filename(self.project), False),
|
||||
htmlhelp_basename = (lambda self: make_filename(self.project), None),
|
||||
|
||||
# Qt help only options
|
||||
qthelp_basename = (lambda self: make_filename(self.project), False),
|
||||
qthelp_basename = (lambda self: make_filename(self.project), None),
|
||||
|
||||
# LaTeX options
|
||||
latex_documents = ([], False),
|
||||
latex_logo = (None, False),
|
||||
latex_appendices = ([], False),
|
||||
latex_use_parts = (False, False),
|
||||
latex_use_modindex = (True, False),
|
||||
latex_documents = ([], None),
|
||||
latex_logo = (None, None),
|
||||
latex_appendices = ([], None),
|
||||
latex_use_parts = (False, None),
|
||||
latex_use_modindex = (True, None),
|
||||
# paper_size and font_size are still separate values
|
||||
# so that you can give them easily on the command line
|
||||
latex_paper_size = ('letter', False),
|
||||
latex_font_size = ('10pt', False),
|
||||
latex_elements = ({}, False),
|
||||
latex_paper_size = ('letter', None),
|
||||
latex_font_size = ('10pt', None),
|
||||
latex_elements = ({}, None),
|
||||
# now deprecated - use latex_elements
|
||||
latex_preamble = ('', False),
|
||||
latex_preamble = ('', None),
|
||||
)
|
||||
|
||||
def __init__(self, dirname, filename, overrides):
|
||||
|
@ -460,8 +460,8 @@ class BuildEnvironment:
|
||||
else:
|
||||
# check if a config value was changed that affects how
|
||||
# doctrees are read
|
||||
for key, descr in config.config_values.iteritems():
|
||||
if not descr[1]:
|
||||
for key, descr in config.values.iteritems():
|
||||
if descr[1] != 'env':
|
||||
continue
|
||||
if self.config[key] != config[key]:
|
||||
msg = '[config changed] '
|
||||
|
Loading…
Reference in New Issue
Block a user