From b39a03479f581c36a7f5ec302160388367ecd5b5 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Fri, 29 Oct 2021 18:05:22 +0200 Subject: [PATCH 1/7] add clear_workdir and -W for #330 --- docs/config-format.md | 1 + dotdrop/dotdrop.py | 8 ++++++++ dotdrop/options.py | 26 ++++++++++++++------------ dotdrop/settings.py | 8 +++++--- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/docs/config-format.md b/docs/config-format.md index 28b12ad..10ea38c 100644 --- a/docs/config-format.md +++ b/docs/config-format.md @@ -15,6 +15,7 @@ Entry | Description | Default `banner` | Display the banner | true `check_version` | Check if a new version of dotdrop is available on github | false `chmod_on_import` | Always add a chmod entry on newly imported dotfiles (see `--preserve-mode`) | false +`clear_workdir` | Clear the `workdir` before install | false `cmpignore` | List of patterns to ignore when comparing, applied to all dotfiles (enclose in quotes when using wildcards; see [ignore patterns](config.md#ignore-patterns)) | - `create` | Create a directory hierarchy when installing dotfiles if it doesn't exist | true `default_actions` | List of action keys to execute for all installed dotfiles (See [actions](config-details.md#actions-entry)) | - diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index b66f71c..d41a16a 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -317,6 +317,14 @@ def cmd_install(opts): installed = [] + # clear the workdir + if opts.install_clear_workdir and not opts.dry: + LOG.dbg('clearing the workdir under {}'.format(opts.workdir)) + for root, _, files in os.walk(opts.workdir): + for file in files: + fpath = os.path.join(root, file) + removepath(fpath, logger=LOG) + # execute profile pre-action LOG.dbg('run {} profile pre actions'.format(len(pro_pre_actions))) templ = _get_templater(opts) diff --git a/dotdrop/options.py b/dotdrop/options.py index f1ea7f8..e43e6fa 100644 --- a/dotdrop/options.py +++ b/dotdrop/options.py @@ -56,18 +56,18 @@ USAGE = """ {} Usage: - dotdrop install [-VbtfndDa] [-c ] [-p ] - [-w ] [...] - dotdrop import [-Vbdfm] [-c ] [-p ] [-s ] - [-l ] [-i ...] ... - dotdrop compare [-LVbz] [-c ] [-p ] - [-w ] [-C ...] [-i ...] - dotdrop update [-VbfdkPz] [-c ] [-p ] - [-w ] [-i ...] [...] - dotdrop remove [-Vbfdk] [-c ] [-p ] [...] - dotdrop files [-VbTG] [-c ] [-p ] - dotdrop detail [-Vb] [-c ] [-p ] [...] - dotdrop profiles [-VbG] [-c ] + dotdrop install [-VbtfndDaW] [-c ] [-p ] + [-w ] [...] + dotdrop import [-Vbdfm] [-c ] [-p ] [-s ] + [-l ] [-i ...] ... + dotdrop compare [-LVbz] [-c ] [-p ] + [-w ] [-C ...] [-i ...] + dotdrop update [-VbfdkPz] [-c ] [-p ] + [-w ] [-i ...] [...] + dotdrop remove [-Vbfdk] [-c ] [-p ] [...] + dotdrop files [-VbTG] [-c ] [-p ] + dotdrop detail [-Vb] [-c ] [-p ] [...] + dotdrop profiles [-VbG] [-c ] dotdrop --help dotdrop --version @@ -93,6 +93,7 @@ Options: -T --template Only template dotfiles. -V --verbose Be verbose. -w --workers= Number of concurrent workers [default: 1]. + -W --workdir-clear Clear the workdir. -z --ignore-missing Ignore files in installed folders that are missing. -v --version Show version. -h --help Show this screen. @@ -244,6 +245,7 @@ class Options(AttrMonitor): if a.kind == Action.post] self.install_ignore = self.instignore self.install_force_chmod = self.force_chmod + self.install_clear_workdir = self.args['--workdir-clear'] or self.clear_workdir def _apply_args_compare(self): """compare specifics""" diff --git a/dotdrop/settings.py b/dotdrop/settings.py index 3b4675a..54554d2 100644 --- a/dotdrop/settings.py +++ b/dotdrop/settings.py @@ -46,6 +46,7 @@ class Settings(DictParser): key_ignore_missing_in_dotdrop = 'ignore_missing_in_dotdrop' key_chmod_on_import = 'chmod_on_import' key_check_version = 'check_version' + key_clear_workdir = 'clear_workdir' # import keys key_import_actions = 'import_actions' @@ -65,9 +66,8 @@ class Settings(DictParser): diff_command='diff -r -u {0} {1}', template_dotfile_default=True, ignore_missing_in_dotdrop=False, - force_chmod=False, - chmod_on_import=False, - check_version=False): + force_chmod=False, chmod_on_import=False, + check_version=False, clear_workdir=False): self.backup = backup self.banner = banner self.create = create @@ -98,6 +98,7 @@ class Settings(DictParser): self.force_chmod = force_chmod self.chmod_on_import = chmod_on_import self.check_version = check_version + self.clear_workdir = clear_workdir def _serialize_seq(self, name, dic): """serialize attribute 'name' into 'dic'""" @@ -125,6 +126,7 @@ class Settings(DictParser): self.key_force_chmod: self.force_chmod, self.key_chmod_on_import: self.chmod_on_import, self.key_check_version: self.check_version, + self.key_clear_workdir: self.clear_workdir, } self._serialize_seq(self.key_default_actions, dic) self._serialize_seq(self.key_import_actions, dic) From 0193d184efd66004c7f45b0a80d220822ae5b780 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Fri, 29 Oct 2021 18:18:15 +0200 Subject: [PATCH 2/7] add test for clear_workdir --- tests-ng/clear-workdir.sh | 132 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100755 tests-ng/clear-workdir.sh diff --git a/tests-ng/clear-workdir.sh b/tests-ng/clear-workdir.sh new file mode 100755 index 0000000..c96490d --- /dev/null +++ b/tests-ng/clear-workdir.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2021, deadc0de6 +# +# test clear_workdir +# 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" +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 +################################################################ + +# dotdrop directory +basedir=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` +mkdir -p ${basedir}/dotfiles +echo "[+] dotdrop dir: ${basedir}" +echo "[+] dotpath dir: ${basedir}/dotfiles" +tmpd=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` +tmpw=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` + +clear_on_exit "${basedir}" +clear_on_exit "${tmpd}" +clear_on_exit "${tmpw}" + +echo "{{@@ profile @@}}" > ${basedir}/dotfiles/x + +# create the config file +cfg="${basedir}/config.yaml" +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + workdir: ${tmpw} +dotfiles: + f_x: + src: x + dst: ${tmpd}/x + link: link +profiles: + p1: + dotfiles: + - f_x +_EOF + +echo "[+] install" +cd ${ddpath} | ${bin} install -c ${cfg} -f -p p1 --verbose | grep '^1 dotfile(s) installed.$' +[ "$?" != "0" ] && exit 1 + +[ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 +[ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 +[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir" && exit 1 + +# add file +touch ${tmpw}/new + +echo "[+] re-install with clear-workdir" +cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose +[ "$?" != "0" ] && exit 1 + +[ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 +[ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 +[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir" && exit 1 +[ -e ${tmpw}/new ] && echo "workdir not cleared" && exit 1 + +# add file +touch ${tmpw}/new + +echo "[+] re-install with config clear-workdir" +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + workdir: ${tmpw} + clear_workdir: true +dotfiles: + f_x: + src: x + dst: ${tmpd}/x + link: link +profiles: + p1: + dotfiles: + - f_x +_EOF +cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose +[ "$?" != "0" ] && exit 1 + +[ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 +[ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 +[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir" && exit 1 +[ -e ${tmpw}/new ] && echo "workdir not cleared" && exit 1 + +echo "OK" +exit 0 From 174d674b4252c715631ec11840c2928028e9f65a Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Fri, 29 Oct 2021 18:18:20 +0200 Subject: [PATCH 3/7] fix tests --- dotdrop/options.py | 4 +++- tests/helpers.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dotdrop/options.py b/dotdrop/options.py index e43e6fa..96fd893 100644 --- a/dotdrop/options.py +++ b/dotdrop/options.py @@ -133,6 +133,7 @@ class Options(AttrMonitor): self.link_on_import = None self.chmod_on_import = None self.check_version = None + self.clear_workdir = None # args parsing self.args = {} @@ -245,7 +246,8 @@ class Options(AttrMonitor): if a.kind == Action.post] self.install_ignore = self.instignore self.install_force_chmod = self.force_chmod - self.install_clear_workdir = self.args['--workdir-clear'] or self.clear_workdir + self.install_clear_workdir = self.args['--workdir-clear'] or \ + self.clear_workdir def _apply_args_compare(self): """compare specifics""" diff --git a/tests/helpers.py b/tests/helpers.py index c29fe62..458514f 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -136,6 +136,7 @@ def _fake_args(): args['--workers'] = 1 args['--preserve-mode'] = False args['--ignore-missing'] = False + args['--workdir-clear'] = False # cmds args['profiles'] = False args['files'] = False From fe43612aef94c62514af18c3d82d382f9ca732e7 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Fri, 29 Oct 2021 18:27:16 +0200 Subject: [PATCH 4/7] more logs for tests --- tests-ng/clear-workdir.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests-ng/clear-workdir.sh b/tests-ng/clear-workdir.sh index c96490d..ec3ad40 100755 --- a/tests-ng/clear-workdir.sh +++ b/tests-ng/clear-workdir.sh @@ -79,30 +79,30 @@ profiles: - f_x _EOF -echo "[+] install" +echo "[+] install (1)" cd ${ddpath} | ${bin} install -c ${cfg} -f -p p1 --verbose | grep '^1 dotfile(s) installed.$' [ "$?" != "0" ] && exit 1 [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 -[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir" && exit 1 +[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 # add file touch ${tmpw}/new -echo "[+] re-install with clear-workdir" +echo "[+] re-install with clear-workdir in cli" cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose [ "$?" != "0" ] && exit 1 [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 -[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir" && exit 1 -[ -e ${tmpw}/new ] && echo "workdir not cleared" && exit 1 +[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 +[ -e ${tmpw}/new ] && echo "workdir not cleared (1)" && exit 1 # add file touch ${tmpw}/new -echo "[+] re-install with config clear-workdir" +echo "[+] re-install with config clear-workdir in config" cat > ${cfg} << _EOF config: backup: true @@ -125,8 +125,8 @@ cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 -[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir" && exit 1 -[ -e ${tmpw}/new ] && echo "workdir not cleared" && exit 1 +[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 +[ -e ${tmpw}/new ] && echo "workdir not cleared (2)" && exit 1 echo "OK" exit 0 From 2867b13aec6e17c23b495c7013c269398e104445 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Fri, 29 Oct 2021 18:37:39 +0200 Subject: [PATCH 5/7] where is workdir on cicd --- tests-ng/clear-workdir.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests-ng/clear-workdir.sh b/tests-ng/clear-workdir.sh index ec3ad40..cfc36f1 100755 --- a/tests-ng/clear-workdir.sh +++ b/tests-ng/clear-workdir.sh @@ -85,6 +85,7 @@ cd ${ddpath} | ${bin} install -c ${cfg} -f -p p1 --verbose | grep '^1 dotfile(s) [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 +ls -l ${tmpd}/x [ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 # add file From 6e0d369038b50cfae092957b0790807f5fca360c Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Sat, 30 Oct 2021 14:41:33 +0200 Subject: [PATCH 6/7] fix clear workdir tests --- tests-ng/clear-workdir.sh | 24 ++++++++++++------------ tests.sh | 13 +++++++++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/tests-ng/clear-workdir.sh b/tests-ng/clear-workdir.sh index cfc36f1..89a4f30 100755 --- a/tests-ng/clear-workdir.sh +++ b/tests-ng/clear-workdir.sh @@ -52,11 +52,14 @@ mkdir -p ${basedir}/dotfiles echo "[+] dotdrop dir: ${basedir}" echo "[+] dotpath dir: ${basedir}/dotfiles" tmpd=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` -tmpw=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` +if [ -z "${DOTDROP_WORKDIR}" ]; then + tmpw=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` + export DOTDROP_WORKDIR="${tmpw}" + clear_on_exit "${tmpw}" +fi clear_on_exit "${basedir}" clear_on_exit "${tmpd}" -clear_on_exit "${tmpw}" echo "{{@@ profile @@}}" > ${basedir}/dotfiles/x @@ -67,7 +70,6 @@ config: backup: true create: true dotpath: dotfiles - workdir: ${tmpw} dotfiles: f_x: src: x @@ -85,11 +87,10 @@ cd ${ddpath} | ${bin} install -c ${cfg} -f -p p1 --verbose | grep '^1 dotfile(s) [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 -ls -l ${tmpd}/x -[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 +[ ! -e ${DOTDROP_WORKDIR}/${tmpd}/x ] && echo "f_x not in workdir (${DOTDROP_WORKDIR}/${tmpd})" && exit 1 # add file -touch ${tmpw}/new +touch ${DOTDROP_WORKDIR}/new echo "[+] re-install with clear-workdir in cli" cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose @@ -97,11 +98,11 @@ cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 -[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 -[ -e ${tmpw}/new ] && echo "workdir not cleared (1)" && exit 1 +[ ! -e ${DOTDROP_WORKDIR}/${tmpd}/x ] && echo "f_x not in workdir (${DOTDROP_WORKDIR}/${tmpd})" && exit 1 +[ -e ${DOTDROP_WORKDIR}/new ] && echo "workdir not cleared (1)" && exit 1 # add file -touch ${tmpw}/new +touch ${DOTDROP_WORKDIR}/new echo "[+] re-install with config clear-workdir in config" cat > ${cfg} << _EOF @@ -109,7 +110,6 @@ config: backup: true create: true dotpath: dotfiles - workdir: ${tmpw} clear_workdir: true dotfiles: f_x: @@ -126,8 +126,8 @@ cd ${ddpath} | printf "y\n" | ${bin} install -W -c ${cfg} -p p1 --verbose [ ! -e ${tmpd}/x ] && echo "f_x not installed" && exit 1 [ ! -h ${tmpd}/x ] && echo "f_x not symlink" && exit 1 -[ ! -e ${tmpw}/${tmpd}/x ] && echo "f_x not in workdir (${tmpw}/${tmpd})" && exit 1 -[ -e ${tmpw}/new ] && echo "workdir not cleared (2)" && exit 1 +[ ! -e ${DOTDROP_WORKDIR}/${tmpd}/x ] && echo "f_x not in workdir (${DOTDROP_WORKDIR}/${tmpd})" && exit 1 +[ -e ${DOTDROP_WORKDIR}/new ] && echo "workdir not cleared (2)" && exit 1 echo "OK" exit 0 diff --git a/tests.sh b/tests.sh index 0ab00a9..adfee97 100755 --- a/tests.sh +++ b/tests.sh @@ -82,7 +82,8 @@ fi unset DOTDROP_DEBUG= export DOTDROP_FORCE_NODEBUG=yes -export DOTDROP_WORKDIR=/tmp/dotdrop-tests-workdir +tmpworkdir="/tmp/dotdrop-tests-workdir" +export DOTDROP_WORKDIR="${tmpworkdir}" if [ ! -z ${workers} ]; then DOTDROP_WORKERS=${workers} @@ -90,8 +91,8 @@ if [ ! -z ${workers} ]; then fi # run bash tests -workdir_tmp="no" -[ -d "~/.config/dotdrop/tmp" ] && workdir_tmp="yes" +workdir_tmp_exists="no" +[ -d "~/.config/dotdrop/tmp" ] && workdir_tmp_exists="yes" if [ -z ${GITHUB_WORKFLOW} ]; then ## local export COVERAGE_FILE= @@ -101,7 +102,11 @@ else export COVERAGE_FILE="${cur}/.coverage" tests-ng/tests-launcher.py 1 fi -[ "${workdir_tmp}" = "no" ] && rm -rf ~/.config/dotdrop/tmp + +# clear workdir +[ "${workdir_tmp_exists}" = "no" ] && rm -rf ~/.config/dotdrop/tmp +# clear temp workdir +rm -rf "${tmpworkdir}" ## test the doc with remark ## https://github.com/remarkjs/remark-validate-links From f137fac71923e38225c079267640da1d3fd16e85 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Sat, 30 Oct 2021 14:41:43 +0200 Subject: [PATCH 7/7] update doc --- docs/config-format.md | 2 +- docs/usage.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/config-format.md b/docs/config-format.md index 10ea38c..36ea314 100644 --- a/docs/config-format.md +++ b/docs/config-format.md @@ -15,7 +15,7 @@ Entry | Description | Default `banner` | Display the banner | true `check_version` | Check if a new version of dotdrop is available on github | false `chmod_on_import` | Always add a chmod entry on newly imported dotfiles (see `--preserve-mode`) | false -`clear_workdir` | Clear the `workdir` before install | false +`clear_workdir` | On `install` clear the `workdir` before installing dotfiles (see `--workdir-clear`) | false `cmpignore` | List of patterns to ignore when comparing, applied to all dotfiles (enclose in quotes when using wildcards; see [ignore patterns](config.md#ignore-patterns)) | - `create` | Create a directory hierarchy when installing dotfiles if it doesn't exist | true `default_actions` | List of action keys to execute for all installed dotfiles (See [actions](config-details.md#actions-entry)) | - diff --git a/docs/usage.md b/docs/usage.md index 69bd2dc..298a810 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -87,6 +87,7 @@ Some available options: Note that actions are not executed in this mode. * `-a`/`--force-actions`: Force the execution of actions even if the dotfiles are not installed * `-f`/`--force`: Do not ask for any confirmation +* `-W`/`--workdir-clear`: Clear the `workdir` before installing dotfiles (see config entry `clear_workdir`) To ignore specific patterns during installation, see [the ignore patterns](config.md#ignore-patterns).