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:
5
CHANGES
5
CHANGES
@@ -96,6 +96,11 @@ New features added
|
|||||||
|
|
||||||
* Builders:
|
* 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.
|
- New builder for Qt help collections, by Antonio Valentino.
|
||||||
|
|
||||||
- The new ``DirectoryHTMLBuilder`` (short name ``dirhtml``) creates
|
- The new ``DirectoryHTMLBuilder`` (short name ``dirhtml``) creates
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ release = version
|
|||||||
show_authors = True
|
show_authors = True
|
||||||
|
|
||||||
# The HTML template theme.
|
# The HTML template theme.
|
||||||
html_theme = 'sphinxdoc'
|
html_theme = 'default'
|
||||||
|
|
||||||
# A list of ignored prefixes names for module index sorting.
|
# A list of ignored prefixes names for module index sorting.
|
||||||
modindex_common_prefix = ['sphinx.']
|
modindex_common_prefix = ['sphinx.']
|
||||||
|
|||||||
@@ -15,20 +15,29 @@ the following public API:
|
|||||||
Register a new builder. *builder* must be a class that inherits from
|
Register a new builder. *builder* must be a class that inherits from
|
||||||
:class:`~sphinx.builders.Builder`.
|
: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
|
Register a configuration value. This is necessary for Sphinx to recognize
|
||||||
new values and set default values accordingly. The *name* should be prefixed
|
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
|
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
|
Python object. The string value *rebuild* must be one of those values:
|
||||||
in the setting only takes effect when a document is parsed -- this means that
|
|
||||||
the whole environment must be rebuilt.
|
* ``'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
|
.. versionchanged:: 0.4
|
||||||
If the *default* value is a callable, it will be called with the config
|
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
|
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.
|
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)
|
.. method:: Sphinx.add_event(name)
|
||||||
|
|
||||||
Register an event called *name*.
|
Register an event called *name*.
|
||||||
|
|||||||
@@ -260,10 +260,12 @@ class Sphinx(object):
|
|||||||
builder.name, self.builderclasses[builder.name].__module__))
|
builder.name, self.builderclasses[builder.name].__module__))
|
||||||
self.builderclasses[builder.name] = builder
|
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:
|
if name in self.config.values:
|
||||||
raise ExtensionError('Config value %r already present' % name)
|
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):
|
def add_event(self, name):
|
||||||
if name in self._events:
|
if name in self._events:
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ import shutil
|
|||||||
import posixpath
|
import posixpath
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
from os import path
|
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 import nodes
|
||||||
from docutils.io import DocTreeInput, StringOutput
|
from docutils.io import DocTreeInput, StringOutput
|
||||||
@@ -67,6 +74,8 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
script_files = ['_static/jquery.js', '_static/doctools.js']
|
script_files = ['_static/jquery.js', '_static/doctools.js']
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
|
# a hash of all config values that, if changed, cause a full rebuild
|
||||||
|
self.config_hash = ''
|
||||||
self.init_templates()
|
self.init_templates()
|
||||||
self.init_highlighter()
|
self.init_highlighter()
|
||||||
self.init_translator_class()
|
self.init_translator_class()
|
||||||
@@ -102,6 +111,55 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
else:
|
else:
|
||||||
self.translator_class = HTMLTranslator
|
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):
|
def render_partial(self, node):
|
||||||
"""Utility: Render a lone doctree node."""
|
"""Utility: Render a lone doctree node."""
|
||||||
doc = new_document('<partial node>')
|
doc = new_document('<partial node>')
|
||||||
@@ -479,6 +537,17 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
logobase = path.basename(self.config.html_logo)
|
logobase = path.basename(self.config.html_logo)
|
||||||
shutil.copyfile(path.join(self.confdir, self.config.html_logo),
|
shutil.copyfile(path.join(self.confdir, self.config.html_logo),
|
||||||
path.join(self.outdir, '_static', logobase))
|
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')
|
self.info('done')
|
||||||
|
|
||||||
# dump the search index
|
# dump the search index
|
||||||
@@ -511,30 +580,6 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
node.replace_self(reference)
|
node.replace_self(reference)
|
||||||
reference.append(node)
|
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):
|
def load_indexer(self, docnames):
|
||||||
keep = set(self.env.all_docs) - set(docnames)
|
keep = set(self.env.all_docs) - set(docnames)
|
||||||
try:
|
try:
|
||||||
|
|||||||
128
sphinx/config.py
128
sphinx/config.py
@@ -18,92 +18,92 @@ from sphinx.util import make_filename
|
|||||||
class Config(object):
|
class Config(object):
|
||||||
"""Configuration file abstraction."""
|
"""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
|
# If you add a value here, don't forget to include it in the
|
||||||
# quickstart.py file template as well as in the docs!
|
# quickstart.py file template as well as in the docs!
|
||||||
|
|
||||||
config_values = dict(
|
config_values = dict(
|
||||||
# general options
|
# general options
|
||||||
project = ('Python', True),
|
project = ('Python', 'env'),
|
||||||
copyright = ('', False),
|
copyright = ('', 'html'),
|
||||||
version = ('', True),
|
version = ('', 'env'),
|
||||||
release = ('', True),
|
release = ('', 'env'),
|
||||||
today = ('', True),
|
today = ('', 'env'),
|
||||||
today_fmt = (None, True), # the real default is locale-dependent
|
today_fmt = (None, 'env'), # the real default is locale-dependent
|
||||||
|
|
||||||
language = (None, True),
|
language = (None, 'env'),
|
||||||
locale_dirs = ([], True),
|
locale_dirs = ([], 'env'),
|
||||||
|
|
||||||
master_doc = ('contents', True),
|
master_doc = ('contents', 'env'),
|
||||||
source_suffix = ('.rst', True),
|
source_suffix = ('.rst', 'env'),
|
||||||
source_encoding = ('utf-8', True),
|
source_encoding = ('utf-8', 'env'),
|
||||||
unused_docs = ([], True),
|
unused_docs = ([], 'env'),
|
||||||
exclude_dirs = ([], True),
|
exclude_dirs = ([], 'env'),
|
||||||
exclude_trees = ([], True),
|
exclude_trees = ([], 'env'),
|
||||||
exclude_dirnames = ([], True),
|
exclude_dirnames = ([], 'env'),
|
||||||
default_role = (None, True),
|
default_role = (None, 'env'),
|
||||||
add_function_parentheses = (True, True),
|
add_function_parentheses = (True, 'env'),
|
||||||
add_module_names = (True, True),
|
add_module_names = (True, 'env'),
|
||||||
trim_footnote_reference_space = (False, True),
|
trim_footnote_reference_space = (False, 'env'),
|
||||||
show_authors = (False, True),
|
show_authors = (False, 'env'),
|
||||||
pygments_style = (None, False),
|
pygments_style = (None, 'html'),
|
||||||
highlight_language = ('python', False),
|
highlight_language = ('python', 'env'),
|
||||||
templates_path = ([], False),
|
templates_path = ([], 'html'),
|
||||||
template_bridge = (None, False),
|
template_bridge = (None, 'html'),
|
||||||
keep_warnings = (False, True),
|
keep_warnings = (False, 'env'),
|
||||||
modindex_common_prefix = ([], False),
|
modindex_common_prefix = ([], 'html'),
|
||||||
rst_epilog = (None, True),
|
rst_epilog = (None, 'env'),
|
||||||
|
|
||||||
# HTML options
|
# HTML options
|
||||||
html_theme = ('default', False),
|
html_theme = ('default', 'html'),
|
||||||
html_theme_path = ([], False),
|
html_theme_path = ([], 'html'),
|
||||||
html_theme_options = ({}, False),
|
html_theme_options = ({}, 'html'),
|
||||||
html_title = (lambda self: '%s v%s documentation' %
|
html_title = (lambda self: '%s v%s documentation' %
|
||||||
(self.project, self.release),
|
(self.project, self.release),
|
||||||
False),
|
'html'),
|
||||||
html_short_title = (lambda self: self.html_title, False),
|
html_short_title = (lambda self: self.html_title, 'html'),
|
||||||
html_style = (None, False),
|
html_style = (None, 'html'),
|
||||||
html_logo = (None, False),
|
html_logo = (None, 'html'),
|
||||||
html_favicon = (None, False),
|
html_favicon = (None, 'html'),
|
||||||
html_static_path = ([], False),
|
html_static_path = ([], 'html'),
|
||||||
# the real default is locale-dependent
|
# the real default is locale-dependent
|
||||||
html_last_updated_fmt = (None, False),
|
html_last_updated_fmt = (None, 'html'),
|
||||||
html_use_smartypants = (True, False),
|
html_use_smartypants = (True, 'html'),
|
||||||
html_translator_class = (None, False),
|
html_translator_class = (None, 'html'),
|
||||||
html_sidebars = ({}, False),
|
html_sidebars = ({}, 'html'),
|
||||||
html_additional_pages = ({}, False),
|
html_additional_pages = ({}, 'html'),
|
||||||
html_use_modindex = (True, False),
|
html_use_modindex = (True, 'html'),
|
||||||
html_add_permalinks = (True, False),
|
html_add_permalinks = (True, 'html'),
|
||||||
html_use_index = (True, False),
|
html_use_index = (True, 'html'),
|
||||||
html_split_index = (False, False),
|
html_split_index = (False, 'html'),
|
||||||
html_copy_source = (True, False),
|
html_copy_source = (True, 'html'),
|
||||||
html_show_sourcelink = (True, False),
|
html_show_sourcelink = (True, 'html'),
|
||||||
html_use_opensearch = ('', False),
|
html_use_opensearch = ('', 'html'),
|
||||||
html_file_suffix = (None, False),
|
html_file_suffix = (None, 'html'),
|
||||||
html_link_suffix = (None, False),
|
html_link_suffix = (None, 'html'),
|
||||||
html_show_sphinx = (True, False),
|
html_show_sphinx = (True, 'html'),
|
||||||
html_context = ({}, False),
|
html_context = ({}, 'html'),
|
||||||
|
|
||||||
# HTML help only options
|
# 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
|
# 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 options
|
||||||
latex_documents = ([], False),
|
latex_documents = ([], None),
|
||||||
latex_logo = (None, False),
|
latex_logo = (None, None),
|
||||||
latex_appendices = ([], False),
|
latex_appendices = ([], None),
|
||||||
latex_use_parts = (False, False),
|
latex_use_parts = (False, None),
|
||||||
latex_use_modindex = (True, False),
|
latex_use_modindex = (True, None),
|
||||||
# paper_size and font_size are still separate values
|
# paper_size and font_size are still separate values
|
||||||
# so that you can give them easily on the command line
|
# so that you can give them easily on the command line
|
||||||
latex_paper_size = ('letter', False),
|
latex_paper_size = ('letter', None),
|
||||||
latex_font_size = ('10pt', False),
|
latex_font_size = ('10pt', None),
|
||||||
latex_elements = ({}, False),
|
latex_elements = ({}, None),
|
||||||
# now deprecated - use latex_elements
|
# now deprecated - use latex_elements
|
||||||
latex_preamble = ('', False),
|
latex_preamble = ('', None),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, dirname, filename, overrides):
|
def __init__(self, dirname, filename, overrides):
|
||||||
|
|||||||
@@ -460,8 +460,8 @@ class BuildEnvironment:
|
|||||||
else:
|
else:
|
||||||
# check if a config value was changed that affects how
|
# check if a config value was changed that affects how
|
||||||
# doctrees are read
|
# doctrees are read
|
||||||
for key, descr in config.config_values.iteritems():
|
for key, descr in config.values.iteritems():
|
||||||
if not descr[1]:
|
if descr[1] != 'env':
|
||||||
continue
|
continue
|
||||||
if self.config[key] != config[key]:
|
if self.config[key] != config[key]:
|
||||||
msg = '[config changed] '
|
msg = '[config changed] '
|
||||||
|
|||||||
Reference in New Issue
Block a user