1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-12 18:45:13 +00:00

Refactoring Cfg merge

This commit is contained in:
Davide Laezza
2019-04-22 21:52:20 +02:00
parent 3c9f0040a3
commit 2d66e1847e
3 changed files with 85 additions and 72 deletions

View File

@@ -5,7 +5,6 @@ Copyright (c) 2017, deadc0de6
yaml config file manager yaml config file manager
""" """
import inspect
import itertools import itertools
import os import os
import shlex import shlex
@@ -19,7 +18,7 @@ from dotdrop.dotfile import Dotfile
from dotdrop.templategen import Templategen from dotdrop.templategen import Templategen
from dotdrop.logger import Logger from dotdrop.logger import Logger
from dotdrop.action import Action, Transform from dotdrop.action import Action, Transform
from dotdrop.utils import is_dict, is_not_magic, strip_home, shell from dotdrop.utils import strip_home, shell
from dotdrop.linktypes import LinkTypes from dotdrop.linktypes import LinkTypes
@@ -269,7 +268,8 @@ class Cfg:
# parse external actions # parse external actions
try: try:
for path in self.lnk_settings[self.key_import_actions]: ext_actions = self.lnk_settings[self.key_import_actions] or ()
for path in ext_actions:
path = self._abs_path(path) path = self._abs_path(path)
if self.debug: if self.debug:
self.log.dbg('loading actions from {}'.format(path)) self.log.dbg('loading actions from {}'.format(path))
@@ -491,6 +491,27 @@ class Cfg:
self.log.dbg('dotfiles for \"{}\": {}'.format(k, df)) self.log.dbg('dotfiles for \"{}\": {}'.format(k, df))
return True return True
def _merge_dict(self, ext_config, warning_prefix, self_member,
ext_member=None):
if ext_member is None:
member_name = self_member
self_member = getattr(self, member_name)
ext_member = getattr(ext_config, member_name)
common_keys = (set(self_member.keys())
.intersection(set(ext_member.keys())))
warning_msg = ('%s {} defined both in %s and %s: {} in %s used'
% (warning_prefix, self.cfgpath, ext_config.cfgpath,
self.cfgpath))
for key in common_keys:
self.log.warn(warning_msg.format(key, key))
merged = ext_member.copy()
merged.update(self_member)
self_member.update(merged)
return self_member
def _merge_cfg(self, config_path): def _merge_cfg(self, config_path):
# Parsing external config file # Parsing external config file
try: try:
@@ -499,35 +520,22 @@ class Cfg:
raise ValueError( raise ValueError(
'external config file not found: {}'.format(config_path)) 'external config file not found: {}'.format(config_path))
# Merging lists in config settings # Merging in members from the external config file
list_settings = ( self._merge_dict(ext_config, 'Dotfile', 'dotfiles')
(k, v) self._merge_dict(ext_config, 'Profile', 'lnk_profiles')
for k, v in ext_config.lnk_settings.items() self._merge_dict(ext_config, 'Action', 'actions')
if isinstance(v, list) self._merge_dict(ext_config, 'Transformation', 'trans_r')
) self._merge_dict(ext_config, 'Write transformation', 'trans_w')
for k, v in list_settings: self._merge_dict(ext_config, 'Profile', 'prodots')
self.lnk_settings[k] += v
# Merging dictionaries # variables need to be merged differently
ext_members = ( merged_variables = self._merge_dict(ext_config, 'Variable',
(name, member) self.get_variables(None),
for name, member in inspect.getmembers(ext_config, is_dict) ext_config.get_variables(None))
if name != 'content' and is_not_magic(name) self.content.setdefault(self.key_variables, {})
) self.content[self.key_variables] = self.content[self.key_variables] \
for name, ext_member in ext_members: or {}
self_member = getattr(self, name, {}) self.content[self.key_variables].update(merged_variables)
ext_member.update(self_member)
setattr(self, name, ext_member)
# Merging variables
self_content, ext_content = self.content, ext_config.content
(ext_content[self.key_variables]
.update(self_content[self.key_variables]))
self.content[self.key_variables] = ext_content[self.key_variables]
(ext_content[self.key_dynvariables]
.update(self_content[self.key_dynvariables]))
self.content[self.key_dynvariables] = \
ext_content[self.key_dynvariables]
def _load_ext_variables(self, paths, profile=None): def _load_ext_variables(self, paths, profile=None):
"""load external variables""" """load external variables"""

View File

@@ -130,13 +130,3 @@ def must_ignore(paths, ignores, debug=False):
LOG.dbg('ignore \"{}\" match: {}'.format(i, p)) LOG.dbg('ignore \"{}\" match: {}'.format(i, p))
return True return True
return False return False
def is_dict(obj):
"""Return true if obj is dict."""
return isinstance(obj, dict)
def is_not_magic(name):
"""Return true if name is not a magic method name."""
return (name[0:2], name[-2:]) != ('__', '__')

View File

