From 7a96b1f1842181ffbf64da5a7bfd44019b95c091 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Sun, 10 Mar 2019 15:08:19 +0100 Subject: [PATCH] implement dynamic ext variables path for #99 --- dotdrop/config.py | 29 ++++---- dotdrop/options.py | 8 +-- tests-ng/dynextvariables.sh | 137 ++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 16 deletions(-) create mode 100755 tests-ng/dynextvariables.sh diff --git a/dotdrop/config.py b/dotdrop/config.py index 919cfcb..803f93b 100644 --- a/dotdrop/config.py +++ b/dotdrop/config.py @@ -80,9 +80,10 @@ class Cfg: default_link_by_default = False default_workdir = '~/.config/dotdrop' - def __init__(self, cfgpath, debug=False): + def __init__(self, cfgpath, profile=None, debug=False): """constructor @cfgpath: path to the config file + @profile: chosen profile @debug: enable debug """ if not os.path.exists(cfgpath): @@ -126,7 +127,7 @@ class Cfg: self.ext_variables = {} self.ext_dynvariables = {} - if not self._load_config(): + if not self._load_config(profile=profile): raise ValueError('config is not valid') def eval_dotfiles(self, profile, variables, debug=False): @@ -147,12 +148,12 @@ class Cfg: action.action = t.generate_string(action.action) return dotfiles - def _load_config(self): + def _load_config(self, profile=None): """load the yaml file""" self.content = self._load_yaml(self.cfgpath) if not self._is_valid(): return False - return self._parse() + return self._parse(profile=profile) def _load_yaml(self, path): """load a yaml file to a dict""" @@ -180,7 +181,7 @@ class Cfg: return False return True - def _parse(self): + def _parse(self, profile=None): """parse config file""" # parse the settings self.lnk_settings = self.content[self.key_settings] @@ -189,7 +190,7 @@ class Cfg: # load external variables/dynvariables if self.key_include_vars in self.lnk_settings: paths = self.lnk_settings[self.key_include_vars] - self._load_ext_variables(paths) + self._load_ext_variables(paths, profile=profile) # parse all actions if self.key_actions in self.content: @@ -379,12 +380,15 @@ class Cfg: return True - def _load_ext_variables(self, paths): + def _load_ext_variables(self, paths, profile=None): """load external variables""" variables = {} dvariables = {} + cur_vars = self.get_variables(profile, debug=self.debug) + t = Templategen(variables=cur_vars) for path in paths: path = self._abs_path(path) + path = t.generate_string(path) if self.debug: self.log.dbg('loading variables from {}'.format(path)) content = self._load_yaml(path) @@ -686,7 +690,7 @@ class Cfg: def get_variables(self, profile, debug=False): """return the variables for this profile""" # get flat variables - variables = self._get_variables(profile) + variables = self._get_variables(profile=profile) # get interpreted variables dvariables = self._get_dynvariables(profile) @@ -719,12 +723,13 @@ class Cfg: t.update_variables(variables) return variables - def _get_variables(self, profile): - """return the flat variables""" + def _get_variables(self, profile=None): + """return the un-interpreted variables""" variables = {} # profile variable - variables['profile'] = profile + if profile: + variables['profile'] = profile # global variables if self.key_variables in self.content: @@ -733,7 +738,7 @@ class Cfg: # external variables variables.update(self.ext_variables) - if profile not in self.lnk_profiles: + if not profile or profile not in self.lnk_profiles: return variables # profile variables diff --git a/dotdrop/options.py b/dotdrop/options.py index 7e93aff..8007c1c 100644 --- a/dotdrop/options.py +++ b/dotdrop/options.py @@ -97,11 +97,12 @@ class Options(AttrMonitor): self.args = docopt(USAGE, version=VERSION) self.log = Logger() self.debug = self.args['--verbose'] + self.profile = self.args['--profile'] self.confpath = os.path.expanduser(self.args['--cfg']) if self.debug: self.log.dbg('config file: {}'.format(self.confpath)) - self._read_config() + self._read_config(self.profile) self._apply_args() self._fill_attr() if ENV_NOBANNER not in os.environ \ @@ -117,9 +118,9 @@ class Options(AttrMonitor): self.log.log(BANNER) self.log.log('') - def _read_config(self): + def _read_config(self, profile=None): """read the config file""" - self.conf = Cfg(self.confpath, debug=self.debug) + self.conf = Cfg(self.confpath, profile=profile, debug=self.debug) # transform the configs in attribute for k, v in self.conf.get_settings().items(): setattr(self, k, v) @@ -137,7 +138,6 @@ class Options(AttrMonitor): # adapt attributes based on arguments self.dry = self.args['--dry'] - self.profile = self.args['--profile'] self.safe = not self.args['--force'] self.link = LinkTypes.NOLINK if self.link_by_default: diff --git a/tests-ng/dynextvariables.sh b/tests-ng/dynextvariables.sh new file mode 100755 index 0000000..8eeea5d --- /dev/null +++ b/tests-ng/dynextvariables.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2017, deadc0de6 +# +# test dynamic external variables +# returns 1 in case of error +# + +# exit on first error +set -e + +# all this crap to get current path +rl="readlink -f" +if ! ${rl} "${0}" >/dev/null 2>&1; then + rl="realpath" + + if ! hash ${rl}; then + echo "\"${rl}\" not found !" && exit 1 + fi +fi +cur=$(dirname "$(${rl} "${0}")") + +#hash dotdrop >/dev/null 2>&1 +#[ "$?" != "0" ] && echo "install dotdrop to run tests" && exit 1 + +#echo "called with ${1}" + +# dotdrop path can be pass as argument +ddpath="${cur}/../" +[ "${1}" != "" ] && ddpath="${1}" +[ ! -d ${ddpath} ] && echo "ddpath \"${ddpath}\" is not a directory" && exit 1 + +export PYTHONPATH="${ddpath}:${PYTHONPATH}" +bin="python3 -m dotdrop.dotdrop" + +echo "dotdrop path: ${ddpath}" +echo "pythonpath: ${PYTHONPATH}" + +# get the helpers +source ${cur}/helpers + +echo -e "\e[96m\e[1m==> RUNNING $(basename $BASH_SOURCE) <==\e[0m" + +################################################################ +# this is the test +################################################################ + +# the dotfile source +tmps=`mktemp -d --suffix='-dotdrop-tests'` +mkdir -p ${tmps}/dotfiles +# the dotfile destination +tmpd=`mktemp -d --suffix='-dotdrop-tests'` +#echo "dotfile destination: ${tmpd}" + +# create the config file +extvars="${tmps}/variables.yaml" +extdvars="${tmps}/dynvariables.yaml" +pvars="${tmps}/p1_vars.yaml" +cfg="${tmps}/config.yaml" +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + import_variables: + - "{{@@ var1 @@}}iables.yaml" + - "{{@@ dvar1 @@}}iables.yaml" + - "{{@@ profile @@}}_vars.yaml" +variables: + var1: "var" +dynvariables: + dvar1: "echo dynvar" +dotfiles: + f_abc: + dst: ${tmpd}/abc + src: abc +profiles: + p1: + dotfiles: + - f_abc +_EOF +#cat ${cfg} + +# create the external variables file +cat > ${extvars} << _EOF +variables: + vara: "extvar1" +dynvariables: + dvara: "echo extdvar1" +_EOF +cat > ${extdvars} << _EOF +variables: + varb: "extvar2" +dynvariables: + dvarb: "echo extdvar2" +_EOF +cat > ${pvars} << _EOF +variables: + pvar: "pvar1" +dynvariables: + pdvar: "echo pdvar1" +_EOF + +# create the dotfile +echo "var1: {{@@ var1 @@}}" > ${tmps}/dotfiles/abc +echo "dvar1: {{@@ dvar1 @@}}" >> ${tmps}/dotfiles/abc +# from var file 1 +echo "vara: {{@@ vara @@}}" >> ${tmps}/dotfiles/abc +echo "dvara: {{@@ dvara @@}}" >> ${tmps}/dotfiles/abc +# from var file 2 +echo "varb: {{@@ varb @@}}" >> ${tmps}/dotfiles/abc +echo "dvarb: {{@@ dvarb @@}}" >> ${tmps}/dotfiles/abc +# from var file 3 +echo "pvar: {{@@ pvar @@}}" >> ${tmps}/dotfiles/abc +echo "pdvar: {{@@ pdvar @@}}" >> ${tmps}/dotfiles/abc + +#cat ${tmps}/dotfiles/abc + +# install +cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V + +#cat ${tmpd}/abc + +grep '^var1: var' ${tmpd}/abc >/dev/null +grep '^dvar1: dynvar' ${tmpd}/abc >/dev/null +grep '^vara: extvar1' ${tmpd}/abc >/dev/null +grep '^dvara: extdvar1' ${tmpd}/abc >/dev/null +grep '^varb: extvar2' ${tmpd}/abc >/dev/null +grep '^dvarb: extdvar2' ${tmpd}/abc >/dev/null +grep '^pvar: pvar1' ${tmpd}/abc >/dev/null +grep '^pdvar: pdvar1' ${tmpd}/abc >/dev/null + +## CLEANING +rm -rf ${tmps} ${tmpd} + +echo "OK" +exit 0