diff --git a/python/mozbuild/mozbuild/frontend/reader.py b/python/mozbuild/mozbuild/frontend/reader.py index c6096f45944..5013324072a 100644 --- a/python/mozbuild/mozbuild/frontend/reader.py +++ b/python/mozbuild/mozbuild/frontend/reader.py @@ -181,6 +181,10 @@ class MozbuildSandbox(Sandbox): 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. @@ -242,6 +246,30 @@ class MozbuildSandbox(Sandbox): 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.""" @@ -680,6 +708,9 @@ class BuildReader(object): 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: diff --git a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py index 14059198091..9e3635f32ff 100644 --- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py +++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py @@ -575,6 +575,34 @@ FUNCTIONS = { 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. diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/bar/moz.build new file mode 100644 index 00000000000..e0755bf8f3d --- /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' diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/baz/moz.build new file mode 100644 index 00000000000..c271ec3908c --- /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/. diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/foo/moz.build new file mode 100644 index 00000000000..ff02beaadc7 --- /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'] diff --git a/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build b/python/mozbuild/mozbuild/test/frontend/data/inheriting-variables/moz.build new file mode 100644 index 00000000000..dde0a80b188 --- /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'] diff --git a/python/mozbuild/mozbuild/test/frontend/test_reader.py b/python/mozbuild/mozbuild/test/frontend/test_reader.py index 9c08202fdcc..9d2ffe66b81 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_reader.py +++ b/python/mozbuild/mozbuild/test/frontend/test_reader.py @@ -253,5 +253,16 @@ class TestBuildReader(unittest.TestCase): 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()