Bug 1260327 - Expose a MOZ_CONFIGURE_OPTIONS variable containing configure options. r=chmanchester
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 13 Apr 2016 11:52:12 +0900
changeset 331186 450647e36329144c9a3de6bc6642cad717ee0c30
parent 331185 5864ce92b53344598fea07f25cabef72aa791514
child 331187 993766c094cfa8d3d8b8f34617bdf321d5fc4737
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschmanchester
bugs1260327
milestone48.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 1260327 - Expose a MOZ_CONFIGURE_OPTIONS variable containing configure options. r=chmanchester
build/moz.configure/init.configure
python/moz.build
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/test/configure/test_moz_configure.py
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -672,16 +672,52 @@ set_define('NIGHTLY_BUILD', delayed_geta
 add_old_configure_assignment('NIGHTLY_BUILD',
                              delayed_getattr(milestone, 'is_nightly'))
 set_config('RELEASE_BUILD', delayed_getattr(milestone, 'is_release'))
 set_define('RELEASE_BUILD', delayed_getattr(milestone, 'is_release'))
 add_old_configure_assignment('RELEASE_BUILD',
                              delayed_getattr(milestone, 'is_release'))
 
 
+# Set the MOZ_CONFIGURE_OPTIONS variable with all the options that
+# were passed somehow (environment, command line, mozconfig)
+@depends(mozconfig_options)
+@imports(_from='mozbuild.shellutil', _import='quote')
+@imports('__sandbox__')
+def all_configure_options(_):
+    result = []
+    previous = None
+    for option in __sandbox__._options.itervalues():
+        # __sandbox__._options contains items for both option.name and
+        # option.env. But it's also an OrderedDict, meaning both are
+        # consecutive.
+        # Also ignore OLD_CONFIGURE and MOZCONFIG because they're not
+        # interesting.
+        if option == previous or option.env in ('OLD_CONFIGURE', 'MOZCONFIG'):
+            continue
+        previous = option
+        value = __sandbox__._value_for(option)
+        # We only want options that were explicitly given on the command
+        # line, the environment, or mozconfig, and that differ from the
+        # defaults.
+        if (value.origin not in ('default', 'implied') and
+                value != option.default):
+            result.append(__sandbox__._raw_options[option])
+        # We however always include options that are sent to old configure
+        # because we don't know their actual defaults. (Keep the conditions
+        # separate for ease of understanding and ease of removal)
+        elif (option.help == 'Help missing for old configure options' and
+                option in __sandbox__._raw_options):
+            result.append(__sandbox__._raw_options[option])
+
+    return quote(*result)
+
+set_config('MOZ_CONFIGURE_OPTIONS', all_configure_options)
+
+
 # This is temporary until js/src/configure and configure are merged.
 # Use instead of option() in js/moz.configure and more generally, for
 # options that are shared between configure and js/src/configure.
 @template
 def js_option(*args, **kwargs):
     opt = option(*args, **kwargs)
 
     @depends(opt.option, build_project)
--- a/python/moz.build
+++ b/python/moz.build
@@ -33,16 +33,17 @@ PYTHON_UNIT_TESTS += [
     'mozbuild/mozbuild/test/backend/test_android_eclipse.py',
     'mozbuild/mozbuild/test/backend/test_build.py',
     'mozbuild/mozbuild/test/backend/test_configenvironment.py',
     'mozbuild/mozbuild/test/backend/test_recursivemake.py',
     'mozbuild/mozbuild/test/backend/test_visualstudio.py',
     'mozbuild/mozbuild/test/compilation/test_warnings.py',
     'mozbuild/mozbuild/test/configure/test_checks_configure.py',
     'mozbuild/mozbuild/test/configure/test_configure.py',
+    'mozbuild/mozbuild/test/configure/test_moz_configure.py',
     'mozbuild/mozbuild/test/configure/test_options.py',
     'mozbuild/mozbuild/test/configure/test_util.py',
     'mozbuild/mozbuild/test/controller/test_ccachestats.py',
     'mozbuild/mozbuild/test/controller/test_clobber.py',
     'mozbuild/mozbuild/test/frontend/test_context.py',
     'mozbuild/mozbuild/test/frontend/test_emitter.py',
     'mozbuild/mozbuild/test/frontend/test_namespaces.py',
     'mozbuild/mozbuild/test/frontend/test_reader.py',
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -114,17 +114,17 @@ class ConfigureSandbox(dict):
         # DependsFunction generated from @depends.
         self._depends = {}
         self._seen = set()
         # Store the @imports added to a given function.
         self._imports = {}
 
         self._options = OrderedDict()
         # Store raw option (as per command line or environment) for each Option
-        self._raw_options = {}
+        self._raw_options = OrderedDict()
 
         # Store options added with `imply_option`, and the reason they were
         # added (which can either have been given to `imply_option`, or
         # inferred. Their order matters, so use a list.
         self._implied_options = []
 
         # Store all results from _prepare_function
         self._prepared_functions = set()
@@ -337,22 +337,23 @@ class ConfigureSandbox(dict):
                 self._helper.add(opt, 'implied')
                 implied[opt] = implied_option
 
         try:
             value, option_string = self._helper.handle(option)
         except ConflictingOptionError as e:
             reason = implied[e.arg].reason
             reason = self._raw_options.get(reason) or reason.option
+            reason = reason.split('=', 1)[0]
             raise InvalidOptionError(
                 "'%s' implied by '%s' conflicts with '%s' from the %s"
                 % (e.arg, reason, e.old_arg, e.old_origin))
 
-        self._raw_options[option] = (option_string.split('=', 1)[0]
-                                     if option_string else option_string)
+        if option_string:
+            self._raw_options[option] = option_string
 
         return value
 
     def option_impl(self, *args, **kwargs):
         '''Implementation of option()
         This function creates and returns an Option() object, passing it the
         resolved arguments (uses the result of functions when functions are
         passed). In most cases, the result of this function is not expected to
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py
@@ -0,0 +1,98 @@
+# 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, print_function, unicode_literals
+
+from StringIO import StringIO
+import os
+import tempfile
+import textwrap
+import unittest
+
+from mozunit import main
+
+from mozbuild.configure import ConfigureSandbox
+
+from buildconfig import (
+    topobjdir,
+    topsrcdir,
+)
+
+
+class TestMozConfigure(unittest.TestCase):
+    def setUp(self):
+        self._cwd = os.getcwd()
+
+    def tearDown(self):
+        os.chdir(self._cwd)
+
+    def get_value_for(self, key, args=[], environ={}, mozconfig=''):
+        os.chdir(topobjdir)
+
+        config = {}
+        out = StringIO()
+
+        fh, mozconfig_path = tempfile.mkstemp()
+        os.write(fh, mozconfig)
+        os.close(fh)
+
+        try:
+            environ = dict(environ,
+                           OLD_CONFIGURE=os.path.join(topsrcdir, 'configure'),
+                           MOZCONFIG=mozconfig_path)
+
+            sandbox = ConfigureSandbox(config, environ, ['configure'] + args,
+                                       out, out)
+            sandbox.include_file(os.path.join(topsrcdir, 'moz.configure'))
+
+            # Add a fake old-configure option
+            sandbox.option_impl('--with-foo', nargs='*',
+                                help='Help missing for old configure options')
+
+            return sandbox._value_for(sandbox[key])
+        finally:
+            os.remove(mozconfig_path)
+
+    def test_moz_configure_options(self):
+        def get_value_for(args=[], environ={}, mozconfig=''):
+            return self.get_value_for('all_configure_options', args, environ,
+                                      mozconfig)
+
+        self.assertEquals('--enable-application=browser',
+                          get_value_for(['--enable-application=browser']))
+
+        self.assertEquals('--enable-application=browser '
+                          'MOZ_PROFILING=1',
+                          get_value_for(['--enable-application=browser',
+                                         'MOZ_PROFILING=1']))
+
+        value = get_value_for(
+            environ={'MOZ_PROFILING': '1'},
+            mozconfig='ac_add_options --enable-project=js')
+
+        self.assertEquals('--enable-project=js MOZ_PROFILING=1',
+                          value)
+
+        # --disable-js-shell is the default, so it's filtered out.
+        self.assertEquals('--enable-application=browser',
+                          get_value_for(['--enable-application=browser',
+                                         '--disable-js-shell']))
+
+        # Normally, --without-foo would be filtered out because that's the
+        # default, but since it is a (fake) old-configure option, it always
+        # appears.
+        self.assertEquals('--enable-application=browser --without-foo',
+                          get_value_for(['--enable-application=browser',
+                                         '--without-foo']))
+        self.assertEquals('--enable-application=browser --with-foo',
+                          get_value_for(['--enable-application=browser',
+                                         '--with-foo']))
+
+        self.assertEquals("--enable-application=browser '--with-foo=foo bar'",
+                          get_value_for(['--enable-application=browser',
+                                         '--with-foo=foo bar']))
+
+
+if __name__ == '__main__':
+    main()