From 217fcd6c02b7c7a6591815c26f376c291c0108d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubom=C3=ADr=20Sedl=C3=A1=C5=99?= Date: Tue, 21 May 2019 15:25:35 +0200 Subject: [PATCH] config-dump: Allow dumping config for multi compose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clone the main config, all referenced parts and included variants or comps files. This requires a new argument: destination directory to which to write the copied files. JIRA: COMPOSE-3289 Signed-off-by: Lubomír Sedlář --- bin/pungi-config-dump | 137 +++++++++++++++++++++++++++++++++++------- 1 file changed, 116 insertions(+), 21 deletions(-) diff --git a/bin/pungi-config-dump b/bin/pungi-config-dump index ec9e5659..612ac0dc 100755 --- a/bin/pungi-config-dump +++ b/bin/pungi-config-dump @@ -7,8 +7,11 @@ import argparse import json import os import re +import shutil import sys +from six.moves import configparser + import kobo.conf import pungi.checks import pungi.util @@ -40,6 +43,93 @@ def validate_definition(value): return value +def dump_multi_config(conf_file, dest, **kwargs): + """Given a multi compose config, clone it and all referenced files to a + given directory. + """ + parser = configparser.RawConfigParser() + parser.read(conf_file) + + pungi.util.makedirs(dest) + basedir = os.path.dirname(conf_file) + + def copy_local_files(config): + """Helper function called on all loaded Pungi configs that copies local + variants or comps files (unless specified by absolute path). + """ + for opt in "comps_file", "variants_file": + val = config.get(opt) + if isinstance(val, str) and val[0] != "/": + shutil.copy2(os.path.join(basedir, val), dest) + + for section in parser.sections(): + if section == "general": + continue + file_path = parser.get(section, "config") + dest_file = os.path.splitext(os.path.join(dest, file_path))[0] + ".json" + with open(dest_file, "w") as fh: + if not process_file( + [os.path.join(basedir, file_path)], + out=fh, + callback=copy_local_files, + **kwargs + ): + return False + parser.set(section, "config", os.path.basename(dest_file)) + + with open(os.path.join(dest, os.path.basename(conf_file)), "w") as fh: + parser.write(fh) + + return True + + +def process_file( + sources, + out=sys.stdout, + callback=None, + defines=None, + just_dump=False, + event=None, + offline=False, +): + """Load Pungi config file, validate it, optionally resolve Git references, + and dump created JSON to a given stream. + + :param callable callback: a callable to call with parsed config + :param dict defines: mapping of values to define before parsing the config + :param bool just_dump: skip validation and adding default values + :param int event: Koji event to hardcode into the config + :param bool offline: skip resolving Git references + :returns: False if validation failed, True otherwise + """ + conf = kobo.conf.PyConfigParser() + conf.load_from_dict(defines or {}) + + for source in sources: + load_source(source, conf) + + if not just_dump: + errors, _ = pungi.checks.validate(conf, offline=offline) + if errors: + for error in errors: + print(error, file=sys.stderr) + return False + + if event: + conf["koji_event"] = event + + # Clean up defines from the final final config. We don't want to keep them + # as they would cause warnings during validation. + for key in defines: + del conf[key] + + if callback: + callback(conf) + + json.dump(conf, out, sort_keys=True, indent=4) + return True + + def main(): parser = argparse.ArgumentParser() parser.add_argument( @@ -84,34 +174,39 @@ def main(): group.add_argument( "--offline", action="store_true", help="Do not resolve git references." ) + parser.add_argument( + "--multi", + metavar="DIR", + help=( + "Treat source as config for pungi-orchestrate and store dump into " + "given directory." + ), + ) args = parser.parse_args() defines = dict(var.split("=", 1) for var in args.define) - conf = kobo.conf.PyConfigParser() - conf.load_from_dict(defines) + if args.multi: + if len(args.sources) > 1: + parser.error("Only one multi config can be specified.") - for source in args.sources: - load_source(source, conf) + return dump_multi_config( + args.sources[0], + dest=args.multi, + defines=defines, + just_dump=args.just_dump, + event=args.freeze_event, + offline=args.offline, + ) - if not args.just_dump: - errors, _ = pungi.checks.validate(conf, offline=args.offline) - if errors: - for error in errors: - print(error, file=sys.stderr) - return False - - if args.freeze_event: - conf["koji_event"] = args.freeze_event - - # Clean up defines from the final final config. We don't want to keep them - # as they would cause warnings during validation. - for key in defines: - del conf[key] - - json.dump(conf, sys.stdout, sort_keys=True, indent=4) - return True + return process_file( + args.sources, + defines=defines, + just_dump=args.just_dump, + event=args.freeze_event, + offline=args.offline, + ) if __name__ == "__main__":