summaryrefslogtreecommitdiffstats
path: root/tools/docs/moztreedocs/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/docs/moztreedocs/__init__.py')
-rw-r--r--tools/docs/moztreedocs/__init__.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/tools/docs/moztreedocs/__init__.py b/tools/docs/moztreedocs/__init__.py
new file mode 100644
index 000000000..a67edbded
--- /dev/null
+++ b/tools/docs/moztreedocs/__init__.py
@@ -0,0 +1,126 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import unicode_literals
+
+import os
+
+from mozbuild.frontend.reader import BuildReader
+from mozpack.copier import FileCopier
+from mozpack.files import FileFinder
+from mozpack.manifests import InstallManifest
+
+import sphinx
+import sphinx.apidoc
+
+
+class SphinxManager(object):
+ """Manages the generation of Sphinx documentation for the tree."""
+
+ def __init__(self, topsrcdir, main_path, output_dir):
+ self._topsrcdir = topsrcdir
+ self._output_dir = output_dir
+ self._docs_dir = os.path.join(output_dir, '_staging')
+ 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()
+
+ 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
+ self.add_tree(os.path.join(reldir, value),
+ os.path.join(reldir, 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)
+
+ def generate_docs(self, app):
+ """Generate/stage documentation."""
+ app.info('Reading Sphinx metadata from build configuration')
+ self.read_build_config()
+ app.info('Staging static documentation')
+ self._synchronize_docs()
+ app.info('Generating Python API documentation')
+ self._generate_python_api_docs()
+
+ def _generate_python_api_docs(self):
+ """Generate Python API doc files."""
+ out_dir = os.path.join(self._docs_dir, 'python')
+ base_args = ['sphinx', '--no-toc', '-o', out_dir]
+
+ for p in sorted(self._python_package_dirs):
+ full = os.path.join(self._topsrcdir, p)
+
+ finder = FileFinder(full, find_executables=False)
+ dirs = {os.path.dirname(f[0]) for f in finder.find('**')}
+
+ excludes = {d for d in dirs if d.endswith('test')}
+
+ args = list(base_args)
+ args.append(full)
+ args.extend(excludes)
+
+ sphinx.apidoc.main(args)
+
+ def _synchronize_docs(self):
+ m = InstallManifest()
+
+ m.add_symlink(self._conf_py_path, 'conf.py')
+
+ 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:
+ source_path = os.path.join(root, f)
+ rel_source = source_path[len(source_dir) + 1:]
+
+ m.add_symlink(source_path, os.path.join(dest, rel_source))
+
+ copier = FileCopier()
+ m.populate_registry(copier)
+ copier.copy(self._docs_dir)
+
+ with open(self._index_path, 'rb') as fh:
+ data = fh.read()
+
+ 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 = ['python/%s' % p for p in packages]
+ packages = '\n '.join(sorted(packages))
+ data = data.format(indexes=indexes, python_packages=packages)
+
+ with open(os.path.join(self._docs_dir, 'index.rst'), 'wb') as fh:
+ fh.write(data)