diff --git a/dotdrop/config.py b/dotdrop/config.py index e57e8d4..9ab5588 100644 --- a/dotdrop/config.py +++ b/dotdrop/config.py @@ -34,12 +34,13 @@ class Cfg: key_imp_link = 'link_on_import' key_dotfile_link = 'link_dotfile_default' key_workdir = 'workdir' + key_cmpignore = 'cmpignore' + key_upignore = 'upignore' # import keys key_import_vars = 'import_variables' key_import_actions = 'import_actions' - key_cmpignore = 'cmpignore' - key_upignore = 'upignore' + key_import_profiles = 'import_profiles' # actions keys key_actions = 'actions' @@ -274,6 +275,18 @@ class Cfg: except KeyError: pass + # parse external profiles + try: + ext_configs = self.lnk_settings[self.key_import_profiles] + for config in ext_configs: + ext_config = Cfg(config) + self.dotfiles.update(ext_config.dotfiles) + self.lnk_profiles.update(ext_config.lnk_profiles) + self.prodots.update(ext_config.prodots) + # need variables, actions and so on + except KeyError: + pass + # parse local actions # If local actions are None, replaces them with empty dict try: @@ -786,9 +799,12 @@ class Cfg: def _dotfile_exists(self, dotfile): """return True and the existing dotfile key if it already exists, False and a new unique key otherwise""" - dsts = [(k, d.dst) for k, d in self.dotfiles.items()] - if dotfile.dst in [x[1] for x in dsts]: - return True, [x[0] for x in dsts if x[1] == dotfile.dst][0] + try: + return True, next(key + for key, d in self.dotfiles.items() + if d.dst == dotfile.dst) + except StopIteration: + pass # return key for this new dotfile path = os.path.expanduser(dotfile.dst) keys = self.dotfiles.keys() diff --git a/tests.sh b/tests.sh index 8aabf14..d59efdb 100755 --- a/tests.sh +++ b/tests.sh @@ -34,6 +34,8 @@ PYTHONPATH=dotdrop ${nosebin} -s --with-coverage --cover-package=dotdrop #PYTHONPATH=dotdrop python3 -m pytest tests ## execute bash script tests -for scr in tests-ng/*.sh; do - ${scr} -done +[ "$1" = '--python-only' ] || { + for scr in tests-ng/*.sh; do + ${scr} + done +} diff --git a/tests/helpers.py b/tests/helpers.py index 091cac3..3309729 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -9,6 +9,7 @@ import shutil import string import random import tempfile +import yaml from dotdrop.options import Options, ENV_NODEBUG from dotdrop.linktypes import LinkTypes @@ -149,8 +150,14 @@ def get_dotfile_from_yaml(dic, path): return [d for d in dotfiles.values() if d['src'] == src][0] +def yaml_dashed_list(items, indent=0): + return ('\n'.join('{}- {}'.format(' ' * indent, item) for item in items) + + '\n') + + def create_fake_config(directory, configname='config.yaml', - dotpath='dotfiles', backup=True, create=True): + dotpath='dotfiles', backup=True, create=True, + import_profiles=()): """Create a fake config file""" path = os.path.join(directory, configname) workdir = os.path.join(directory, 'workdir') @@ -160,7 +167,27 @@ def create_fake_config(directory, configname='config.yaml', f.write(' create: {}\n'.format(str(create))) f.write(' dotpath: {}\n'.format(dotpath)) f.write(' workdir: {}\n'.format(workdir)) + if import_profiles: + f.write(' import_profiles:\n') + f.write(yaml_dashed_list(import_profiles, 4)) f.write('dotfiles:\n') f.write('profiles:\n') f.write('actions:\n') return path + + +def populate_fake_config(config, dotfiles=(), profiles=()): + """Adds some juicy content to config files""" + is_path = isinstance(config, str) + if is_path: + config_path = config + with open(config_path) as config_file: + config = yaml.safe_load(config_file) + + config['dotfiles'] = dotfiles + config['profiles'] = profiles + + if is_path: + with open(config_path, 'w') as config_file: + yaml.safe_dump(config, config_file, default_flow_style=False, + indent=2) diff --git a/tests/test_config.py b/tests/test_config.py index b28e029..86871fb 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -14,7 +14,7 @@ from dotdrop.config import Cfg from dotdrop.options import Options from dotdrop.linktypes import LinkTypes from tests.helpers import get_tempdir, clean, \ - create_fake_config, _fake_args + create_fake_config, _fake_args, populate_fake_config class TestConfig(unittest.TestCase): @@ -24,6 +24,7 @@ class TestConfig(unittest.TestCase): CONFIG_DOTPATH = 'dotfiles' TMPSUFFIX = '.dotdrop' CONFIG_NAME = 'config.yaml' + CONFIG_NAME_2 = 'config-2.yaml' def test_config(self): """Test the config class""" @@ -199,6 +200,79 @@ profiles: conf = Cfg(confpath) self.assertTrue(conf is not None) + def test_include_profiles(self): + tmp = get_tempdir() + self.assertTrue(os.path.exists(tmp)) + self.addCleanup(clean, tmp) + + # create the imported base config file + imported = create_fake_config(tmp, + configname=self.CONFIG_NAME_2, + dotpath=self.CONFIG_DOTPATH, + backup=self.CONFIG_BACKUP, + create=self.CONFIG_CREATE) + # create the importing base config file + importing = create_fake_config(tmp, + configname=self.CONFIG_NAME, + dotpath=self.CONFIG_DOTPATH, + backup=self.CONFIG_BACKUP, + create=self.CONFIG_CREATE, + import_profiles=(imported,)) + + # keys + keys = { + 'dotfile1': 'f_vimrc', + 'dotfile2': 'f_xinitrc', + 'profile1': 'host1', + 'profile2': 'host2', + } + + # edit the imported config + dotfiles_imported = { + keys['dotfile1']: {'dst': '~/.vimrc', 'src': 'vimrc'}, + } + profiles_imported = { + keys['profile1']: {'dotfiles': [keys['dotfile1']]}, + } + populate_fake_config(imported, + dotfiles=dotfiles_imported, + profiles=profiles_imported) + + # edit the importing config + dotfiles_importing = { + keys['dotfile2']: {'dst': '~/.vimrc', 'src': 'vimrc'}, + } + profiles_importing = { + keys['profile2']: { + 'dotfiles': [keys['dotfile2']], + 'include': [keys['profile1']], + } + } + populate_fake_config(importing, + dotfiles=dotfiles_importing, + profiles=profiles_importing) + + # do the tests + importing_cfg = Cfg(importing) + self.assertIsNotNone(importing_cfg) + + # test profile + profiles = importing_cfg.get_profiles() + self.assertIn(keys['profile2'], profiles) + + # test dotfiles + importing_cfg_dotfiles = [ + (dotfile.key, {'src': dotfile.src, 'dst': dotfile.dst}) + for dotfile in importing_cfg.prodots[keys['profile2']] + ] + + self.assertIn( + (keys['dotfile2'], dotfiles_importing[keys['dotfile2']]), + importing_cfg_dotfiles) + self.assertIn( + (keys['dotfile1'], dotfiles_imported[keys['dotfile1']]), + importing_cfg_dotfiles) + def main(): unittest.main()