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 160090 0eec37596a6d1c0a0ff1077d518cd1df3e0e0c26
parent 160089 d6f19da0dfb30c6b74e7d1765de2c119ceaa0ff8
child 160091 95c9865ac36688fb99013c8b0adf5d38e3d8612e
push id25821
push usercbook@mozilla.com
push dateThu, 12 Dec 2013 11:53:39 +0000
treeherdermozilla-central@d15ed5648a5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs939367
milestone29.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 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