Fix #2022: html_extra_path also copies dotfiles and refers exclude_patterns

This commit is contained in:
Takeshi KOMIYA 2016-01-15 20:44:03 +09:00
parent 9ed3d51826
commit ae478f678e
15 changed files with 64 additions and 3 deletions

View File

@ -17,6 +17,8 @@ Incompatible changes
* ``sphinx.ext.graphviz``: show graph image in inline by default
* #2060, #2224: The ``manpage`` role now generate ``sphinx.addnodes.manpage`` node instead
of ``sphinx.addnodes.literal_emphasis`` node.
* #2022: :confval:`html_extra_path` also copies dotfiles in the extra directory, and
refers to :confval:`exclude_patterns` to exclude extra files and directories.
Features added
--------------

View File

@ -131,7 +131,7 @@ General configuration
:confval:`exclude_dirnames`)
:confval:`exclude_patterns` is also consulted when looking for static files
in :confval:`html_static_path`.
in :confval:`html_static_path` and :confval:`html_extra_path`.
.. versionadded:: 1.0
@ -640,6 +640,11 @@ that use Sphinx's HTMLWriter class.
.. versionadded:: 1.2
.. versionchanged:: 1.4
The dotfiles in the extra directory will be copied to the output directory.
And it refers :confval:`exclude_patterns` on copying extra files and
directories, and ignores if path matches to patterns.
.. confval:: html_last_updated_fmt
If this is not None, a 'Last updated on:' timestamp is inserted

View File

@ -27,7 +27,7 @@ from docutils.frontend import OptionParser
from docutils.readers.doctree import Reader as DoctreeReader
from sphinx import package_dir, __display_version__
from sphinx.util import jsonimpl, copy_static_entry
from sphinx.util import jsonimpl, copy_static_entry, copy_extra_entry
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, ustrftime, copyfile
from sphinx.util.nodes import inline_all_toctrees
@ -644,11 +644,12 @@ class StandaloneHTMLBuilder(Builder):
self.info(bold('copying extra files... '), nonl=True)
extraentries = [path.join(self.confdir, epath)
for epath in self.config.html_extra_path]
matchers = compile_matchers(self.config.exclude_patterns)
for entry in extraentries:
if not path.exists(entry):
self.warn('html_extra_path entry %r does not exist' % entry)
continue
copy_static_entry(entry, self.outdir, self)
copy_extra_entry(entry, self.outdir, matchers)
self.info('done')
def write_buildinfo(self):

View File

@ -146,6 +146,7 @@ language = %(language)r
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = [%(exclude_patterns)s]
# The reST default role (used for this markup: `text`) to use for all

View File

@ -182,6 +182,36 @@ def copy_static_entry(source, targetdir, builder, context={},
exclude_matchers=exclude_matchers)
def copy_extra_entry(source, targetdir, exclude_matchers=()):
"""Copy a HTML builder extra_path entry from source to targetdir.
Handles all possible cases of files, directories and subdirectories.
"""
def excluded(path):
relpath = relative_path(os.path.dirname(source), path)
return any(matcher(relpath) for matcher in exclude_matchers)
def copy_extra_file(source_, targetdir_):
if not excluded(source_):
target = path.join(targetdir_, os.path.basename(source_))
copyfile(source_, target)
if os.path.isfile(source):
copy_extra_file(source, targetdir)
return
for root, dirs, files in os.walk(source):
reltargetdir = os.path.join(targetdir, relative_path(source, root))
for dir in dirs[:]:
if excluded(os.path.join(root, dir)):
dirs.remove(dir)
else:
target = os.path.join(reltargetdir, dir)
if not path.exists(target):
os.mkdir(target)
for file in files:
copy_extra_file(os.path.join(root, file), reltargetdir)
_DEBUG_HEADER = '''\
# Sphinx version: %s
# Python version: %s (%s)

View File

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
html_extra_path = ['extra', 'subdir']
exclude_patterns = ['**/_build', '**/.htpasswd']

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -0,0 +1,3 @@
test-html_extra_path
=====================
this is dummy content

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -954,3 +954,16 @@ def test_jsmath(app, status, warning):
'e^{ix} = \\cos x + i\\sin x</div>' in content)
assert '<div class="math">\nn \\in \\mathbb N</div>' in content
assert '<div class="math">\na + 1 &lt; b</div>' in content
@with_app(buildername='html', testroot='html_extra_path')
def test_html_extra_path(app, status, warning):
app.builder.build_all()
assert (app.outdir / '.htaccess').exists()
assert not (app.outdir / '.htpasswd').exists()
assert (app.outdir / 'API.html_t').exists()
assert (app.outdir / 'css/style.css').exists()
assert (app.outdir / 'rimg.png').exists()
assert not (app.outdir / '_build/index.html').exists()
assert (app.outdir / 'background.png').exists()