1#!/usr/bin/env python3
2"""Copied from phosphor-settings-manager
3Loads a "target" YAML file and overwrites its values with values from
4"override" YAML files.
5
6Override files are processed in the order given.
7
8Usage:
9    merge_settings.py <target yaml> [override yamls]
10"""
11import sys
12import yaml
13import copy
14
15# Custom representer for None types. This is to handle empty dictionaries.
16# By default Pyyaml outputs these as "null", whereas we want an empty character.
17def represent_none(self, _):
18    return self.represent_scalar('tag:yaml.org,2002:null', '')
19
20def dict_merge(target, source):
21    """Deep merge for dicts.
22
23    Works like dict.update() that recursively updates any dict values present in
24    both parameters.
25
26    Args:
27        target (dict): Values to be overwritten by corresponding values from
28            `source`.
29        source (dict): Overriding values. Not changed by call.
30
31    Returns:
32        `target` with values overwritten from those in `source` at any and all
33        levels of nested dicts.
34    """
35    if not isinstance(source, dict):
36        return source
37    for k, v in source.items():
38        if k in target and isinstance(target[k], dict):
39            dict_merge(target[k], v)
40        else:
41            target[k] = copy.deepcopy(v)
42    return target
43
44if len(sys.argv) < 2:
45    sys.exit('Argument required: target yaml')
46
47if len(sys.argv) == 2:
48    # No overrides to handle
49    sys.exit(0)
50
51yaml.add_representer(type(None), represent_none)
52
53target_filename = sys.argv[1]
54with open(target_filename) as target_file:
55    data = yaml.safe_load(target_file)
56    print('Loaded target YAML file ' + target_filename)
57
58for override_filename in sys.argv[2:]:
59    with open(override_filename) as override_file:
60        override = yaml.safe_load(override_file)
61        dict_merge(data, override)
62        print('Merged override YAML file ' + override_filename)
63
64with open(target_filename, 'w') as target_file:
65    yaml.dump(data, target_file, default_flow_style=False)
66    print('Wrote merged target YAML file ' + target_filename)
67