blob: 928e8bdef22312e78906c8bbf2efdc2b169b41f0 [file] [log] [blame]
Andrew Geissler06fe9692020-03-30 14:31:19 +00001#!/usr/bin/env python3
Dhruvaraj Subhashchandrana03c56d2017-07-12 06:45:14 -05002"""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
Santosh Puranik7106ecf2019-07-11 14:04:39 +053015# 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
Dhruvaraj Subhashchandrana03c56d2017-07-12 06:45:14 -050020def 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
Andrew Geissler06fe9692020-03-30 14:31:19 +000037 for k, v in source.items():
Dhruvaraj Subhashchandrana03c56d2017-07-12 06:45:14 -050038 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
Santosh Puranik7106ecf2019-07-11 14:04:39 +053051yaml.add_representer(type(None), represent_none)
52
Dhruvaraj Subhashchandrana03c56d2017-07-12 06:45:14 -050053target_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)