diff --git a/dotdrop/cfg_aggregator.py b/dotdrop/cfg_aggregator.py index d7b3437..32d59f4 100644 --- a/dotdrop/cfg_aggregator.py +++ b/dotdrop/cfg_aggregator.py @@ -100,14 +100,17 @@ class CfgAggregator: path = os.path.join(TILD, path) return path - def get_dotfile_by_dst(self, dst): + def get_dotfile_by_dst(self, dst, profile_key=None): """ get a list of dotfiles by dst @dst: dotfile dst (on filesystem) """ dotfiles = [] dst = self._norm_path(dst) - for dotfile in self.dotfiles: + dfs = self.dotfiles + if profile_key: + dfs = self.get_dotfiles(profile_key=profile_key) + for dotfile in dfs: left = self._norm_path(dotfile.dst) if left == dst: dotfiles.append(dotfile) @@ -153,10 +156,14 @@ class CfgAggregator: """return profiles""" return self.profiles - def get_profile(self): + def get_profile(self, key=None): """return profile object""" + pro = self.profile_key + if key: + pro = key + try: - return next(x for x in self.profiles if x.key == self.profile_key) + return next(x for x in self.profiles if x.key == pro) except StopIteration: return None @@ -169,21 +176,27 @@ class CfgAggregator: res.append(profile) return res - def get_dotfiles(self): - """get all dotfiles for this profile""" + def get_dotfiles(self, profile_key=None): + """get all dotfiles for this profile or specified profile key""" dotfiles = [] - profile = self.get_profile() + profile = self.get_profile(key=profile_key) if not profile: return dotfiles return profile.dotfiles - def get_dotfile(self, key): + def get_dotfile(self, key, profile_key=None): """ return dotfile object by key @key: the dotfile key to look for """ + dfs = self.dotfiles + if profile_key: + profile = self.get_profile(key=profile_key) + if not profile: + return None + dfs = profile.dotfiles try: - return next(x for x in self.dotfiles + return next(x for x in dfs if x.key == key) except StopIteration: return None diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 2aecd62..b66f71c 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -77,7 +77,7 @@ def _dotfile_update(opts, path, key=False): update a dotfile pointed by path if key is false or by key (in path) """ - updater = Updater(opts.dotpath, opts.variables, opts.conf, + updater = Updater(opts.dotpath, opts.variables, opts.conf, opts.profile, dry=opts.dry, safe=opts.safe, debug=opts.debug, ignore=opts.update_ignore, showpatch=opts.update_showpatch, diff --git a/dotdrop/importer.py b/dotdrop/importer.py index 4332453..143c035 100644 --- a/dotdrop/importer.py +++ b/dotdrop/importer.py @@ -224,7 +224,7 @@ class Importer: test no other dotfile exists with same dst for this profile but different src """ - dfs = self.conf.get_dotfile_by_dst(dst) + dfs = self.conf.get_dotfile_by_dst(dst, profile_key=self.profile) if not dfs: return False for dotfile in dfs: diff --git a/dotdrop/updater.py b/dotdrop/updater.py index dc033dc..7340e33 100644 --- a/dotdrop/updater.py +++ b/dotdrop/updater.py @@ -25,13 +25,14 @@ class Updater: """dotfiles updater""" def __init__(self, dotpath, variables, conf, - dry=False, safe=True, debug=False, - ignore=None, showpatch=False, + profile_key, dry=False, safe=True, + debug=False, ignore=None, showpatch=False, ignore_missing_in_dotdrop=False): """constructor @dotpath: path where dotfiles are stored @variables: dictionary of variables for the templates @conf: configuration manager + @profile_key: the profile key @dry: simulate @safe: ask for overwrite if True @debug: enable debug @@ -41,6 +42,7 @@ class Updater: self.dotpath = dotpath self.variables = variables self.conf = conf + self.profile_key = profile_key self.dry = dry self.safe = safe self.debug = debug @@ -61,7 +63,8 @@ class Updater: if not os.path.lexists(path): self.log.err('\"{}\" does not exist!'.format(path)) return False - dotfiles = self.conf.get_dotfile_by_dst(path) + dotfiles = self.conf.get_dotfile_by_dst(path, + profile_key=self.profile_key) if not dotfiles: return False for dotfile in dotfiles: @@ -78,8 +81,11 @@ class Updater: def update_key(self, key): """update the dotfile referenced by key""" - dotfile = self.conf.get_dotfile(key) + dotfile = self.conf.get_dotfile(key, profile_key=self.profile_key) if not dotfile: + self.log.dbg('no such dotfile: \"{}\"'.format(key)) + msg = 'invalid dotfile for update: {}' + self.log.err(msg.format(key)) return False self.log.dbg('updating {} from key \"{}\"'.format(dotfile, key)) path = self.conf.path_to_dotfile_dst(dotfile.dst) diff --git a/tests-ng/update-profile-check.sh b/tests-ng/update-profile-check.sh new file mode 100755 index 0000000..e8283b4 --- /dev/null +++ b/tests-ng/update-profile-check.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2021, deadc0de6 +# +# test update dotfile from different profile +# 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}")") + +# 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" +hash coverage 2>/dev/null && bin="coverage run -a --source=dotdrop -m dotdrop.dotdrop" || true + +echo "dotdrop path: ${ddpath}" +echo "pythonpath: ${PYTHONPATH}" + +# get the helpers +source ${cur}/helpers + +echo -e "$(tput setaf 6)==> RUNNING $(basename $BASH_SOURCE) <==$(tput sgr0)" + +################################################################ +# this is the test +################################################################ + +# $1 pattern +# $2 path +grep_or_fail() +{ + grep "${1}" "${2}" >/dev/null 2>&1 || (echo "pattern not found in ${2}" && exit 1) +} + +# dotdrop directory +tmps=`mktemp -d --suffix='-dotdrop-tests-source' || mktemp -d` +dt="${tmps}/dotfiles" +mkdir -p ${dt} + +xori="profile x" +xori="profile y" +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# fs dotfiles +tmpd=`mktemp -d --suffix='-dotdrop-tests-dest' || mktemp -d` +touch ${tmpd}/file + +# create the config file +cfg="${tmps}/config.yaml" +cat > ${cfg} << _EOF +config: + backup: false + create: true + dotpath: dotfiles +dotfiles: + f_file_x: + dst: ${tmpd}/file + src: file_x + f_file_y: + dst: ${tmpd}/file + src: file_y +profiles: + x: + dotfiles: + - f_file_x + y: + dotfiles: + - f_file_y +_EOF +cat ${cfg} + +# reset +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# test with key +echo "test update x from key" +n="patched content for X" +echo "${n}" > ${tmpd}/file +cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=x --key f_file_x +grep_or_fail "${n}" "${dt}/file_x" +grep_or_fail "${yori}" "${dt}/file_y" + +# reset +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# test with key +echo "test update y from key" +n="patched content for Y" +echo "${n}" > ${tmpd}/file +cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=y --key f_file_y +grep_or_fail "${n}" "${dt}/file_y" +grep_or_fail "${xori}" "${dt}/file_x" + +# reset +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# test with path +echo "test update x from path" +n="patched content for X" +echo "${n}" > ${tmpd}/file +cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=x "${tmpd}/file" +grep_or_fail "${n}" "${dt}/file_x" +grep_or_fail "${yori}" "${dt}/file_y" + +# reset +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# test with path +echo "test update y from path" +n="patched content for Y" +echo "${n}" > ${tmpd}/file +cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=y "${tmpd}/file" +grep_or_fail "${n}" "${dt}/file_y" +grep_or_fail "${xori}" "${dt}/file_x" + +## make sure it fails when wrong dotfile +# reset +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# test with key +echo "test wrong key for x" +n="patched content for X" +echo "${n}" > ${tmpd}/file +set +e +cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=x --key f_file_y +set -e +grep_or_fail "${xori}" "${dt}/file_x" +grep_or_fail "${yori}" "${dt}/file_y" + +# reset +echo "${xori}" > ${dt}/file_x +echo "${yori}" > ${dt}/file_y + +# test with key +echo "test wrong key for y" +n="patched content for Y" +echo "${n}" > ${tmpd}/file +set +e +cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=y --key f_file_x +set -e +grep_or_fail "${xori}" "${dt}/file_x" +grep_or_fail "${yori}" "${dt}/file_y" + +# CLEANING +rm -rf ${tmps} ${tmpd} + +echo "OK" +exit 0