Bug 939367 - Allow Sphinx docs to come from all over the tree; r=glandium
authorGregory Szorc <gps@mozilla.com>
Wed, 20 Nov 2013 12:37:22 -0800
changeset 160134 0eec37596a6d1c0a0ff1077d518cd1df3e0e0c26
parent 160133 d6f19da0dfb30c6b74e7d1765de2c119ceaa0ff8
child 160135 95c9865ac36688fb99013c8b0adf5d38e3d8612e
push id3938
push usercbook@mozilla.com
push dateThu, 12 Dec 2013 15:09:56 +0000
treeherderfx-team@0cf1107e2791 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs939367
milestone29.0a1
Bug 939367 - Allow Sphinx docs to come from all over the tree; r=glandium
build/docs/Vagrantfile
build/docs/conf.py
build/docs/index.rst
build/docs/python/makeutils.rst
build/docs/python/mozbuild.action.rst
build/docs/python/mozbuild.backend.rst
build/docs/python/mozbuild.compilation.rst
build/docs/python/mozbuild.controller.rst
build/docs/python/mozbuild.frontend.rst
build/docs/python/mozbuild.rst
build/docs/python/mozpack.chrome.rst
build/docs/python/mozpack.packager.rst
build/docs/python/mozpack.rst
build/docs/python/mozversioncontrol.rst
build/mach_bootstrap.py
build/moz.build
build/virtualenv_packages.txt
js/src/shell/moz.build
python/moz.build
python/mozbuild/mozbuild/frontend/reader.py
python/mozbuild/mozbuild/frontend/sandbox_symbols.py
python/mozbuild/mozbuild/mach_commands.py
tools/docs/Vagrantfile
tools/docs/conf.py
tools/docs/index.rst
tools/docs/mach_commands.py
tools/docs/moztreedocs/__init__.py
widget/gonk/libdisplay/moz.build
deleted file mode 100644
--- a/build/docs/Vagrantfile
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- mode: ruby -*-
-# vi: set ft=ruby :
-
-# We intentionally use the old config format because Mozilla's Jenkins
-# server doesn't run a modern Vagrant.
-Vagrant::Config.run do |config|
-  config.vm.box = "precise64"
-  config.vm.box_url = "http://files.vagrantup.com/precise64.box"
-  config.vm.share_folder("gecko", "/gecko", "../..")
-  # Doxygen needs more than the default memory or it will swap and be
-  # extremely slow.
-  config.vm.customize ["modifyvm", :id, "--memory", 2048]
-end
deleted file mode 100644
--- a/build/docs/conf.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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
-
-from datetime import datetime
-
-
-here = os.path.abspath(os.path.dirname(__file__))
-mozilla_dir = os.path.normpath(os.path.join(here, '..', '..'))
-
-import mdn_theme
-
-extensions = [
-    'sphinx.ext.autodoc',
-    'sphinx.ext.graphviz',
-    'sphinx.ext.todo',
-    'mozbuild.sphinx',
-]
-
-templates_path = ['_templates']
-source_suffix = '.rst'
-master_doc = 'index'
-project = u'Mozilla Build System'
-year = datetime.now().year
-
-# Grab the version from the source tree's milestone.
-with open(os.path.join(mozilla_dir, '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']
-pygments_style = 'sphinx'
-
-html_theme_path = [mdn_theme.get_theme_dir()]
-html_theme = 'mdn'
-
-html_static_path = ['_static']
-htmlhelp_basename = 'MozillaBuildSystemdoc'
--- a/build/docs/index.rst
+++ b/build/docs/index.rst
@@ -1,25 +1,18 @@
-==================================
-Mozilla Build System Documentation
-==================================
-
-Overview
-========
-
-.. toctree::
-   :maxdepth: 1
-
-   glossary
+============
+Build System
+============
 
 Important Concepts
 ==================
 .. toctree::
    :maxdepth: 1
 
+   glossary
    build-overview
    supported-configurations
    Mozconfig Files <mozconfigs>
    mozbuild-files
    mozbuild-symbols
    Profile Guided Optimization <pgo>
    slow
    environment-variables
@@ -36,29 +29,8 @@ mozbuild
 mozbuild is a Python package containing a lot of the code for the
 Mozilla build system.
 
 .. toctree::
    :maxdepth: 1
 
    mozbuild/index
    mozbuild/dumbmake
-
-Python Packages
-===============
-
-.. toctree::
-   :maxdepth: 2
-
-   python/codegen
-   python/makeutils
-   python/mozbuild
-   python/mozpack
-   python/mozversioncontrol
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
deleted file mode 100644
--- a/build/docs/python/makeutils.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-makeutils Module
-================
-
-.. automodule:: makeutils
-    :members:
-    :undoc-members:
-    :show-inheritance:
deleted file mode 100644
--- a/build/docs/python/mozbuild.action.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-action Package
-==============
-
-:mod:`link_deps` Module
------------------------
-
-.. automodule:: mozbuild.action.link_deps
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`process_install_manifest` Module
---------------------------------------
-
-.. automodule:: mozbuild.action.process_install_manifest
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`xpccheck` Module
-----------------------
-
-.. automodule:: mozbuild.action.xpccheck
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`xpidl-process` Module
----------------------------
-
-.. automodule:: mozbuild.action.xpidl-process
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozbuild.backend.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-backend Package
-===============
-
-:mod:`base` Module
-------------------
-
-.. automodule:: mozbuild.backend.base
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`common` Module
---------------------
-
-.. automodule:: mozbuild.backend.common
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`configenvironment` Module
--------------------------------
-
-.. automodule:: mozbuild.backend.configenvironment
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`recursivemake` Module
----------------------------
-
-.. automodule:: mozbuild.backend.recursivemake
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozbuild.compilation.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-compilation Package
-===================
-
-:mod:`warnings` Module
-----------------------
-
-.. automodule:: mozbuild.compilation.warnings
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozbuild.controller.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-controller Package
-==================
-
-:mod:`building` Module
-----------------------
-
-.. automodule:: mozbuild.controller.building
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`clobber` Module
----------------------
-
-.. automodule:: mozbuild.controller.clobber
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozbuild.frontend.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-frontend Package
-================
-
-:mod:`data` Module
-------------------
-
-.. automodule:: mozbuild.frontend.data
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`emitter` Module
----------------------
-
-.. automodule:: mozbuild.frontend.emitter
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`mach_commands` Module
----------------------------
-
-.. automodule:: mozbuild.frontend.mach_commands
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`reader` Module
---------------------
-
-.. automodule:: mozbuild.frontend.reader
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`sandbox` Module
----------------------
-
-.. automodule:: mozbuild.frontend.sandbox
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`sandbox_symbols` Module
------------------------------
-
-.. automodule:: mozbuild.frontend.sandbox_symbols
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozbuild.rst
+++ /dev/null
@@ -1,103 +0,0 @@
-mozbuild Package
-================
-
-:mod:`base` Module
-------------------
-
-.. automodule:: mozbuild.base
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`config` Module
---------------------
-
-.. automodule:: mozbuild.config
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`html_build_viewer` Module
--------------------------------
-
-.. automodule:: mozbuild.html_build_viewer
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`mach_commands` Module
----------------------------
-
-.. automodule:: mozbuild.mach_commands
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`makeutil` Module
-----------------------
-
-.. automodule:: mozbuild.makeutil
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`mozconfig` Module
------------------------
-
-.. automodule:: mozbuild.mozconfig
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`mozinfo` Module
----------------------
-
-.. automodule:: mozbuild.mozinfo
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`pythonutil` Module
-------------------------
-
-.. automodule:: mozbuild.pythonutil
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`sphinx` Module
---------------------
-
-.. automodule:: mozbuild.sphinx
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`util` Module
-------------------
-
-.. automodule:: mozbuild.util
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`virtualenv` Module
-------------------------
-
-.. automodule:: mozbuild.virtualenv
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-Subpackages
------------
-
-.. toctree::
-
-    mozbuild.action
-    mozbuild.backend
-    mozbuild.compilation
-    mozbuild.controller
-    mozbuild.frontend
-    mozbuild.test
-
deleted file mode 100644
--- a/build/docs/python/mozpack.chrome.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-chrome Package
-==============
-
-:mod:`flags` Module
--------------------
-
-.. automodule:: mozpack.chrome.flags
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`manifest` Module
-----------------------
-
-.. automodule:: mozpack.chrome.manifest
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozpack.packager.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-packager Package
-================
-
-:mod:`packager` Package
------------------------
-
-.. automodule:: mozpack.packager
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`formats` Module
----------------------
-
-.. automodule:: mozpack.packager.formats
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`l10n` Module
-------------------
-
-.. automodule:: mozpack.packager.l10n
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`unpack` Module
---------------------
-
-.. automodule:: mozpack.packager.unpack
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
deleted file mode 100644
--- a/build/docs/python/mozpack.rst
+++ /dev/null
@@ -1,76 +0,0 @@
-mozpack Package
-===============
-
-:mod:`copier` Module
---------------------
-
-.. automodule:: mozpack.copier
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`errors` Module
---------------------
-
-.. automodule:: mozpack.errors
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`executables` Module
--------------------------
-
-.. automodule:: mozpack.executables
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`files` Module
--------------------
-
-.. automodule:: mozpack.files
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`manifests` Module
------------------------
-
-.. automodule:: mozpack.manifests
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`mozjar` Module
---------------------
-
-.. automodule:: mozpack.mozjar
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`path` Module
-------------------
-
-.. automodule:: mozpack.path
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`unify` Module
--------------------
-
-.. automodule:: mozpack.unify
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-Subpackages
------------
-
-.. toctree::
-
-    mozpack.chrome
-    mozpack.packager
-    mozpack.test
-
deleted file mode 100644
--- a/build/docs/python/mozversioncontrol.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-mozversioncontrol Package
-=========================
-
-:mod:`repoupdate` Module
-------------------------
-
-.. automodule:: mozversioncontrol.repoupdate
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -70,16 +70,17 @@ MACH_MODULES = [
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/frontend/mach_commands.py',
     'testing/mach_commands.py',
     'testing/marionette/mach_commands.py',
     'testing/mochitest/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
     'testing/talos/mach_commands.py',
     'testing/xpcshell/mach_commands.py',
+    'tools/docs/mach_commands.py',
     'tools/mercurial/mach_commands.py',
     'tools/mach_commands.py',
 ]
 
 
 CATEGORIES = {
     'build': {
         'short': 'Build Commands',
--- a/build/moz.build
+++ b/build/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+SPHINX_TREES['build'] = 'docs'
+
 if CONFIG['OS_ARCH'] not in ('WINNT', 'OS2'):
     DIRS += ['unix']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['win32']
 
 if CONFIG['OS_TARGET'] == 'Android' and not CONFIG['MOZ_ANDROID_LIBSTDCXX']:
     DIRS += ['stlport']
 
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -8,11 +8,12 @@ optional:setup.py:python/psutil:build_ex
 optional:psutil.pth:python/psutil
 which.pth:python/which
 ply.pth:other-licenses/ply/
 codegen.pth:python/codegen/
 mock.pth:python/mock-1.0.0
 mozilla.pth:build
 mozilla.pth:config
 mozilla.pth:xpcom/typelib/xpt/tools
+moztreedocs.pth:tools/docs
 copy:build/buildconfig.py
 packages.txt:testing/mozbase/packages.txt
 objdir:build
--- a/js/src/shell/moz.build
+++ b/js/src/shell/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-PROGRAM = CONFIG['JS_SHELL_NAME']
+if CONFIG['JS_SHELL_NAME']:
+    PROGRAM = CONFIG['JS_SHELL_NAME']
 
 UNIFIED_SOURCES += [
     'js.cpp',
     'jsheaptools.cpp',
     'jsoptparse.cpp',
 ]
 
 # Building against js_static requires that we declare mfbt sybols "exported"
--- a/python/moz.build
+++ b/python/moz.build
@@ -1,6 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+SPHINX_PYTHON_PACKAGE_DIRS += [
+    'codegen',
+    'mozbuild/mozbuild',
+    'mozbuild/mozpack',
+    'mozversioncontrol/mozversioncontrol',
+]
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -35,16 +35,17 @@ from io import StringIO
 
 from mozbuild.util import (
     ReadOnlyDefaultDict,
     ReadOnlyDict,
 )
 
 from mozbuild.backend.configenvironment import ConfigEnvironment
 
+from mozpack.files import FileFinder
 import mozpack.path as mozpath
 
 from .data import (
     JavaJarData,
 )
 
 from .sandbox import (
     SandboxError,
@@ -509,17 +510,17 @@ class BuildReaderError(Exception):
             self._print_keyerror(inner, s)
         elif isinstance(inner, ValueError):
             self._print_valueerror(inner, s)
         else:
             self._print_exception(inner, s)
 
     def _print_keyerror(self, inner, s):
         if inner.args[0] not in ('global_ns', 'local_ns'):
-            self._print_exception(unner, s)
+            self._print_exception(inner, s)
             return
 
         if inner.args[0] == 'global_ns':
             verb = None
             if inner.args[1] == 'get_unknown':
                 verb = 'read'
             elif inner.args[1] == 'set_unknown':
                 verb = 'write'
@@ -592,34 +593,64 @@ class BuildReader(object):
     This is where the build system starts. You give it a tree configuration
     (the output of configuration) and it executes the moz.build files and
     collects the data they define.
     """
 
     def __init__(self, config):
         self.config = config
         self.topsrcdir = config.topsrcdir
+        self.topobjdir = config.topobjdir
 
         self._log = logging.getLogger(__name__)
         self._read_files = set()
         self._execution_stack = []
 
     def read_topsrcdir(self):
-        """Read the tree of mozconfig files into a data structure.
+        """Read the tree of linked moz.build files.
 
-        This starts with the tree's top-most mozbuild file and descends into
-        all linked mozbuild files until all relevant files have been evaluated.
+        This starts with the tree's top-most moz.build file and descends into
+        all linked moz.build files until all relevant files have been evaluated.
 
-        This is a generator of Sandbox instances. As each mozbuild file is
-        read, a new Sandbox is created. Each created Sandbox is returned.
+        This is a generator of Sandbox instances. As each moz.build file is
+        read, a new Sandbox is created and emitted.
         """
         path = mozpath.join(self.topsrcdir, 'moz.build')
         return self.read_mozbuild(path, read_tiers=True,
             filesystem_absolute=True, metadata={'tier': None})
 
+    def walk_topsrcdir(self):
+        """Read all moz.build files in the source tree.
+
+        This is different from read_topsrcdir() in that this version performs a
+        filesystem walk to discover every moz.build file rather than relying on
+        data from executed moz.build files to drive traversal.
+
+        This is a generator of Sandbox instances.
+        """
+        # In the future, we may traverse moz.build files by looking
+        # for DIRS references in the AST, even if a directory is added behind
+        # a conditional. For now, just walk the filesystem.
+        ignore = {
+            # Ignore fake moz.build files used for testing moz.build.
+            'python/mozbuild/mozbuild/test',
+
+            # Ignore object directories.
+            'obj*',
+        }
+
+        finder = FileFinder(self.topsrcdir, find_executables=False,
+            ignore=ignore)
+
+        for path, f in finder.find('**/moz.build'):
+            path = os.path.join(self.topsrcdir, path)
+            for s in self.read_mozbuild(path, descend=False,
+                filesystem_absolute=True, read_tiers=True):
+                yield s
+
     def read_mozbuild(self, path, read_tiers=False, filesystem_absolute=False,
             descend=True, metadata={}):
         """Read and process a mozbuild file, descending into children.
 
         This starts with a single mozbuild file, executes it, and descends into
         other referenced files per our traversal logic.
 
         The traversal logic is to iterate over the *DIRS variables, treating
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -566,16 +566,28 @@ VARIABLES = {
         """The name of the directory to install targets to.
 
         The directory is relative to the top of the object directory. The
         default value is dependent on the values of XPI_NAME and DIST_SUBDIR. If
         neither are present, the result is dist/bin. If XPI_NAME is present, the
         result is dist/xpi-stage/$(XPI_NAME). If DIST_SUBDIR is present, then
         the $(DIST_SUBDIR) directory of the otherwise default value is used.
         """, 'libs'),
+
+    'SPHINX_TREES': (dict, dict,
+        """Describes what the Sphinx documentation tree will look like.
+
+        Keys are relative directories inside the final Sphinx documentation
+        tree to install files into. Values are directories (relative to this
+        file) whose content to copy into the Sphinx documentation tree.
+        """, None),
+
+    'SPHINX_PYTHON_PACKAGE_DIRS': (StrictOrderingOnAppendList, list,
+        """Directories containing Python packages that Sphinx documents.
+        """, None),
 }
 
 # The set of functions exposed to the sandbox.
 #
 # Each entry is a tuple of:
 #
 #  (method attribute, (argument types), docs)
 #
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -987,67 +987,8 @@ class MachDebug(MachCommandBase):
             if verbose:
                 print('config substitutions:')
                 for k in sorted(config.substs):
                     print('\t%s: %s' % (k, config.substs[k]))
 
                 print('config defines:')
                 for k in sorted(config.defines):
                     print('\t%s' % k)
-
-
-@CommandProvider
-class Documentation(MachCommandBase):
-    """Helps manage in-tree documentation."""
-
-    @Command('build-docs', category='build-dev',
-        description='Generate documentation for the tree.')
-    @CommandArgument('--format', default='html',
-        help='Documentation format to write.')
-    @CommandArgument('--api-docs', action='store_true',
-        help='If specified, we will generate api docs templates for in-tree '
-            'Python. This will likely create and/or modify files in '
-            'build/docs. It is meant to be run by build maintainers when new '
-            'Python modules are added to the tree.')
-    @CommandArgument('outdir', default='<DEFAULT>', nargs='?',
-        help='Where to write output.')
-    def build_docs(self, format=None, api_docs=False, outdir=None):
-        self._activate_virtualenv()
-
-        self.virtualenv_manager.install_pip_package('mdn-sphinx-theme==0.3')
-
-        if api_docs:
-            import sphinx.apidoc
-            outdir = os.path.join(self.topsrcdir, 'build', 'docs', 'python')
-
-            base_args = [sys.argv[0], '--no-toc', '-o', outdir]
-
-            packages = [
-                ('python/codegen',),
-                ('python/mozbuild/mozbuild', 'test'),
-                ('python/mozbuild/mozpack', 'test'),
-                ('python/mozversioncontrol/mozversioncontrol',),
-            ]
-
-            for package in packages:
-                extra_args = [os.path.join(self.topsrcdir, package[0])]
-                extra_args.extend(package[1:])
-
-                sphinx.apidoc.main(base_args + extra_args)
-
-            return 0
-
-        import sphinx
-        if outdir == '<DEFAULT>':
-            outdir = os.path.join(self.topobjdir, 'docs', format)
-
-        args = [
-            sys.argv[0],
-            '-b', format,
-            os.path.join(self.topsrcdir, 'build', 'docs'),
-            outdir,
-        ]
-
-        result = sphinx.main(args)
-
-        print('Docs written to %s.' % outdir)
-
-        return result
new file mode 100644
--- /dev/null
+++ b/tools/docs/Vagrantfile
@@ -0,0 +1,13 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# We intentionally use the old config format because Mozilla's Jenkins
+# server doesn't run a modern Vagrant.
+Vagrant::Config.run do |config|
+  config.vm.box = "precise64"
+  config.vm.box_url = "http://files.vagrantup.com/precise64.box"
+  config.vm.share_folder("gecko", "/gecko", "../..")
+  # Doxygen needs more than the default memory or it will swap and be
+  # extremely slow.
+  config.vm.customize ["modifyvm", :id, "--memory", 2048]
+end
new file mode 100644
--- /dev/null
+++ b/tools/docs/conf.py
@@ -0,0 +1,51 @@
+# 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
+
+from datetime import datetime
+
+
+mozilla_dir = os.environ['MOZILLA_DIR']
+
+import mdn_theme
+
+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:
+    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']
+pygments_style = 'sphinx'
+
+html_theme_path = [mdn_theme.get_theme_dir()]
+html_theme = 'mdn'
+
+html_static_path = ['_static']
+htmlhelp_basename = 'MozillaTreeDocs'
new file mode 100644
--- /dev/null
+++ b/tools/docs/index.rst
@@ -0,0 +1,58 @@
+=================================
+Mozilla Source Tree Documentation
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   {indexes}
+
+Python Packages
+===============
+
+.. toctree::
+   :maxdepth: 2
+
+   {python_packages}
+
+Managing Documentation
+======================
+
+This documentation is generated via the
+`Sphinx <http://sphinx-doc.org/>`_ tool from sources in the tree.
+
+To build the documentation, run ``mach build-docs``. Run
+``mach help build-docs`` to see configurable options.
+
+Adding Documentation
+--------------------
+
+To add new documentation, define the ``SPHINX_TREES`` and
+``SPHINX_PYTHON_PACKAGE_DIRS`` variables in ``moz.build`` files in
+the tree and documentation will automatically get picked up.
+
+Say you have a directory ``featureX`` you would like to write some
+documentation for. Here are the steps to create Sphinx documentation
+for it:
+
+1. Create a directory for the docs. This is typically ``docs``. e.g.
+   ``featureX/docs``.
+2. Create an ``index.rst`` file in this directory. The ``index.rst`` file
+   is the root documentation for that section. See ``build/docs/index.rst``
+   for an example file.
+3. In a ``moz.build`` file (typically the one in the parent directory of
+   the ``docs`` directory), define ``SPHINX_TREES`` to hook up the plumbing.
+   e.g. ``SPHINX_TREES['featureX'] = 'docs'``. This says *the ``docs``
+   directory under the current directory should be installed into the
+   Sphinx documentation tree under ``/featureX``*.
+4. If you have Python packages you would like to generate Python API
+   documentation for, you can use ``SPHINX_PYTHON_PACKAGE_DIRS`` to
+   declare directories containing Python packages. e.g.
+   ``SPHINX_PYTHON_PACKAGE_DIRS += ['mozpackage']``.
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
new file mode 100644
--- /dev/null
+++ b/tools/docs/mach_commands.py
@@ -0,0 +1,51 @@
+# 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 mach.decorators import (
+    CommandArgument,
+    CommandProvider,
+    Command,
+)
+
+from mozbuild.base import MachCommandBase
+from mozbuild.frontend.reader import BuildReader
+
+
+@CommandProvider
+class Documentation(MachCommandBase):
+    """Helps manage in-tree documentation."""
+
+    @Command('build-docs', category='build-dev',
+        description='Generate documentation for the tree.')
+    @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('mdn-sphinx-theme==0.4')
+
+        from moztreedocs import SphinxManager
+
+        if outdir == '<DEFAULT>':
+            outdir = os.path.join(self.topobjdir, 'docs')
+
+        manager = SphinxManager(self.topsrcdir, os.path.join(self.topsrcdir,
+            'tools', 'docs'), outdir)
+
+        reader = BuildReader(self.config_environment)
+        for sandbox in reader.walk_topsrcdir():
+            for dest_dir, source_dir in sandbox['SPHINX_TREES'].items():
+                manager.add_tree(os.path.join(sandbox['RELATIVEDIR'],
+                    source_dir), dest_dir)
+
+            for entry in sandbox['SPHINX_PYTHON_PACKAGE_DIRS']:
+                manager.add_python_package_dir(os.path.join(sandbox['RELATIVEDIR'],
+                    entry))
+
+        return manager.generate_docs(format)
new file mode 100644
--- /dev/null
+++ b/tools/docs/moztreedocs/__init__.py
@@ -0,0 +1,113 @@
+# 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 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._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 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, fmt):
+        """Generate documentation using Sphinx."""
+        self._synchronize_docs()
+        self._generate_python_api_docs()
+
+        old_env = os.environ.copy()
+        try:
+            os.environ['MOZILLA_DIR'] = self._topsrcdir
+            args = [
+                'sphinx',
+                '-b', fmt,
+                os.path.join(self._output_dir, 'staging'),
+                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._output_dir, 'staging', '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))
+
+        stage_dir = os.path.join(self._output_dir, 'staging')
+        copier = FileCopier()
+        m.populate_registry(copier)
+        copier.copy(stage_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(stage_dir, 'index.rst'), 'wb') as fh:
+            fh.write(data)
--- a/widget/gonk/libdisplay/moz.build
+++ b/widget/gonk/libdisplay/moz.build
@@ -28,17 +28,17 @@ elif CONFIG['ANDROID_VERSION'] == '17':
         'FramebufferSurface.cpp',
         'GonkDisplayJB.cpp',
         'GraphicBufferAlloc.cpp',
     ]
 elif CONFIG['ANDROID_VERSION'] == '15':
     SOURCES += [
         'GonkDisplayICS.cpp'
     ]
-elif CONFIG['COMPILE_ENVIRONMENT']:
+elif CONFIG['ANDROID_VERSION'] and CONFIG['COMPILE_ENVIRONMENT']:
     error('Unsupported platform version: %s' % (CONFIG['ANDROID_VERSION']))
 
 LIBRARY_NAME = 'display'
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FORCE_STATIC_LIB = True