diff --git a/tools/docs/moztreedocs/__init__.py b/tools/docs/moztreedocs/__init__.py index e46766368d67..18d2b572a4c9 100644 --- a/tools/docs/moztreedocs/__init__.py +++ b/tools/docs/moztreedocs/__init__.py @@ -8,6 +8,7 @@ import os from mozbuild.base import MozbuildObject from mozbuild.frontend.reader import BuildReader +from mozbuild.util import memoize from mozpack.copier import FileCopier from mozpack.files import FileFinder from mozpack.manifests import InstallManifest @@ -21,6 +22,41 @@ build = MozbuildObject.from_environment(cwd=here) MAIN_DOC_PATH = os.path.join(build.topsrcdir, 'tools', 'docs') +@memoize +def read_build_config(docdir): + """Read the active build config and return the relevant doc paths. + + The return value is cached so re-generating with the same docdir won't + invoke the build system a second time.""" + trees = {} + python_package_dirs = set() + + # Reading the Sphinx variables doesn't require a full build context. + # Only define the parts we need. + class fakeconfig(object): + topsrcdir = build.topsrcdir + + reader = BuildReader(fakeconfig()) + for path, name, key, value in reader.find_sphinx_variables(): + reldir = os.path.join(os.path.dirname(path), value) + + if name == 'SPHINX_TREES': + assert key + if key.startswith('/'): + key = key[1:] + else: + key = os.path.join(reldir, key) + + if key in trees: + raise Exception('%s has already been registered as a destination.' % key) + trees[key] = reldir + + if name == 'SPHINX_PYTHON_PACKAGE_DIRS': + python_package_dirs.add(reldir) + + return trees, python_package_dirs + + class _SphinxManager(object): """Manages the generation of Sphinx documentation for the tree.""" @@ -29,58 +65,18 @@ class _SphinxManager(object): self.conf_py_path = os.path.join(main_path, 'conf.py') self.index_path = os.path.join(main_path, 'index.rst') - self._trees = {} - self._python_package_dirs = set() - # Instance variables that get set in self.generate_docs() self.staging_dir = None - - def read_build_config(self): - """Read the active build config and add docs to this instance.""" - - # Reading the Sphinx variables doesn't require a full build context. - # Only define the parts we need. - class fakeconfig(object): - def __init__(self, topsrcdir): - self.topsrcdir = topsrcdir - - config = fakeconfig(self.topsrcdir) - reader = BuildReader(config) - - for path, name, key, value in reader.find_sphinx_variables(): - reldir = os.path.dirname(path) - if name == 'SPHINX_TREES': - assert key - if key.startswith('/'): - key = key[1:] - else: - key = os.path.join(reldir, key) - self.add_tree(os.path.join(reldir, value), key) - - if name == 'SPHINX_PYTHON_PACKAGE_DIRS': - self.add_python_package_dir(os.path.join(reldir, value)) - - def add_tree(self, source_dir, dest_dir): - """Add a directory from where docs should be sourced.""" - if dest_dir in self._trees: - raise Exception('%s has already been registered as a destination.' - % dest_dir) - - self._trees[dest_dir] = source_dir - - def add_python_package_dir(self, source_dir): - """Add a directory containing Python packages. - - Added directories will have Python API docs generated automatically. - """ - self._python_package_dirs.add(source_dir) + self.trees = None + self.python_package_dirs = None def generate_docs(self, app): """Generate/stage documentation.""" self.staging_dir = os.path.join(app.outdir, '_staging') app.info('Reading Sphinx metadata from build configuration') - self.read_build_config() + self.trees, self.python_package_dirs = read_build_config(app.srcdir) + app.info('Staging static documentation') self._synchronize_docs() app.info('Generating Python API documentation') @@ -91,7 +87,7 @@ class _SphinxManager(object): out_dir = os.path.join(self.staging_dir, 'python') base_args = ['sphinx', '--no-toc', '-o', out_dir] - for p in sorted(self._python_package_dirs): + for p in sorted(self.python_package_dirs): full = os.path.join(self.topsrcdir, p) finder = FileFinder(full) @@ -110,7 +106,7 @@ class _SphinxManager(object): m.add_link(self.conf_py_path, 'conf.py') - for dest, source in sorted(self._trees.items()): + for dest, source in sorted(self.trees.items()): source_dir = os.path.join(self.topsrcdir, source) for root, dirs, files in os.walk(source_dir): for f in files: @@ -126,10 +122,10 @@ class _SphinxManager(object): with open(self.index_path, 'rb') as fh: data = fh.read() - indexes = ['%s/index' % p for p in sorted(self._trees.keys())] + indexes = ['%s/index' % p for p in sorted(self.trees.keys())] indexes = '\n '.join(indexes) - packages = [os.path.basename(p) for p in self._python_package_dirs] + packages = [os.path.basename(p) for p in self.python_package_dirs] packages = ['python/%s' % p for p in packages] packages = '\n '.join(sorted(packages)) data = data.format(indexes=indexes, python_packages=packages)