diff --git a/dotdrop/config.py b/dotdrop/config.py index ccf1ddd..ada5446 100644 --- a/dotdrop/config.py +++ b/dotdrop/config.py @@ -17,9 +17,6 @@ from dotdrop.action import Action, Transform from dotdrop.utils import * -TILD = '~' - - class Cfg: key_all = 'ALL' @@ -314,7 +311,12 @@ class Cfg: # make sure we have an absolute dotpath self.curdotpath = self.lnk_settings[self.key_dotpath] - self.lnk_settings[self.key_dotpath] = self.abs_dotpath(self.curdotpath) + self.lnk_settings[self.key_dotpath] = self.abs_or_rel(self.curdotpath) + + # make sure we have an absolute workdir + self.curworkdir = self.lnk_settings[self.key_workdir] + self.lnk_settings[self.key_workdir] = self.abs_or_rel(self.curworkdir) + return True def _get_included_dotfiles(self, profile): @@ -401,8 +403,9 @@ class Cfg: if self.key_ignoreempty not in self.lnk_settings: self.lnk_settings[self.key_ignoreempty] = self.default_ignoreempty - def abs_dotpath(self, path): - """transform path to an absolute path based on config path""" + def abs_or_rel(self, path): + """path is either absolute or relative to the config path""" + path = os.path.expanduser(path) if not os.path.isabs(path): absconf = os.path.join(os.path.dirname( self.cfgpath), path) @@ -424,7 +427,7 @@ class Cfg: return elem.lower() def _get_paths(self, path): - p = self._strip_home(path) + p = strip_home(path) dirs = [] while True: p, f = os.path.split(p) @@ -466,14 +469,6 @@ class Cfg: break return key - def _strip_home(self, path): - """strip home part if any""" - path = os.path.expanduser(path) - home = os.path.expanduser(TILD) - if path.startswith(home): - path = path.lstrip(home) - return path - def short_to_long(self): """transform all short keys to long keys""" if not self.content[self.key_dotfiles]: @@ -600,22 +595,28 @@ class Cfg: def dump(self): """return a dump of the config""" - # temporary reset dotpath + # temporary reset paths dotpath = self.lnk_settings[self.key_dotpath] + workdir = self.lnk_settings[self.key_workdir] self.lnk_settings[self.key_dotpath] = self.curdotpath + self.lnk_settings[self.key_workdir] = self.curworkdir # dump ret = yaml.dump(self.content, default_flow_style=False, indent=2) - # restore dotpath + # restore paths self.lnk_settings[self.key_dotpath] = dotpath + self.lnk_settings[self.key_workdir] = workdir return ret def save(self): """save the config to file""" - # temporary reset dotpath + # temporary reset paths dotpath = self.lnk_settings[self.key_dotpath] + workdir = self.lnk_settings[self.key_workdir] self.lnk_settings[self.key_dotpath] = self.curdotpath + self.lnk_settings[self.key_workdir] = self.curworkdir # save ret = self._save(self.content, self.cfgpath) - # restore dotpath + # restore path self.lnk_settings[self.key_dotpath] = dotpath + self.lnk_settings[self.key_workdir] = workdir return ret diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 13b1cac..6d75143 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -22,14 +22,12 @@ from dotdrop.dotfile import Dotfile from dotdrop.config import Cfg from dotdrop.utils import * -CUR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) LOG = Logger() ENV_PROFILE = 'DOTDROP_PROFILE' ENV_NOBANNER = 'DOTDROP_NOBANNER' PROFILE = socket.gethostname() if ENV_PROFILE in os.environ: PROFILE = os.environ[ENV_PROFILE] -TILD = '~' TRANS_SUFFIX = 'trans' BANNER = """ _ _ _ @@ -235,7 +233,6 @@ def cmd_update(opts, conf, paths, iskey=False): def cmd_importer(opts, conf, paths): """import dotfile(s) from paths""" ret = True - home = os.path.expanduser(TILD) cnt = 0 for path in paths: if not os.path.lexists(path): @@ -244,9 +241,7 @@ def cmd_importer(opts, conf, paths): continue dst = path.rstrip(os.sep) dst = os.path.abspath(dst) - src = dst - if dst.startswith(home): - src = dst[len(home):] + src = strip_home(dst) strip = '.' + os.sep if opts['keepdot']: strip = os.sep @@ -257,7 +252,7 @@ def cmd_importer(opts, conf, paths): linkit = opts['link'] or opts['link_by_default'] # prepare hierarchy for dotfile - srcf = os.path.join(CUR, opts['dotpath'], src) + srcf = os.path.join(opts['dotpath'], src) if not os.path.exists(srcf): cmd = ['mkdir', '-p', '{}'.format(os.path.dirname(srcf))] if opts['dry']: @@ -294,7 +289,7 @@ def cmd_importer(opts, conf, paths): else: conf.save() LOG.log('\n{} file(s) imported.'.format(cnt)) - return True + return ret def cmd_list_profiles(conf): diff --git a/dotdrop/installer.py b/dotdrop/installer.py index bb28ebd..5292bae 100644 --- a/dotdrop/installer.py +++ b/dotdrop/installer.py @@ -253,8 +253,7 @@ class Installer: def _pivot_path(self, path, newdir, striphome=False): """change path to be under newdir""" if striphome: - home = os.path.expanduser('~') - path = path.lstrip(home) + utils.strip_home(path) sub = path.lstrip(os.sep) return os.path.join(newdir, sub) diff --git a/dotdrop/updater.py b/dotdrop/updater.py index e648a6c..8a3e1a1 100644 --- a/dotdrop/updater.py +++ b/dotdrop/updater.py @@ -14,6 +14,7 @@ from dotdrop.logger import Logger from dotdrop.templategen import Templategen import dotdrop.utils as utils + TILD = '~' @@ -21,7 +22,6 @@ class Updater: def __init__(self, conf, dotpath, dry, safe, iskey=False, debug=False): - self.home = os.path.expanduser(TILD) self.conf = conf self.dotpath = dotpath self.dry = dry @@ -59,7 +59,7 @@ class Updater: ret = False new_path = None left = os.path.expanduser(path) - right = os.path.join(self.conf.abs_dotpath(self.dotpath), dotfile.src) + right = os.path.join(self.conf.abs_or_rel(self.dotpath), dotfile.src) right = os.path.expanduser(right) if dotfile.trans_w: # apply write transformation if any @@ -95,10 +95,11 @@ class Updater: path = os.path.expanduser(path) path = os.path.expandvars(path) path = os.path.abspath(path) + home = os.path.expanduser(TILD) + os.sep # normalize the path - if path.startswith(self.home): - path = path.lstrip(self.home) + if path.startswith(home): + path = path[len(home):] path = os.path.join(TILD, path) return path diff --git a/dotdrop/utils.py b/dotdrop/utils.py index b949a75..b88780b 100644 --- a/dotdrop/utils.py +++ b/dotdrop/utils.py @@ -101,3 +101,11 @@ def content_empty(string): if string == b'\n': return True return False + + +def strip_home(path): + """properly strip $HOME from path""" + home = os.path.expanduser('~') + os.sep + if path.startswith(home): + path = path[len(home):] + return path diff --git a/tests-ng/workdir.sh b/tests-ng/workdir.sh new file mode 100755 index 0000000..cb57f93 --- /dev/null +++ b/tests-ng/workdir.sh @@ -0,0 +1,160 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2017, deadc0de6 +# +# test workdir relative or absolute +# 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 +################################################################ +string="blabla" + +# the dotfile source +tmp=`mktemp -d` + +tmpf="${tmp}/dotfiles" +tmpw="${tmp}/workdir" + +mkdir -p ${tmpf} +echo "dotfiles source (dotpath): ${tmpf}" +mkdir -p ${tmpw} +echo "workdir: ${tmpw}" + +# create the config file +cfg="${tmp}/config.yaml" +echo "config file: ${cfg}" + +# the dotfile destination +tmpd=`mktemp -d` +echo "dotfiles destination: ${tmpd}" + +## RELATIVE +echo "RUNNING RELATIVE" +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + workdir: `echo ${tmpw} | sed 's/^.*\///g'` +dotfiles: + f_abc: + dst: ${tmpd}/abc + src: abc + link: true +profiles: + p1: + dotfiles: + - f_abc +_EOF +cat ${cfg} + +# create the dotfile +echo "{{@@ profile @@}}" > ${tmpf}/abc +echo "${string}" >> ${tmpf}/abc + +# install +cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -b -V + +# checks +grep -r p1 ${tmpw} >/dev/null +grep -r ${string} ${tmpw} >/dev/null +[ ! -e ${tmpd}/abc ] && echo "[ERROR] dotfile not installed" && exit 1 +[ ! -h ${tmpd}/abc ] && echo "[ERROR] dotfile is not a symlink" && exit 1 + +## CLEANING +rm -rf ${tmp} ${tmpd} + +## ABSOLUTE +echo "RUNNING ABSOLUTE" +# the dotfile source +tmp=`mktemp -d` + +tmpf="${tmp}/dotfiles" +tmpw="${tmp}/workdir" + +mkdir -p ${tmpf} +echo "dotfiles source (dotpath): ${tmpf}" +mkdir -p ${tmpw} +echo "workdir: ${tmpw}" + +# create the config file +cfg="${tmp}/config.yaml" +echo "config file: ${cfg}" + +# the dotfile destination +tmpd=`mktemp -d` +echo "dotfiles destination: ${tmpd}" + +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + workdir: ${tmpw} +dotfiles: + f_abc: + dst: ${tmpd}/abc + src: abc + link: true +profiles: + p1: + dotfiles: + - f_abc +_EOF +cat ${cfg} + +# create the dotfile +echo "{{@@ profile @@}}" > ${tmpf}/abc +echo "${string}" >> ${tmpf}/abc + +# install +cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -b -V + +# checks +grep -r p1 ${tmpw} >/dev/null +grep -r ${string} ${tmpw} >/dev/null +[ ! -e ${tmpd}/abc ] && echo "[ERROR] dotfile not installed" && exit 1 +[ ! -h ${tmpd}/abc ] && echo "[ERROR] dotfile is not a symlink" && exit 1 + +## CLEANING +rm -rf ${tmp} ${tmpd} + +echo "OK" +exit 0 diff --git a/tests/helpers.py b/tests/helpers.py index f1783f6..472069b 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -11,6 +11,7 @@ import random import tempfile from dotdrop.config import Cfg +from dotdrop.utils import * TMPSUFFIX = '.dotdrop' @@ -96,11 +97,9 @@ def load_config(confpath, profile): def get_path_strip_version(path): '''Return the path of a file as stored in yaml config''' - strip = path - home = os.path.expanduser('~') - if strip.startswith(home): - strip = strip[len(home):] - return strip.lstrip('.' + os.sep) + path = strip_home(path) + path = path.lstrip('.' + os.sep) + return path def get_dotfile_from_yaml(dic, path): diff --git a/tests/test_config.py b/tests/test_config.py index 62100ac..6363806 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -89,7 +89,6 @@ class TestConfig(unittest.TestCase): # test profile opts = conf.get_settings() - print(conf.get_profiles()) profiles = conf.get_profiles() self.assertTrue(pf1key in profiles) self.assertTrue(pf2key in profiles)