@@ -226,10 +226,32 @@ profiles:
vars_ed_file = create_yaml_keyval(vars_ed, tmp) vars_ed_file = create_yaml_keyval(vars_ed, tmp)
vars_ing_file = create_yaml_keyval(vars_ing, tmp) vars_ing_file = create_yaml_keyval(vars_ing, tmp)
actions_ed = {
'pre': {
'a_pre_action_ed': 'echo pre 22',
},
'post': {
'a_post_action_ed': 'echo post 22',
},
'a_action_ed': 'echo 22',
}
actions_ing = {
'pre': {
'a_pre_action_ing': 'echo pre aa',
},
'post': {
'a_post_action_ing': 'echo post aa',
},
'a_action_ing': 'echo aa',
}
actions_ed_file = create_yaml_keyval(actions_ed, tmp)
actions_ing_file = create_yaml_keyval(actions_ing, tmp)
imported = { imported = {
'config': { 'config': {
'dotpath': 'importing', 'dotpath': 'importing',
'import_variables': [vars_ed_file], 'import_variables': [vars_ed_file],
'import_actions': [actions_ed_file],
}, },
'dotfiles': { 'dotfiles': {
'f_vimrc': {'dst': '~/.vimrc', 'src': 'vimrc'}, 'f_vimrc': {'dst': '~/.vimrc', 'src': 'vimrc'},
@@ -265,6 +287,7 @@ profiles:
'config': { 'config': {
'dotpath': 'importing', 'dotpath': 'importing',
'import_variables': [vars_ing_file], 'import_variables': [vars_ing_file],
'import_actions': [actions_ing_file],
}, },
'dotfiles': { 'dotfiles': {
'f_xinitrc': {'dst': '~/.xinitrc', 'src': 'xinitrc'}, 'f_xinitrc': {'dst': '~/.xinitrc', 'src': 'xinitrc'},
@@ -328,10 +351,6 @@ profiles:
self.assertIsNotNone(importing_cfg) self.assertIsNotNone(importing_cfg)
self.assertIsNotNone(imported_cfg) self.assertIsNotNone(imported_cfg)
# test settings
self.assertIsSubset(imported_cfg.lnk_settings,
importing_cfg.lnk_settings)
# test profiles # test profiles
self.assertIsSubset(imported_cfg.lnk_profiles, self.assertIsSubset(imported_cfg.lnk_profiles,
importing_cfg.lnk_profiles) importing_cfg.lnk_profiles)
@@ -365,14 +384,6 @@ profiles:
# test prodots # test prodots
self.assertIsSubset(imported_cfg.prodots, importing_cfg.prodots) self.assertIsSubset(imported_cfg.prodots, importing_cfg.prodots)
# test ext_variables (reduntant, but still)
self.assertIsSubset(imported_cfg.ext_variables,
importing_cfg.ext_variables)
# test ext_dynvariables (reduntant, but still)
self.assertIsSubset(imported_cfg.ext_dynvariables,
importing_cfg.ext_dynvariables)
def test_import_configs_override(self): def test_import_configs_override(self):
"""Test import_configs when some config keys overlap.""" """Test import_configs when some config keys overlap."""
tmp = get_tempdir() tmp = get_tempdir()
@@ -398,11 +409,33 @@ profiles:
vars_ed_file = create_yaml_keyval(vars_ed, tmp) vars_ed_file = create_yaml_keyval(vars_ed, tmp)
vars_ing_file = create_yaml_keyval(vars_ing, tmp) vars_ing_file = create_yaml_keyval(vars_ing, tmp)
actions_ed = {
'pre': {
'a_pre_action': 'echo pre 22',
},
'post': {
'a_post_action': 'echo post 22',
},
'a_action': 'echo 22',
}
actions_ing = {
'pre': {
'a_pre_action': 'echo pre aa',
},
'post': {
'a_post_action': 'echo post aa',
},
'a_action': 'echo aa',
}
actions_ed_file = create_yaml_keyval(actions_ed, tmp)
actions_ing_file = create_yaml_keyval(actions_ing, tmp)
imported = { imported = {
'config': { 'config': {
'dotpath': 'imported', 'dotpath': 'imported',
'backup': False, 'backup': False,
'import_variables': [vars_ed_file], 'import_variables': [vars_ed_file],
'import_actions': [actions_ed_file],
}, },
'dotfiles': { 'dotfiles': {
'f_vimrc': {'dst': '~/.vimrc', 'src': 'vimrc'}, 'f_vimrc': {'dst': '~/.vimrc', 'src': 'vimrc'},
@@ -444,6 +477,7 @@ profiles:
'dotpath': 'importing', 'dotpath': 'importing',
'backup': True, 'backup': True,
'import_variables': [vars_ing_file], 'import_variables': [vars_ing_file],
'import_actions': [actions_ing_file],
}, },
'dotfiles': { 'dotfiles': {
'f_xinitrc': {'dst': '~/.xinitrc', 'src': 'xinitrc'}, 'f_xinitrc': {'dst': '~/.xinitrc', 'src': 'xinitrc'},
@@ -507,12 +541,6 @@ profiles:
self.assertIsNotNone(importing_cfg) self.assertIsNotNone(importing_cfg)
self.assertIsNotNone(imported_cfg) self.assertIsNotNone(imported_cfg)
# test settings
self.assertTrue(importing_cfg.lnk_settings['dotpath']
.endswith(importing['config']['dotpath']))
self.assertEqual(importing_cfg.lnk_settings['backup'],
importing['config']['backup'])
# test profiles # test profiles
self.assertIsSubset(imported_cfg.lnk_profiles, self.assertIsSubset(imported_cfg.lnk_profiles,
importing_cfg.lnk_profiles) importing_cfg.lnk_profiles)
@@ -561,19 +589,6 @@ profiles:
self.assertTrue(set(imported_cfg.prodots['host1']) self.assertTrue(set(imported_cfg.prodots['host1'])
< set(importing_cfg.prodots['host2'])) < set(importing_cfg.prodots['host2']))
# test ext_variables (reduntant, but still)
self.assertFalse(any(
imported_cfg.ext_variables[key] == importing_cfg.ext_variables[key]
for key in imported_cfg.ext_variables
))
# test ext_dynvariables (reduntant, but still)
self.assertFalse(any(
(imported_cfg.ext_dynvariables[key]
== importing_cfg.ext_dynvariables[key])
for key in imported_cfg.ext_dynvariables
))
def main(): def main():
unittest.main() unittest.main()