Bug 1454640 - [docs] Memoize the result of processing sphinx moz.build variables r=mshal

Now that we can rebuild docs with the liveserver, there are some optimizations
we should make. One of those is processing the sphinx moz.build variables. This
patch makes sure we don't re-process moz.build if we've already done so in a
previous rebuild.

MozReview-Commit-ID: 2AIr1KeAPQV

--HG--
extra : source : 30b4083534b51213a1b9fe0d86f996cfa0e7fa54
This commit is contained in:
Andrew Halberstadt 2018-04-18 15:01:10 -04:00
Родитель 03da91b713
Коммит a33ec550e5
1 изменённых файлов: 44 добавлений и 48 удалений

Просмотреть файл

@ -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)