Bug 1733610 [wpt PR 31056] - Sync interfaces/ with @webref/idl 2.6.0, a=testonly
[gecko.git] / configure.py
blobe08ac9c96e0d630f987a0dbaba2bdc864ebbed66
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from __future__ import absolute_import, print_function, unicode_literals
7 import codecs
8 import errno
9 import io
10 import itertools
11 import logging
12 import os
13 import sys
14 import textwrap
17 try:
18 from collections.abc import Iterable
19 except ImportError:
20 from collections import Iterable
23 base_dir = os.path.abspath(os.path.dirname(__file__))
24 sys.path.insert(0, os.path.join(base_dir, "python", "mach"))
25 sys.path.insert(0, os.path.join(base_dir, "python", "mozboot"))
26 sys.path.insert(0, os.path.join(base_dir, "python", "mozbuild"))
27 sys.path.insert(0, os.path.join(base_dir, "third_party", "python", "packaging"))
28 sys.path.insert(0, os.path.join(base_dir, "third_party", "python", "pyparsing"))
29 sys.path.insert(0, os.path.join(base_dir, "third_party", "python", "six"))
30 from mozbuild.configure import (
31 ConfigureSandbox,
32 TRACE,
34 from mozbuild.pythonutil import iter_modules_in_path
35 from mozbuild.backend.configenvironment import PartialConfigEnvironment
36 from mozbuild.util import write_indented_repr
37 import mozpack.path as mozpath
38 import six
41 def main(argv):
42 config = {}
44 if "OLD_CONFIGURE" not in os.environ:
45 os.environ["OLD_CONFIGURE"] = os.path.join(base_dir, "old-configure")
47 sandbox = ConfigureSandbox(config, os.environ, argv)
49 clobber_file = "CLOBBER"
50 if not os.path.exists(clobber_file):
51 # Simply touch the file.
52 with open(clobber_file, "a"):
53 pass
55 if os.environ.get("MOZ_CONFIGURE_TRACE"):
56 sandbox._logger.setLevel(TRACE)
58 sandbox.run(os.path.join(os.path.dirname(__file__), "moz.configure"))
60 if sandbox._help:
61 return 0
63 logging.getLogger("moz.configure").info("Creating config.status")
65 old_js_configure_substs = config.pop("OLD_JS_CONFIGURE_SUBSTS", None)
66 old_js_configure_defines = config.pop("OLD_JS_CONFIGURE_DEFINES", None)
67 if old_js_configure_substs or old_js_configure_defines:
68 js_config = config.copy()
69 pwd = os.getcwd()
70 try:
71 try:
72 os.makedirs("js/src")
73 except OSError as e:
74 if e.errno != errno.EEXIST:
75 raise
77 os.chdir("js/src")
78 js_config["OLD_CONFIGURE_SUBSTS"] = old_js_configure_substs
79 js_config["OLD_CONFIGURE_DEFINES"] = old_js_configure_defines
80 # The build system frontend expects $objdir/js/src/config.status
81 # to have $objdir/js/src as topobjdir.
82 # We want forward slashes on all platforms.
83 js_config["TOPOBJDIR"] += "/js/src"
84 config_status(js_config, execute=False)
85 finally:
86 os.chdir(pwd)
88 return config_status(config)
91 def check_unicode(obj):
92 """Recursively check that all strings in the object are unicode strings."""
93 if isinstance(obj, dict):
94 result = True
95 for k, v in six.iteritems(obj):
96 if not check_unicode(k):
97 print("%s key is not unicode." % k, file=sys.stderr)
98 result = False
99 elif not check_unicode(v):
100 print("%s value is not unicode." % k, file=sys.stderr)
101 result = False
102 return result
103 if isinstance(obj, bytes):
104 return False
105 if isinstance(obj, six.text_type):
106 return True
107 if isinstance(obj, Iterable):
108 return all(check_unicode(o) for o in obj)
109 return True
112 def config_status(config, execute=True):
113 # Sanitize config data to feed config.status
114 # Ideally, all the backend and frontend code would handle the booleans, but
115 # there are so many things involved, that it's easier to keep config.status
116 # untouched for now.
117 def sanitize_config(v):
118 if v is True:
119 return "1"
120 if v is False:
121 return ""
122 # Serialize types that look like lists and tuples as lists.
123 if not isinstance(v, (bytes, six.text_type, dict)) and isinstance(v, Iterable):
124 return list(v)
125 return v
127 sanitized_config = {}
128 sanitized_config["substs"] = {
129 k: sanitize_config(v)
130 for k, v in six.iteritems(config)
131 if k
132 not in (
133 "DEFINES",
134 "TOPSRCDIR",
135 "TOPOBJDIR",
136 "CONFIG_STATUS_DEPS",
137 "OLD_CONFIGURE_SUBSTS",
138 "OLD_CONFIGURE_DEFINES",
141 for k, v in config["OLD_CONFIGURE_SUBSTS"]:
142 sanitized_config["substs"][k] = sanitize_config(v)
143 sanitized_config["defines"] = {
144 k: sanitize_config(v) for k, v in six.iteritems(config["DEFINES"])
146 for k, v in config["OLD_CONFIGURE_DEFINES"]:
147 sanitized_config["defines"][k] = sanitize_config(v)
148 sanitized_config["topsrcdir"] = config["TOPSRCDIR"]
149 sanitized_config["topobjdir"] = config["TOPOBJDIR"]
150 sanitized_config["mozconfig"] = config.get("MOZCONFIG")
152 if not check_unicode(sanitized_config):
153 print("Configuration should be all unicode.", file=sys.stderr)
154 print("Please file a bug for the above.", file=sys.stderr)
155 sys.exit(1)
157 # Some values in sanitized_config also have more complex types, such as
158 # EnumString, which using when calling config_status would currently
159 # break the build, as well as making it inconsistent with re-running
160 # config.status, for which they are normalized to plain strings via
161 # indented_repr. Likewise for non-dict non-string iterables being
162 # converted to lists.
163 def normalize(obj):
164 if isinstance(obj, dict):
165 return {k: normalize(v) for k, v in six.iteritems(obj)}
166 if isinstance(obj, six.text_type):
167 return six.text_type(obj)
168 if isinstance(obj, Iterable):
169 return [normalize(o) for o in obj]
170 return obj
172 sanitized_config = normalize(sanitized_config)
174 # Create config.status. Eventually, we'll want to just do the work it does
175 # here, when we're able to skip configure tests/use cached results/not rely
176 # on autoconf.
177 with codecs.open("config.status", "w", "utf-8") as fh:
178 fh.write(
179 textwrap.dedent(
180 """\
181 #!%(python)s
182 # coding=utf-8
183 from __future__ import unicode_literals
186 % {"python": config["PYTHON3"]}
188 for k, v in sorted(six.iteritems(sanitized_config)):
189 fh.write("%s = " % k)
190 write_indented_repr(fh, v)
191 fh.write(
192 "__all__ = ['topobjdir', 'topsrcdir', 'defines', " "'substs', 'mozconfig']"
195 if execute:
196 fh.write(
197 textwrap.dedent(
199 if __name__ == '__main__':
200 from mozbuild.config_status import config_status
201 args = dict([(name, globals()[name]) for name in __all__])
202 config_status(**args)
207 partial_config = PartialConfigEnvironment(config["TOPOBJDIR"])
208 partial_config.write_vars(sanitized_config)
210 # Write out a file so the build backend knows to re-run configure when
211 # relevant Python changes.
212 with io.open("config_status_deps.in", "w", encoding="utf-8", newline="\n") as fh:
213 for f in sorted(
214 itertools.chain(
215 config["CONFIG_STATUS_DEPS"],
216 iter_modules_in_path(config["TOPOBJDIR"], config["TOPSRCDIR"]),
219 fh.write("%s\n" % mozpath.normpath(f))
221 # Other things than us are going to run this file, so we need to give it
222 # executable permissions.
223 os.chmod("config.status", 0o755)
224 if execute:
225 from mozbuild.config_status import config_status
227 return config_status(args=[], **sanitized_config)
228 return 0
231 if __name__ == "__main__":
232 sys.exit(main(sys.argv))