Skip to content

Commit

Permalink
[feature] Add possibility to change list handling behaviour #153
Browse files Browse the repository at this point in the history
Closes #153
  • Loading branch information
okraits committed Nov 9, 2023
1 parent 571af14 commit 2a05ab4
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 12 deletions.
27 changes: 22 additions & 5 deletions netjsonconfig/backends/base/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ class BaseBackend(object):
FILE_SECTION_DELIMITER = '# ---------- files ---------- #'
list_identifiers = []

def __init__(self, config=None, native=None, templates=None, context=None):
def __init__(
self,
config=None,
native=None,
templates=None,
templates_list_handling=None,
context=None,
):
"""
:param config: ``dict`` containing a valid **NetJSON** configuration dictionary
:param native: ``str`` or file object representing a native configuration that will
Expand All @@ -44,7 +51,7 @@ def __init__(self, config=None, native=None, templates=None, context=None):
if config is not None:
# perform deepcopy to avoid modifying the original config argument
config = deepcopy(self._load(config))
self.config = self._merge_config(config, templates)
self.config = self._merge_config(config, templates, templates_list_handling)
self.config = self._evaluate_vars(self.config, context)
# backward conversion (native configuration > NetJSON)
elif native is not None:
Expand All @@ -70,7 +77,7 @@ def _load(self, config):
)
return config

def _merge_config(self, config, templates):
def _merge_config(self, config, templates, templates_list_handling):
"""
Merges config with templates
"""
Expand All @@ -82,8 +89,18 @@ def _merge_config(self, config, templates):
# merge templates with main configuration
result = {}
config_list = templates + [config]
for merging in config_list:
result = merge_config(result, self._load(merging), self.list_identifiers)
for i, merging in enumerate(config_list):
if i < len(templates):
result = merge_config(
result,
self._load(merging),
self.list_identifiers,
templates_list_handling[i],
)
else:
result = merge_config(
result, self._load(merging), self.list_identifiers
)
return result

def _evaluate_vars(self, config, context):
Expand Down
10 changes: 8 additions & 2 deletions netjsonconfig/backends/openwrt/openwrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ class OpenWrt(BaseBackend):
list_identifiers = ['name', 'config_value', 'id']

def __init__(
self, config=None, native=None, templates=None, context=None, dsa=True
self,
config=None,
native=None,
templates=None,
templates_list_handling=None,
context=None,
dsa=True,
):
"""
:param config: ``dict`` containing a valid **NetJSON** configuration dictionary
Expand All @@ -52,7 +58,7 @@ def __init__(
``templates`` is not of type ``list``
"""
self.dsa = dsa
super().__init__(config, native, templates, context)
super().__init__(config, native, templates, templates_list_handling, context)

def _generate_contents(self, tar):
"""
Expand Down
23 changes: 18 additions & 5 deletions netjsonconfig/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from copy import deepcopy


def merge_config(template, config, list_identifiers=None):
def merge_config(
template, config, list_identifiers=None, list_handling='append_at_end'
):
"""
Merges ``config`` on top of ``template``.
Expand All @@ -24,15 +26,17 @@ def merge_config(template, config, list_identifiers=None):
for key, value in config.items():
if isinstance(value, dict):
node = result.get(key, OrderedDict())
result[key] = merge_config(node, value)
result[key] = merge_config(node, value, list_handling=list_handling)
elif isinstance(value, list) and isinstance(result.get(key), list):
result[key] = merge_list(result[key], value, list_identifiers)
result[key] = merge_list(
result[key], value, list_identifiers, list_handling
)
else:
result[key] = value
return result


def merge_list(list1, list2, identifiers=None):
def merge_list(list1, list2, identifiers=None, list_handling='append_at_end'):
"""
Merges ``list2`` on top of ``list1``.
Expand All @@ -47,6 +51,8 @@ def merge_list(list1, list2, identifiers=None):
:param identifiers: ``list`` or ``None``
:returns: merged ``list``
"""
if list_handling == 'override':
return list2
identifiers = identifiers or []
dict_map = {'list1': OrderedDict(), 'list2': OrderedDict()}
counter = 1
Expand Down Expand Up @@ -74,7 +80,14 @@ def merge_list(list1, list2, identifiers=None):
key = tuple(key)
container[key] = deepcopy(el)
counter += 1
merged = merge_config(dict_map['list1'], dict_map['list2'])
if list_handling == 'insert_at_beginning':
merged = merge_config(
dict_map['list2'], dict_map['list1'], list_handling=list_handling
)
else:
merged = merge_config(
dict_map['list1'], dict_map['list2'], list_handling=list_handling
)
return list(merged.values())


Expand Down

0 comments on commit 2a05ab4

Please sign in to comment.