diff options
author | Scott Moser <smoser@ubuntu.com> | 2013-05-10 14:26:32 -0700 |
---|---|---|
committer | Scott Moser <smoser@ubuntu.com> | 2013-05-10 14:26:32 -0700 |
commit | 638cc131857582e3df0c35b8a49433c660fdd299 (patch) | |
tree | fcad890958997eff2e643f3141165e71bdd6eb71 /cloudinit/mergers/m_dict.py | |
parent | 4697c1afcc7d05951f4717a83dad01d2360301c6 (diff) | |
parent | 9f866ff5540558bab56f10e38481e4ad2efa079b (diff) | |
download | vyos-cloud-init-638cc131857582e3df0c35b8a49433c660fdd299.tar.gz vyos-cloud-init-638cc131857582e3df0c35b8a49433c660fdd299.zip |
Fixed merging capabilities.
Instead of previously having merging which was not backwards compatible
with the 0.7.1 and prior methods this patch works to ensure said backwards
compatible while at the same time making the new merging functionality
work in a more customizable manner.
Diffstat (limited to 'cloudinit/mergers/m_dict.py')
-rw-r--r-- | cloudinit/mergers/m_dict.py | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/cloudinit/mergers/m_dict.py b/cloudinit/mergers/m_dict.py index 45a7d3a5..a16141fa 100644 --- a/cloudinit/mergers/m_dict.py +++ b/cloudinit/mergers/m_dict.py @@ -16,33 +16,71 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +DEF_MERGE_TYPE = 'no_replace' +MERGE_TYPES = ('replace', DEF_MERGE_TYPE,) + + +def _has_any(what, *keys): + for k in keys: + if k in what: + return True + return False + class Merger(object): def __init__(self, merger, opts): self._merger = merger - self._overwrite = 'overwrite' in opts - - # This merging algorithm will attempt to merge with - # another dictionary, on encountering any other type of object - # it will not merge with said object, but will instead return - # the original value - # - # On encountering a dictionary, it will create a new dictionary - # composed of the original and the one to merge with, if 'overwrite' - # is enabled then keys that exist in the original will be overwritten - # by keys in the one to merge with (and associated values). Otherwise - # if not in overwrite mode the 2 conflicting keys themselves will - # be merged. - def _on_dict(self, value, merge_with): - if not isinstance(merge_with, (dict)): - return value - merged = dict(value) + # Affects merging behavior... + self._method = DEF_MERGE_TYPE + for m in MERGE_TYPES: + if m in opts: + self._method = m + break + # Affect how recursive merging is done on other primitives. + self._recurse_str = 'recurse_str' in opts + self._recurse_array = _has_any(opts, 'recurse_array', 'recurse_list') + self._allow_delete = 'allow_delete' in opts + # Backwards compat require this to be on. + self._recurse_dict = True + + def __str__(self): + s = ('DictMerger: (method=%s,recurse_str=%s,' + 'recurse_dict=%s,recurse_array=%s,allow_delete=%s)') + s = s % (self._method, self._recurse_str, + self._recurse_dict, self._recurse_array, self._allow_delete) + return s + + def _do_dict_replace(self, value, merge_with, do_replace): + + def merge_same_key(old_v, new_v): + if do_replace: + return new_v + if isinstance(new_v, (list, tuple)) and self._recurse_array: + return self._merger.merge(old_v, new_v) + if isinstance(new_v, (basestring)) and self._recurse_str: + return self._merger.merge(old_v, new_v) + if isinstance(new_v, (dict)) and self._recurse_dict: + return self._merger.merge(old_v, new_v) + # Otherwise leave it be... + return old_v + for (k, v) in merge_with.items(): - if k in merged: - if not self._overwrite: - merged[k] = self._merger.merge(merged[k], v) + if k in value: + if v is None and self._allow_delete: + value.pop(k) else: - merged[k] = v + value[k] = merge_same_key(value[k], v) else: - merged[k] = v + value[k] = v + return value + + def _on_dict(self, value, merge_with): + if not isinstance(merge_with, (dict)): + return value + if self._method == 'replace': + merged = self._do_dict_replace(dict(value), merge_with, True) + elif self._method == 'no_replace': + merged = self._do_dict_replace(dict(value), merge_with, False) + else: + raise NotImplementedError("Unknown merge type %s" % (self._method)) return merged |