Mini Shell
"""
Utilities for comparing and updating configurations while keeping track of
changes in a way that can be easily reported in a state.
"""
def compare_and_update_config(config, update_config, changes, namespace=""):
"""
Recursively compare two configs, writing any needed changes to the
update_config and capturing changes in the changes dict.
"""
if isinstance(config, dict):
if not update_config:
if config:
# the updated config is more valid--report that we are using it
changes[namespace] = {
"new": config,
"old": update_config,
}
return config
elif not isinstance(update_config, dict):
# new config is a dict, other isn't--new one wins
changes[namespace] = {
"new": config,
"old": update_config,
}
return config
else:
# compare each key in the base config with the values in the
# update_config, overwriting the values that are different but
# keeping any that are not defined in config
for key, value in config.items():
_namespace = key
if namespace:
_namespace = f"{namespace}.{_namespace}"
update_config[key] = compare_and_update_config(
value,
update_config.get(key, None),
changes,
namespace=_namespace,
)
return update_config
elif isinstance(config, list):
if not update_config:
if config:
# the updated config is more valid--report that we are using it
changes[namespace] = {
"new": config,
"old": update_config,
}
return config
elif not isinstance(update_config, list):
# new config is a list, other isn't--new one wins
changes[namespace] = {
"new": config,
"old": update_config,
}
return config
else:
# iterate through config list, ensuring that each index in the
# update_config list is the same
for idx, item in enumerate(config):
_namespace = f"[{idx}]"
if namespace:
_namespace = f"{namespace}{_namespace}"
_update = None
if len(update_config) > idx:
_update = update_config[idx]
if _update:
update_config[idx] = compare_and_update_config(
config[idx],
_update,
changes,
namespace=_namespace,
)
else:
changes[_namespace] = {
"new": config[idx],
"old": _update,
}
update_config.append(config[idx])
if len(update_config) > len(config):
# trim any items in update_config that are not in config
for idx, old_item in enumerate(update_config):
if idx < len(config):
continue
_namespace = f"[{idx}]"
if namespace:
_namespace = f"{namespace}{_namespace}"
changes[_namespace] = {
"new": None,
"old": old_item,
}
del update_config[len(config) :]
return update_config
else:
if config != update_config:
changes[namespace] = {
"new": config,
"old": update_config,
}
return config
Zerion Mini Shell 1.0