Xo Wang | 51a53f0 | 2017-03-17 18:15:10 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | """Loads a "target" YAML file and overwrites its values with values from |
| 3 | "override" YAML files. |
| 4 | |
| 5 | Override files are processed in the order given. |
| 6 | |
| 7 | Usage: |
| 8 | merge_settings.py <target yaml> [override yamls] |
| 9 | """ |
| 10 | import sys |
| 11 | import yaml |
| 12 | import copy |
| 13 | |
| 14 | def dict_merge(target, source): |
| 15 | """Deep merge for dicts. |
| 16 | |
| 17 | Works like dict.update() that recursively updates any dict values present in |
| 18 | both parameters. |
| 19 | |
| 20 | Args: |
| 21 | target (dict): Values to be overwritten by corresponding values from |
| 22 | `source`. |
| 23 | source (dict): Overriding values. Not changed by call. |
| 24 | |
| 25 | Returns: |
| 26 | `target` with values overwritten from those in `source` at any and all |
| 27 | levels of nested dicts. |
| 28 | """ |
| 29 | if not isinstance(source, dict): |
| 30 | return source |
| 31 | for k, v in source.iteritems(): |
| 32 | if k in target and isinstance(target[k], dict): |
| 33 | dict_merge(target[k], v) |
| 34 | else: |
| 35 | target[k] = copy.deepcopy(v) |
| 36 | return target |
| 37 | |
| 38 | if len(sys.argv) < 2: |
| 39 | sys.exit('Argument required: target yaml') |
| 40 | |
| 41 | if len(sys.argv) == 2: |
| 42 | # No overrides to handle |
| 43 | sys.exit() |
| 44 | |
| 45 | target_filename = sys.argv[1] |
| 46 | with open(target_filename) as target_file: |
| 47 | data = yaml.safe_load(target_file) |
| 48 | print('Loaded target YAML file ' + target_filename) |
| 49 | |
| 50 | for override_filename in sys.argv[2:]: |
| 51 | with open(override_filename) as override_file: |
| 52 | override = yaml.safe_load(override_file) |
| 53 | dict_merge(data, override) |
| 54 | print('Merged override YAML file ' + override_filename) |
| 55 | |
| 56 | with open(target_filename, 'w') as target_file: |
| 57 | yaml.dump(data, target_file) |
| 58 | print('Wrote merged target YAML file ' + target_filename) |