mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-07-20 15:21:10 +02:00
Added icon to mig
This commit is contained in:
parent
6a1a83432f
commit
8ccfb1dfbe
39
filter_plugins/merge_with_defaults.py
Normal file
39
filter_plugins/merge_with_defaults.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
def merge_with_defaults(defaults, customs):
|
||||||
|
"""
|
||||||
|
Recursively merge two dicts (customs into defaults).
|
||||||
|
For each top-level key in customs, ensure all dict keys from defaults are present (at least empty dict).
|
||||||
|
Customs always take precedence.
|
||||||
|
"""
|
||||||
|
def merge_dict(d1, d2):
|
||||||
|
# Recursively merge d2 into d1, d2 wins
|
||||||
|
result = dict(d1) if d1 else {}
|
||||||
|
for k, v in (d2 or {}).items():
|
||||||
|
if k in result and isinstance(result[k], dict) and isinstance(v, dict):
|
||||||
|
result[k] = merge_dict(result[k], v)
|
||||||
|
else:
|
||||||
|
result[k] = v
|
||||||
|
return result
|
||||||
|
|
||||||
|
merged = {}
|
||||||
|
# Union of all app-keys
|
||||||
|
all_keys = set(defaults or {}).union(set(customs or {}))
|
||||||
|
for app_key in all_keys:
|
||||||
|
base = (defaults or {}).get(app_key, {})
|
||||||
|
override = (customs or {}).get(app_key, {})
|
||||||
|
|
||||||
|
# Step 1: merge override into base
|
||||||
|
result = merge_dict(base, override)
|
||||||
|
|
||||||
|
# Step 2: ensure all dict keys from base exist in result (at least {})
|
||||||
|
for k, v in (base or {}).items():
|
||||||
|
if isinstance(v, dict) and k not in result:
|
||||||
|
result[k] = {}
|
||||||
|
merged[app_key] = result
|
||||||
|
return merged
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
'''Custom merge filter for CyMaIS: merge_with_defaults'''
|
||||||
|
def filters(self):
|
||||||
|
return {
|
||||||
|
'merge_with_defaults': merge_with_defaults,
|
||||||
|
}
|
@ -19,7 +19,7 @@ galaxy_info:
|
|||||||
issue_tracker_url: "https://github.com/kevinveenbirkenbach/meta-infinite-graph/issues"
|
issue_tracker_url: "https://github.com/kevinveenbirkenbach/meta-infinite-graph/issues"
|
||||||
documentation: "https://github.com/kevinveenbirkenbach/meta-infinite-graph/"
|
documentation: "https://github.com/kevinveenbirkenbach/meta-infinite-graph/"
|
||||||
logo:
|
logo:
|
||||||
class: ""
|
class: "fa-solid fa-infinity"
|
||||||
run_after: []
|
run_after: []
|
||||||
dependencies:
|
dependencies:
|
||||||
- sys-cli
|
- sys-cli
|
||||||
|
107
tests/unit/filter_plugins/test_merge_with_defaults.py
Normal file
107
tests/unit/filter_plugins/test_merge_with_defaults.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Allow import from project filter_plugins directory
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')))
|
||||||
|
|
||||||
|
from merge_with_defaults import merge_with_defaults
|
||||||
|
|
||||||
|
class TestMergeWithDefaultsFilter(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_basic_merge(self):
|
||||||
|
defaults = {
|
||||||
|
"app1": {
|
||||||
|
"docker": {
|
||||||
|
"network": "default",
|
||||||
|
"services": {"foo": "bar"},
|
||||||
|
"volumes": {"data": "/mnt"}
|
||||||
|
},
|
||||||
|
"features": {"ldap": True, "sso": False},
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customs = {
|
||||||
|
"app1": {
|
||||||
|
"docker": {
|
||||||
|
"network": "customnet"
|
||||||
|
},
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"app2": {
|
||||||
|
"docker": {
|
||||||
|
"network": "other"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"app1": {
|
||||||
|
"docker": {
|
||||||
|
"network": "customnet",
|
||||||
|
"services": {"foo": "bar"},
|
||||||
|
"volumes": {"data": "/mnt"}
|
||||||
|
},
|
||||||
|
"features": {"ldap": True, "sso": False},
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"app2": {
|
||||||
|
"docker": {
|
||||||
|
"network": "other"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = merge_with_defaults(defaults, customs)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_keys_from_defaults_only(self):
|
||||||
|
defaults = {
|
||||||
|
"foo": {"docker": {"a": 1, "b": 2}, "features": {"x": True}},
|
||||||
|
}
|
||||||
|
customs = {
|
||||||
|
"foo": {},
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
"foo": {"docker": {"a": 1, "b": 2}, "features": {"x": True}}
|
||||||
|
}
|
||||||
|
result = merge_with_defaults(defaults, customs)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_custom_overrides_nested_dict(self):
|
||||||
|
defaults = {"x": {"docker": {"bar": 1, "baz": 2}}}
|
||||||
|
customs = {"x": {"docker": {"bar": 99}}}
|
||||||
|
expected = {"x": {"docker": {"bar": 99, "baz": 2}}}
|
||||||
|
result = merge_with_defaults(defaults, customs)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_only_defaults_present(self):
|
||||||
|
defaults = {"only": {"value": 1}}
|
||||||
|
customs = {}
|
||||||
|
expected = {"only": {"value": 1}}
|
||||||
|
result = merge_with_defaults(defaults, customs)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_only_customs_present(self):
|
||||||
|
defaults = {}
|
||||||
|
customs = {"x": {"foo": 42}}
|
||||||
|
expected = {"x": {"foo": 42}}
|
||||||
|
result = merge_with_defaults(defaults, customs)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_deep_merge_multiple_levels(self):
|
||||||
|
defaults = {
|
||||||
|
"a": {"outer": {"mid": {"inner": 1, "keep": True}}, "plain": "test"}
|
||||||
|
}
|
||||||
|
customs = {
|
||||||
|
"a": {"outer": {"mid": {"inner": 99}}, "plain": "changed"}
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
"a": {"outer": {"mid": {"inner": 99, "keep": True}}, "plain": "changed"}
|
||||||
|
}
|
||||||
|
result = merge_with_defaults(defaults, customs)
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user