Bug 1257049 - Stop spawning a separate process for config.status from configure.py. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 19 Aug 2016 11:11:57 +0900
changeset 310399 ee9f4eeaebe897ec6d5e76ab7c4ace8d4782de18
parent 310328 30fa88c82366a358f412ca2cc3268142c8991f0d
child 310400 c3edbba2eb8aa5484eb41511bb0ce5269d3dfd11
push idunknown
push userunknown
push dateunknown
reviewersgps
bugs1257049
milestone51.0a1
Bug 1257049 - Stop spawning a separate process for config.status from configure.py. r=gps
configure.py
python/mozbuild/mozbuild/config_status.py
--- a/configure.py
+++ b/configure.py
@@ -5,16 +5,18 @@
 from __future__ import print_function, unicode_literals
 
 import codecs
 import json
 import os
 import subprocess
 import sys
 
+from collections import Iterable
+
 
 base_dir = os.path.abspath(os.path.dirname(__file__))
 sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild'))
 from mozbuild.configure import ConfigureSandbox
 
 
 def main(argv):
     config = {}
@@ -74,21 +76,43 @@ def config_status(config):
         if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'):
             fh.write('''
 if __name__ == '__main__':
     args = dict([(name, globals()[name]) for name in __all__])
     from mozbuild.config_status import config_status
     config_status(**args)
 ''')
 
+    # Running config.status standalone uses byte literals for all the config,
+    # instead of the unicode literals we have in sanitized_config right now.
+    # Some values in sanitized_config also have more complex types, such as
+    # EnumString, which using when calling config_status would currently break
+    # the build, as well as making it inconsistent with re-running
+    # config.status. Fortunately, EnumString derives from unicode, so it's
+    # covered by converting unicode strings.
+    # Moreover, a lot of the build backend code is currently expecting byte
+    # strings and breaks in subtle ways with unicode strings.
+    def encode(v):
+        if isinstance(v, dict):
+            return {
+                encode(k): encode(val)
+                for k, val in v.iteritems()
+            }
+        if isinstance(v, str):
+            return v
+        if isinstance(v, unicode):
+            return v.encode(encoding)
+        if isinstance(v, Iterable):
+            return [encode(i) for i in v]
+        return v
+
     # Other things than us are going to run this file, so we need to give it
     # executable permissions.
     os.chmod('config.status', 0o755)
     if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'):
-        os.environ['WRITE_MOZINFO'] = '1'
-        # Until we have access to the virtualenv from this script, execute
-        # config.status externally, with the virtualenv python.
-        return subprocess.call([config['PYTHON'], 'config.status'])
+        os.environ[b'WRITE_MOZINFO'] = b'1'
+        from mozbuild.config_status import config_status
+        return config_status(args=[], **encode(sanitized_config))
     return 0
 
 
 if __name__ == '__main__':
     sys.exit(main(sys.argv))
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -58,17 +58,17 @@ files by running:
    mach build-backend --backend=VisualStudio
 
 ===============================
 '''.strip()
 
 
 def config_status(topobjdir='.', topsrcdir='.', defines=None,
                   non_global_defines=None, substs=None, source=None,
-                  mozconfig=None):
+                  mozconfig=None, args=sys.argv[1:]):
     '''Main function, providing config.status functionality.
 
     Contrary to config.status, it doesn't use CONFIG_FILES or CONFIG_HEADERS
     variables.
 
     Without the -n option, this program acts as config.status and considers
     the current directory as the top object directory, even when config.status
     is in a different directory. It will, however, treat the directory
@@ -102,17 +102,17 @@ def config_status(topobjdir='.', topsrcd
     parser.add_argument('-d', '--diff', action='store_true',
                         help='print diffs of changed files.')
     parser.add_argument('-b', '--backend', nargs='+', choices=sorted(backends),
                         default=default_backends,
                         help='what backend to build (default: %s).' %
                         ' '.join(default_backends))
     parser.add_argument('--dry-run', action='store_true',
                         help='do everything except writing files out.')
-    options = parser.parse_args()
+    options = parser.parse_args(args)
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
         topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
             non_global_defines=non_global_defines, substs=substs,
             source=source, mozconfig=mozconfig)