Bug 900526, part 1: Allow inheritable moz.build variables, r=gps.
authorJoshua Cranmer <Pidgeot18@gmail.com>
Mon, 21 Oct 2013 13:07:30 -0500
changeset 166363 5709e2db35ff8484b695befd64a26224ef6eaff7
parent 166362 a92ac47a8ba759ff99379ddad1f45323b9707d2e
child 166364 fb42a764f90bc91a628e472889e00b27b28b55ed
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs900526
milestone27.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 900526, part 1: Allow inheritable moz.build variables, r=gps.
python/mozbuild/mozbuild/frontend/reader.py
python/mozbuild/mozbuild/frontend/sandbox_symbols.py
python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build
python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build
python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build
python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build
python/mozbuild/mozbuild/test/frontend/test_reader.py
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -176,16 +176,20 @@ class MozbuildSandbox(Sandbox):
             var = metadata.get('var', None)
             if var and var in ['TOOL_DIRS', 'TEST_TOOL_DIRS']:
                 d['IS_TOOL_DIR'] = True
 
             # Register functions.
             for name, func in FUNCTIONS.items():
                 d[name] = getattr(self, func[0])
 
+        # Initialize the exports that we need in the global.
+        extra_vars = self.metadata.get('exports', dict())
+        self._globals.update(extra_vars)
+
     def exec_file(self, path, filesystem_absolute=False):
         """Override exec_file to normalize paths and restrict file loading.
 
         If the path is absolute, behavior is governed by filesystem_absolute.
         If filesystem_absolute is True, the path is interpreted as absolute on
         the actual filesystem. If it is false, the path is treated as absolute
         within the current topsrcdir.
 
@@ -237,16 +241,40 @@ class MozbuildSandbox(Sandbox):
 
         for path in reldir:
             if path in self['TIERS'][tier][key]:
                 raise Exception('Directory has already been registered with '
                     'tier: %s' % path)
 
             self['TIERS'][tier][key].append(path)
 
+    def _export(self, varname):
+        """Export the variable to all subdirectories of the current path."""
+
+        exports = self.metadata.setdefault('exports', dict())
+        if varname in exports:
+            raise Exception('Variable has already been exported: %s' % varname)
+
+        try:
+            # Doing a regular self._globals[varname] causes a set as a side
+            # effect. By calling the dict method instead, we don't have any
+            # side effects.
+            exports[varname] = dict.__getitem__(self._globals, varname)
+        except KeyError:
+            self.last_name_error = KeyError('global_ns', 'get_unknown', varname)
+            raise self.last_name_error
+
+    def recompute_exports(self):
+        """Recompute the variables to export to subdirectories with the current
+        values in the subdirectory."""
+
+        if 'exports' in self.metadata:
+            for key in self.metadata['exports']:
+                self.metadata['exports'][key] = self[key]
+
     def _include(self, path):
         """Include and exec another file within the context of this one."""
 
         # exec_file() handles normalization and verification of the path.
         self.exec_file(path)
 
     def _warning(self, message):
         # FUTURE consider capturing warnings in a variable instead of printing.
@@ -675,16 +703,19 @@ class BuildReader(object):
                 if d in recurse_info:
                     raise SandboxValidationError(
                         'Directory (%s) registered multiple times in %s' % (
                             d, var))
 
                 recurse_info[d] = {'tier': metadata.get('tier', None),
                                    'parent': sandbox['RELATIVEDIR'],
                                    'var': var}
+                if 'exports' in sandbox.metadata:
+                    sandbox.recompute_exports()
+                    recurse_info[d]['exports'] = sandbox.metadata['exports']
 
         # We also have tiers whose members are directories.
         if 'TIERS' in sandbox:
             if not read_tiers:
                 raise SandboxValidationError(
                     'TIERS defined but it should not be')
 
             for tier, values in sandbox['TIERS'].items():
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -570,16 +570,44 @@ FUNCTIONS = {
            add_tier_dir('base', 'foo', static=True)
 
         Register a directory as having external content (same as static
         content, but traversed with export, libs, and tools subtiers::
 
            add_tier_dir('base', 'bar', external=True)
         """),
 
+    'export': ('_export', (str,),
+        """Make the specified variable available to all child directories.
+
+        The variable specified by the argument string is added to the
+        environment of all directories specified in the DIRS, PARALLEL_DIRS,
+        TOOL_DIRS, TEST_DIRS, and TEST_TOOL_DIRS variables. If those directories
+        themselves have child directories, the variable will be exported to all
+        of them.
+
+        The value used for the variable is the final value at the end of the
+        moz.build file, so it is possible (but not recommended style) to place
+        the export before the definition of the variable.
+
+        This function is limited to the upper-case variables that have special
+        meaning in moz.build files.
+
+        NOTE: Please consult with a build peer before adding a new use of this
+        function.
+
+        Example usage
+        ^^^^^^^^^^^^^
+
+        To make all children directories install as the given extension::
+
+          XPI_NAME = 'cool-extension'
+          export('XPI_NAME')
+        """),
+
     'warning': ('_warning', (str,),
         """Issue a warning.
 
         Warnings are string messages that are printed during execution.
 
         Warnings are ignored during execution.
         """),
 
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build
@@ -0,0 +1,7 @@
+# -*- 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/.
+
+XPIDL_MODULE = 'bazbar'
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build
@@ -0,0 +1,5 @@
+# -*- 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/.
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build
@@ -0,0 +1,7 @@
+# -*- 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/.
+
+DIRS += ['baz']
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build
@@ -0,0 +1,10 @@
+# -*- 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/.
+
+XPIDL_MODULE = 'foobar'
+export("XPIDL_MODULE")
+
+DIRS += ['foo', 'bar']
--- a/python/mozbuild/mozbuild/test/frontend/test_reader.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_reader.py
@@ -248,10 +248,21 @@ class TestBuildReader(unittest.TestCase)
         reader = self.reader('reader-error-traversal-tools')
 
         with self.assertRaises(BuildReaderError) as bre:
             list(reader.read_topsrcdir())
 
         e = bre.exception
         self.assertIn('The DIRS variable is not allowed in such directories.', str(e))
 
+    def test_inheriting_variables(self):
+        reader = self.reader('inheriting-variables')
+
+        sandboxes = list(reader.read_topsrcdir())
+
+        self.assertEqual(len(sandboxes), 4)
+        self.assertEqual([sandbox['RELATIVEDIR'] for sandbox in sandboxes],
+            ['', 'foo', 'foo/baz', 'bar'])
+        self.assertEqual([sandbox['XPIDL_MODULE'] for sandbox in sandboxes],
+            ['foobar', 'foobar', 'foobar', 'bazbar'])
+
 if __name__ == '__main__':
     main()