Changeset View
Changeset View
Standalone View
Standalone View
swh/core/config.py
# Copyright (C) 2015 The Software Heritage developers | # Copyright (C) 2015 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU General Public License version 3, or any later version | # License: GNU General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
import configparser | import configparser | ||||
import logging | import logging | ||||
import os | import os | ||||
import yaml | import yaml | ||||
from itertools import chain | |||||
from copy import deepcopy | |||||
logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||
SWH_CONFIG_DIRECTORIES = [ | SWH_CONFIG_DIRECTORIES = [ | ||||
'~/.config/swh', | '~/.config/swh', | ||||
'~/.swh', | '~/.swh', | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | def merge_default_configs(base_config, *other_configs): | ||||
full_config = base_config.copy() | full_config = base_config.copy() | ||||
for config in other_configs: | for config in other_configs: | ||||
full_config.update(config) | full_config.update(config) | ||||
return full_config | return full_config | ||||
def merge_configs(base, other): | |||||
"""Merge two config dictionaries | |||||
This does merge config dicts recursively, with the rules, for every value | |||||
of the dicts (with 'val' not being a dict): | |||||
- None + type -> type | |||||
- type + None -> None | |||||
- dict + dict -> dict (merged) | |||||
- val + dict -> TypeError | |||||
- dict + val -> TypeError | |||||
- val + val -> val (other) | |||||
so merging | |||||
{ | |||||
'key1': { | |||||
'skey1': value1, | |||||
'skey2': {'sskey1': value2}, | |||||
}, | |||||
'key2': value3, | |||||
} | |||||
with | |||||
{ | |||||
'key1': { | |||||
'skey1': value4, | |||||
'skey2': {'sskey2': value5}, | |||||
}, | |||||
'key3': value6, | |||||
} | |||||
will give: | |||||
{ | |||||
'key1': { | |||||
'skey1': value4, # <-- note this | |||||
'skey2': { | |||||
'sskey1': value2, | |||||
'sskey2': value5, | |||||
}, | |||||
}, | |||||
ardumont: shouldn't it be ...
```
...
'key2': value3,
'key3': value6,
}
```
I suppose there is… | |||||
Done Inline Actionsindeed, good catch douardda: indeed, good catch | |||||
Not Done Inline ActionsThis could be a doctest vlorentz: This could be a doctest | |||||
'key2': value3, | |||||
'key3': value6, | |||||
} | |||||
Note that no type checking is done for anything but dicts. | |||||
""" | |||||
if not isinstance(base, dict) or not isinstance(other, dict): | |||||
raise TypeError( | |||||
'Cannot merge a %s with a %s' % (type(base), type(other))) | |||||
output = {} | |||||
allkeys = set(chain(base.keys(), other.keys())) | |||||
for k in allkeys: | |||||
vb = base.get(k) | |||||
vo = other.get(k) | |||||
if isinstance(vo, dict): | |||||
output[k] = merge_configs(vb is not None and vb or {}, vo) | |||||
elif isinstance(vb, dict) and k in other and other[k] is not None: | |||||
output[k] = merge_configs(vb, vo is not None and vo or {}) | |||||
elif k in other: | |||||
output[k] = deepcopy(vo) | |||||
else: | |||||
output[k] = deepcopy(vb) | |||||
return output | |||||
def swh_config_paths(base_filename): | def swh_config_paths(base_filename): | ||||
"""Return the Software Heritage specific configuration paths for the given | """Return the Software Heritage specific configuration paths for the given | ||||
filename.""" | filename.""" | ||||
return [os.path.join(dirname, base_filename) | return [os.path.join(dirname, base_filename) | ||||
for dirname in SWH_CONFIG_DIRECTORIES] | for dirname in SWH_CONFIG_DIRECTORIES] | ||||
▲ Show 20 Lines • Show All 96 Lines • Show Last 20 Lines |
shouldn't it be ...
I suppose there is an issue with the input instead and the key3 of the second dict should have been key2 instead?