def test_write_indented_repr_py2(self): data = textwrap.dedent(r""" { 'a': 1, 'b': b'abc', b'c': 'xyz', 'd': False, 'e': { 'a': 1, 'b': b'2', 'c': '3', }, 'f': [ 1, b'2', '3', ], 'pile_of_bytes': b'\xf0\x9f\x92\xa9', 'pile_of_poo': '💩', 'special_chars': '\\\'"\x08\n\t', 'with_accents': 'éà ñ', } """).lstrip() obj = eval(data) buf = io.StringIO() write_indented_repr(buf, obj) self.assertEqual(buf.getvalue(), data)
def config_status(config, execute=True): # Sanitize config data to feed config.status # Ideally, all the backend and frontend code would handle the booleans, but # there are so many things involved, that it's easier to keep config.status # untouched for now. def sanitize_config(v): if v is True: return "1" if v is False: return "" # Serialize types that look like lists and tuples as lists. if not isinstance(v, (bytes, six.text_type, dict)) and isinstance( v, Iterable): return list(v) return v sanitized_config = {} sanitized_config["substs"] = { k: sanitize_config(v) for k, v in six.iteritems(config) if k not in ( "DEFINES", "TOPSRCDIR", "TOPOBJDIR", "CONFIG_STATUS_DEPS", "OLD_CONFIGURE_SUBSTS", "OLD_CONFIGURE_DEFINES", ) } for k, v in config["OLD_CONFIGURE_SUBSTS"]: sanitized_config["substs"][k] = sanitize_config(v) sanitized_config["defines"] = { k: sanitize_config(v) for k, v in six.iteritems(config["DEFINES"]) } for k, v in config["OLD_CONFIGURE_DEFINES"]: sanitized_config["defines"][k] = sanitize_config(v) sanitized_config["topsrcdir"] = config["TOPSRCDIR"] sanitized_config["topobjdir"] = config["TOPOBJDIR"] sanitized_config["mozconfig"] = config.get("MOZCONFIG") if not check_unicode(sanitized_config): print("Configuration should be all unicode.", file=sys.stderr) print("Please file a bug for the above.", file=sys.stderr) sys.exit(1) # 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, for which they are normalized to plain strings via # indented_repr. Likewise for non-dict non-string iterables being # converted to lists. def normalize(obj): if isinstance(obj, dict): return {k: normalize(v) for k, v in six.iteritems(obj)} if isinstance(obj, six.text_type): return six.text_type(obj) if isinstance(obj, Iterable): return [normalize(o) for o in obj] return obj sanitized_config = normalize(sanitized_config) # Create config.status. Eventually, we'll want to just do the work it does # here, when we're able to skip configure tests/use cached results/not rely # on autoconf. with codecs.open("config.status", "w", "utf-8") as fh: fh.write( textwrap.dedent("""\ #!%(python)s # coding=utf-8 from __future__ import unicode_literals """) % {"python": config["PYTHON3"]}) for k, v in sorted(six.iteritems(sanitized_config)): fh.write("%s = " % k) write_indented_repr(fh, v) fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', " "'substs', 'mozconfig']") if execute: fh.write( textwrap.dedent(""" if __name__ == '__main__': from mozbuild.util import patch_main patch_main() from mozbuild.config_status import config_status args = dict([(name, globals()[name]) for name in __all__]) config_status(**args) """)) partial_config = PartialConfigEnvironment(config["TOPOBJDIR"]) partial_config.write_vars(sanitized_config) # Write out a file so the build backend knows to re-run configure when # relevant Python changes. with io.open("config_status_deps.in", "w", encoding="utf-8", newline="\n") as fh: for f in sorted( itertools.chain( config["CONFIG_STATUS_DEPS"], iter_modules_in_path(config["TOPOBJDIR"], config["TOPSRCDIR"]), )): fh.write("%s\n" % mozpath.normpath(f)) # Other things than us are going to run this file, so we need to give it # executable permissions. os.chmod("config.status", 0o755) if execute: from mozbuild.config_status import config_status return config_status(args=[], **sanitized_config) return 0
def config_status(config): # Sanitize config data to feed config.status # Ideally, all the backend and frontend code would handle the booleans, but # there are so many things involved, that it's easier to keep config.status # untouched for now. def sanitized_bools(v): if v is True: return '1' if v is False: return '' return v sanitized_config = {} sanitized_config['substs'] = { k: sanitized_bools(v) for k, v in six.iteritems(config) if k not in ('DEFINES', 'non_global_defines', 'TOPSRCDIR', 'TOPOBJDIR', 'CONFIG_STATUS_DEPS') } sanitized_config['defines'] = { k: sanitized_bools(v) for k, v in six.iteritems(config['DEFINES']) } sanitized_config['non_global_defines'] = config['non_global_defines'] sanitized_config['topsrcdir'] = config['TOPSRCDIR'] sanitized_config['topobjdir'] = config['TOPOBJDIR'] sanitized_config['mozconfig'] = config.get('MOZCONFIG') if not check_unicode(sanitized_config): print("Configuration should be all unicode.", file=sys.stderr) print("Please file a bug for the above.", file=sys.stderr) sys.exit(1) # Create config.status. Eventually, we'll want to just do the work it does # here, when we're able to skip configure tests/use cached results/not rely # on autoconf. logging.getLogger('moz.configure').info('Creating config.status') with codecs.open('config.status', 'w', 'utf-8') as fh: fh.write( textwrap.dedent('''\ #!%(python)s # coding=utf-8 from __future__ import unicode_literals ''') % {'python': config['PYTHON3']}) for k, v in six.iteritems(sanitized_config): fh.write('%s = ' % k) write_indented_repr(fh, v) fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', " "'non_global_defines', 'substs', 'mozconfig']") if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'): fh.write( textwrap.dedent(''' if __name__ == '__main__': from mozbuild.util import patch_main patch_main() from mozbuild.config_status import config_status args = dict([(name, globals()[name]) for name in __all__]) config_status(**args) ''')) partial_config = PartialConfigEnvironment(config['TOPOBJDIR']) partial_config.write_vars(sanitized_config) # Write out a file so the build backend knows to re-run configure when # relevant Python changes. with io.open('config_status_deps.in', 'w', encoding='utf-8', newline='\n') as fh: for f in itertools.chain( config['CONFIG_STATUS_DEPS'], iter_modules_in_path(config['TOPOBJDIR'], config['TOPSRCDIR'])): fh.write('%s\n' % mozpath.normpath(f)) # 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'): from mozbuild.config_status import config_status # 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, for which they are normalized to plain strings via # indented_repr. Likewise for non-dict non-string iterables being # converted to lists. def normalize(obj): if isinstance(obj, dict): return {k: normalize(v) for k, v in six.iteritems(obj)} if isinstance(obj, six.text_type): return six.text_type(obj) if isinstance(obj, Iterable): return [normalize(o) for o in obj] return obj return config_status(args=[], **normalize(sanitized_config)) return 0