diff --git a/CHANGES b/CHANGES index cc53820d8..94a38204b 100644 --- a/CHANGES +++ b/CHANGES @@ -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 -------------- diff --git a/doc/config.rst b/doc/config.rst index 5076d62e0..b0c148c04 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -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 diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index 01c593b72..03199f3b9 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -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): diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py index f7a6731dc..e2f6edd45 100644 --- a/sphinx/quickstart.py +++ b/sphinx/quickstart.py @@ -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 diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index b3b065f8e..0d2e70c18 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -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) diff --git a/tests/roots/test-html_extra_path/conf.py b/tests/roots/test-html_extra_path/conf.py new file mode 100644 index 000000000..53ee62197 --- /dev/null +++ b/tests/roots/test-html_extra_path/conf.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +master_doc = 'index' + +html_extra_path = ['extra', 'subdir'] +exclude_patterns = ['**/_build', '**/.htpasswd'] diff --git a/tests/roots/test-html_extra_path/extra/.htaccess b/tests/roots/test-html_extra_path/extra/.htaccess new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-html_extra_path/extra/.htpasswd b/tests/roots/test-html_extra_path/extra/.htpasswd new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-html_extra_path/extra/API.html_t b/tests/roots/test-html_extra_path/extra/API.html_t new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-html_extra_path/extra/css/style.css b/tests/roots/test-html_extra_path/extra/css/style.css new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-html_extra_path/extra/rimg.png b/tests/roots/test-html_extra_path/extra/rimg.png new file mode 100644 index 000000000..1081dc143 Binary files /dev/null and b/tests/roots/test-html_extra_path/extra/rimg.png differ diff --git a/tests/roots/test-html_extra_path/index.rst b/tests/roots/test-html_extra_path/index.rst new file mode 100644 index 000000000..6d5619455 --- /dev/null +++ b/tests/roots/test-html_extra_path/index.rst @@ -0,0 +1,3 @@ +test-html_extra_path +===================== +this is dummy content diff --git a/tests/roots/test-html_extra_path/subdir/_build/index.html b/tests/roots/test-html_extra_path/subdir/_build/index.html new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-html_extra_path/subdir/background.png b/tests/roots/test-html_extra_path/subdir/background.png new file mode 100644 index 000000000..1081dc143 Binary files /dev/null and b/tests/roots/test-html_extra_path/subdir/background.png differ diff --git a/tests/test_build_html.py b/tests/test_build_html.py index 40fda97f9..2afeaace6 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -954,3 +954,16 @@ def test_jsmath(app, status, warning): 'e^{ix} = \\cos x + i\\sin x' in content) assert '
\nn \\in \\mathbb N
' in content assert '
\na + 1 < b
' 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()