diff --git a/sphinx/application.py b/sphinx/application.py index 7e6878a7d..448b03672 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -97,12 +97,14 @@ builtin_extensions = ( 'sphinx.domains.python', 'sphinx.domains.rst', 'sphinx.domains.std', - 'sphinx.environment.collectors.asset', 'sphinx.directives', 'sphinx.directives.code', 'sphinx.directives.other', 'sphinx.directives.patches', 'sphinx.roles', + # collectors should be loaded by specific order + 'sphinx.environment.collectors.dependencies', + 'sphinx.environment.collectors.asset', ) # type: Tuple[unicode, ...] CONFIG_FILENAME = 'conf.py' diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index da31e3148..3b45c38b7 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -26,7 +26,7 @@ from six.moves import cPickle as pickle from docutils import nodes from docutils.io import NullOutput from docutils.core import Publisher -from docutils.utils import Reporter, relative_path, get_source_line +from docutils.utils import Reporter, get_source_line from docutils.parsers.rst import roles from docutils.parsers.rst.languages import en as english from docutils.frontend import OptionParser @@ -37,7 +37,7 @@ from sphinx.util import logging from sphinx.util import get_matching_docs, docname_join, FilenameUniqDict, status_iterator from sphinx.util.nodes import clean_astext, WarningStream, is_translatable, \ process_only_nodes -from sphinx.util.osutil import SEP, getcwd, fs_encoding, ensuredir +from sphinx.util.osutil import SEP, ensuredir from sphinx.util.i18n import find_catalog_files from sphinx.util.console import bold # type: ignore from sphinx.util.docutils import sphinx_domains @@ -313,7 +313,6 @@ class BuildEnvironment(object): self.all_docs.pop(docname, None) self.reread_always.discard(docname) self.metadata.pop(docname, None) - self.dependencies.pop(docname, None) self.titles.pop(docname, None) self.longtitles.pop(docname, None) @@ -340,8 +339,6 @@ class BuildEnvironment(object): if docname in other.reread_always: self.reread_always.add(docname) self.metadata[docname] = other.metadata[docname] - if docname in other.dependencies: - self.dependencies[docname] = other.dependencies[docname] self.titles[docname] = other.titles[docname] self.longtitles[docname] = other.longtitles[docname] @@ -728,7 +725,6 @@ class BuildEnvironment(object): doctree = pub.document # post-processing - self.process_dependencies(docname, doctree) self.process_metadata(docname, doctree) self.create_title_from(docname, doctree) for manager in itervalues(self.managers): @@ -857,23 +853,6 @@ class BuildEnvironment(object): # post-processing of read doctrees - def process_dependencies(self, docname, doctree): - # type: (unicode, nodes.Node) -> None - """Process docutils-generated dependency info.""" - cwd = getcwd() - frompath = path.join(path.normpath(self.srcdir), 'dummy') - deps = doctree.settings.record_dependencies - if not deps: - return - for dep in deps.list: - # the dependency path is relative to the working dir, so get - # one relative to the srcdir - if isinstance(dep, bytes): - dep = dep.decode(fs_encoding) - relpath = relative_path(frompath, - path.normpath(path.join(cwd, dep))) - self.dependencies[docname].add(relpath) - def process_metadata(self, docname, doctree): # type: (unicode, nodes.Node) -> None """Process the docinfo part of the doctree as metadata. diff --git a/sphinx/environment/collectors/dependencies.py b/sphinx/environment/collectors/dependencies.py new file mode 100644 index 000000000..b4d35caf7 --- /dev/null +++ b/sphinx/environment/collectors/dependencies.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +""" + sphinx.environment.collectors.dependencies + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The dependencies collector components for sphinx.environment. + + :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" + +from os import path + +from docutils.utils import relative_path + +from sphinx.util.osutil import getcwd, fs_encoding +from sphinx.environment.collectors import EnvironmentCollector + +if False: + # For type annotation + from docutils import nodes # NOQA + from sphinx.sphinx import Sphinx # NOQA + from sphinx.environment import BuildEnvironment # NOQA + + +class DependenciesCollector(EnvironmentCollector): + """dependencies collector for sphinx.environment.""" + + def clear_doc(self, app, env, docname): + # type: (Sphinx, BuildEnvironment, unicode) -> None + env.dependencies.pop(docname, None) + + def merge_other(self, app, env, docnames, other): + # type: (Sphinx, BuildEnvironment, Set[unicode], BuildEnvironment) -> None + for docname in docnames: + if docname in other.dependencies: + env.dependencies[docname] = other.dependencies[docname] + + def process_doc(self, app, doctree): + # type: (Sphinx, nodes.Node) -> None + """Process docutils-generated dependency info.""" + cwd = getcwd() + frompath = path.join(path.normpath(app.srcdir), 'dummy') + deps = doctree.settings.record_dependencies + if not deps: + return + for dep in deps.list: + # the dependency path is relative to the working dir, so get + # one relative to the srcdir + if isinstance(dep, bytes): + dep = dep.decode(fs_encoding) + relpath = relative_path(frompath, + path.normpath(path.join(cwd, dep))) + app.env.dependencies[app.env.docname].add(relpath) + + +def setup(app): + # type: (Sphinx) -> None + app.add_env_collector(DependenciesCollector)