diff --git a/tools/osbuild-mpp b/tools/osbuild-mpp index 966ff8ee..a822f4a4 100755 --- a/tools/osbuild-mpp +++ b/tools/osbuild-mpp @@ -242,6 +242,7 @@ import collections import contextlib import hashlib import json +import yaml import os import pathlib import string @@ -257,6 +258,33 @@ import hawkey from osbuild.util.rhsm import Subscriptions +class YamlOrderedLoader(yaml.Loader): + def construct_mapping(self, node, deep=False): + if not isinstance(node, yaml.MappingNode): + raise ConstructorError(None, None, + "expected a mapping node, but found %s" % node.id, + node.start_mark) + mapping = collections.OrderedDict() + for key_node, value_node in node.value: + key = self.construct_object(key_node, deep=deep) + if not isinstance(key, collections.abc.Hashable): + raise ConstructorError("while constructing a mapping", node.start_mark, + "found unhashable key", key_node.start_mark) + value = self.construct_object(value_node, deep=deep) + mapping[key] = value + return mapping + def construct_yaml_map(self, node): + data = collections.OrderedDict() + yield data + value = self.construct_mapping(node) + data.update(value) +yaml.add_constructor('tag:yaml.org,2002:map', YamlOrderedLoader.construct_yaml_map) + +def yaml_load_ordered(source): + return yaml.load(source, YamlOrderedLoader) + +def json_load_ordered(source): + return json.load(source, object_pairs_hook=collections.OrderedDict) def element_enter(element, key, default): if key not in element: @@ -603,11 +631,22 @@ class ManifestFile: @staticmethod def load_from_fd(f, path, overrides, default_vars): # We use OrderedDict to preserve key order (for python < 3.6) - try: - data = json.load(f, object_pairs_hook=collections.OrderedDict) - except json.decoder.JSONDecodeError as err: - print (f"Invalid json in \"{path}\": {err.msg} at line {err.lineno} (col {err.colno})") - sys.exit(1) + if path.endswith(".yml") or path.endswith(".yaml"): + try: + data = yaml_load_ordered(f) + except yaml.YAMLError as err: + pos = "" + if hasattr(err, 'problem_mark'): + mark = err.problem_mark + pos = f" at line {mark.line+1} (col {mark.column+1})" + print(f"Invalid yaml in \"{path}\": {err.problem}{pos}") + sys.exit(1) + else: + try: + data = json_load_ordered(f) + except json.decoder.JSONDecodeError as err: + print(f"Invalid json in \"{path}\": {err.msg} at line {err.lineno} (col {err.colno})") + sys.exit(1) version = int(data.get("version", "1")) if version == 1: