Cleanup combine_vars

* Dedupe combine_vars() code (removed from VariableManager)
* Fix merge_hash algorithm to preserve the type
* unittest combine_vars and merge_hash
This commit is contained in:
Toshio Kuratomi 2015-09-01 11:20:16 -07:00
parent 7fe495d619
commit aeff960d02
5 changed files with 158 additions and 92 deletions

View file

@ -20,39 +20,64 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import ast
from collections import MutableMapping
from six import string_types
from six import iteritems, string_types
from ansible import constants as C
from ansible.errors import AnsibleError
from ansible.parsing.splitter import parse_kv
from ansible.utils.unicode import to_unicode
def _validate_mutable_mappings(a, b):
"""
Internal convenience function to ensure arguments are MutableMappings
This checks that all arguments are MutableMappings or raises an error
:raises AnsibleError: if one of the arguments is not a MutableMapping
"""
# If this becomes generally needed, change the signature to operate on
# a variable number of arguments instead.
if not (isinstance(a, MutableMapping) and isinstance(b, MutableMapping)):
raise AnsibleError("failed to combine variables, expected dicts but"
" got a '{0}' and a '{1}'".format(
a.__class__.__name__, b.__class__.__name__))
def combine_vars(a, b):
"""
Return a copy of dictionaries of variables based on configured hash behavior
"""
if C.DEFAULT_HASH_BEHAVIOUR == "merge":
return merge_hash(a, b)
else:
# HASH_BEHAVIOUR == 'replace'
_validate_mutable_mappings(a, b)
result = a.copy()
result.update(b)
return result
def merge_hash(a, b):
''' recursively merges hash b into a
keys from b take precedence over keys from a '''
"""
Recursively merges hash b into a so that keys from b take precedence over keys from a
"""
result = {}
_validate_mutable_mappings(a, b)
result = a.copy()
for dicts in a, b:
# next, iterate over b keys and values
for k, v in dicts.iteritems():
# if there's already such key in a
# and that key contains dict
if k in result and isinstance(result[k], dict):
# merge those dicts recursively
result[k] = merge_hash(a[k], v)
else:
# otherwise, just copy a value from b to a
result[k] = v
# next, iterate over b keys and values
for k, v in iteritems(b):
# if there's already such key in a
# and that key contains a MutableMapping
if k in result and isinstance(result[k], MutableMapping):
# merge those dicts recursively
result[k] = merge_hash(result[k], v)
else:
# otherwise, just copy the value from b to a
result[k] = v
return result