Bug 1115278 - Move Sphinx documentation staging into Sphinx extension; r=glandium
authorGregory Szorc <gps@mozilla.com>
Wed, 24 Dec 2014 09:46:41 -0800
changeset 221522 6e708bf5daaba3fca00a2376394587052bbbb710
parent 221521 01ece2e26ef9af43271594094b2d8fc93933aaec
child 221523 245bebb9e0d23070b3708d8f4ae45c85efb126b9
push id28032
push userkwierso@gmail.com
push dateTue, 30 Dec 2014 01:28:14 +0000
treeherdermozilla-central@67872ce17918 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1115278
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1115278 - Move Sphinx documentation staging into Sphinx extension; r=glandium Previously, code for staging the Sphinx documentation from moz.build metadata lived in a mach command and in the moztreedocs module. This patch moves the invocation to the Sphinx extension. When the code is part of the Sphinx extension, it will run when executed with sphinx-build. This is a prerequisite to getting RTD working, since sphinx-build is the only supported entrypoint for generating documentation there. With this patch, we can now invoke sphinx-build to build the documentation. The `mach build-docs` command is no longer needed.
python/mozbuild/mozbuild/sphinx.py
tools/docs/conf.py
tools/docs/mach_commands.py
tools/docs/moztreedocs/__init__.py
--- a/python/mozbuild/mozbuild/sphinx.py
+++ b/python/mozbuild/mozbuild/sphinx.py
@@ -1,15 +1,16 @@
 # 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 absolute_import
 
 import importlib
+import os
 
 from sphinx.util.compat import Directive
 from sphinx.util.docstrings import prepare_docstring
 
 
 def function_reference(f, attr, args, doc):
     lines = []
 
@@ -147,8 +148,24 @@ class MozbuildSymbols(Directive):
         # there's no record of us.
         self.state_machine.insert_input(format_module(module), fname)
 
         return []
 
 
 def setup(app):
     app.add_directive('mozbuildsymbols', MozbuildSymbols)
+
+    # Unlike typical Sphinx installs, our documentation is assembled from
+    # many sources and staged in a common location. This arguably isn't a best
+    # practice, but it was the easiest to implement at the time.
+    #
+    # Here, we invoke our custom code for staging/generating all our
+    # documentation.
+    from moztreedocs import SphinxManager
+
+    topsrcdir = app.config._raw_config['topsrcdir']
+    manager = SphinxManager(topsrcdir,
+        os.path.join(topsrcdir, 'tools', 'docs'),
+        app.outdir)
+    manager.generate_docs(app)
+
+    app.srcdir = manager._docs_dir
--- a/tools/docs/conf.py
+++ b/tools/docs/conf.py
@@ -1,50 +1,56 @@
 # 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
 import re
+import sys
 
 from datetime import datetime
 
+# Set up Python environment to load build system packages.
+OUR_DIR = os.path.dirname(__file__)
+topsrcdir = os.path.normpath(os.path.join(OUR_DIR, '..', '..'))
 
-mozilla_dir = os.environ['MOZILLA_DIR']
+sys.path.insert(0, os.path.join(topsrcdir, 'python', 'jsmin'))
+sys.path.insert(0, os.path.join(topsrcdir, 'python', 'mozbuild'))
+sys.path.insert(0, OUR_DIR)
 
 extensions = [
     'sphinx.ext.autodoc',
     'sphinx.ext.graphviz',
     'sphinx.ext.todo',
     'mozbuild.sphinx',
 ]
 
 templates_path = ['_templates']
 source_suffix = '.rst'
 master_doc = 'index'
 project = u'Mozilla Source Tree Docs'
 year = datetime.now().year
 
 # Grab the version from the source tree's milestone.
 # FUTURE Use Python API from bug 941299.
-with open(os.path.join(mozilla_dir, 'config', 'milestone.txt'), 'rt') as fh:
+with open(os.path.join(topsrcdir, 'config', 'milestone.txt'), 'rt') as fh:
     for line in fh:
         line = line.strip()
 
         if not line or line.startswith('#'):
             continue
 
         release = line
         break
 
 version = re.sub(r'[ab]\d+$', '', release)
 
-exclude_patterns = ['_build']
+exclude_patterns = ['_build', '_staging']
 pygments_style = 'sphinx'
 
 # Read The Docs can't import sphinx_rtd_theme, so don't import it there.
 on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
 
 if not on_rtd:
     import sphinx_rtd_theme
     html_theme = 'sphinx_rtd_theme'
--- a/tools/docs/mach_commands.py
+++ b/tools/docs/mach_commands.py
@@ -25,19 +25,21 @@ class Documentation(MachCommandBase):
     @CommandArgument('--format', default='html',
         help='Documentation format to write.')
     @CommandArgument('outdir', default='<DEFAULT>', nargs='?',
         help='Where to write output.')
     def build_docs(self, format=None, outdir=None):
         self._activate_virtualenv()
         self.virtualenv_manager.install_pip_package('sphinx_rtd_theme==0.1.6')
 
-        from moztreedocs import SphinxManager
+        import sphinx
 
         if outdir == '<DEFAULT>':
             outdir = os.path.join(self.topobjdir, 'docs')
 
-        manager = SphinxManager(self.topsrcdir, os.path.join(self.topsrcdir,
-            'tools', 'docs'), outdir)
+        args = [
+            'sphinx',
+            '-b', format,
+            os.path.join(self.topsrcdir, 'tools', 'docs'),
+            os.path.join(outdir, format),
+        ]
 
-        manager.read_build_config()
-
-        return manager.generate_docs(format)
+        return sphinx.main(args)
--- a/tools/docs/moztreedocs/__init__.py
+++ b/tools/docs/moztreedocs/__init__.py
@@ -16,17 +16,17 @@ 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._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."""
 
@@ -60,36 +60,25 @@ class SphinxManager(object):
 
     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, fmt):
-        """Generate documentation using Sphinx."""
+    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()
 
-        old_env = os.environ.copy()
-        try:
-            os.environ['MOZILLA_DIR'] = self._topsrcdir
-            args = [
-                'sphinx',
-                '-b', fmt,
-                self._docs_dir,
-                os.path.join(self._output_dir, fmt),
-            ]
-
-            return sphinx.main(args)
-        finally:
-            os.environ.clear()
-            os.environ.update(old_env)
-
     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)