From 0182e314ae2fa9ae5eef41f3761c5f267e0ff0cb Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 21:36:30 +0100 Subject: [PATCH 1/7] workdir compare --- dotdrop/dotdrop.py | 45 +++++++++- dotdrop/installer.py | 19 ++--- dotdrop/utils.py | 14 +++ tests-ng/workdir-compare.sh | 165 ++++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 15 deletions(-) create mode 100755 tests-ng/workdir-compare.sh diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index b66f71c..1e15c23 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -8,6 +8,7 @@ entry point import os import sys import time +import fnmatch from concurrent import futures # local imports @@ -20,7 +21,7 @@ from dotdrop.comparator import Comparator from dotdrop.importer import Importer from dotdrop.utils import get_tmpdir, removepath, \ uniq_list, patch_ignores, dependencies_met, \ - adapt_workers, check_version + adapt_workers, check_version, pivot_path from dotdrop.linktypes import LinkTypes from dotdrop.exceptions import YamlException, \ UndefinedException, UnmetDependency @@ -371,6 +372,44 @@ def cmd_install(opts): return True +def _workdir_enum(opts): + workdir_files = [] + for root, dirs, files in os.walk(opts.workdir): + for file in files: + fpath = os.path.join(root, file) + workdir_files.append(fpath) + + for dotfile in opts.dotfiles: + src = os.path.join(opts.dotpath, dotfile.src) + if dotfile.link == LinkTypes.NOLINK: + # ignore not link files + continue + if not Templategen.is_template(src): + # ignore not template + continue + newpath = pivot_path(dotfile.dst, opts.workdir, + striphome=True, logger=None) + if os.path.isdir(newpath): + # recursive + pattern = '{}/*'.format(newpath) + files = workdir_files.copy() + for f in files: + if fnmatch.fnmatch(f, pattern): + workdir_files.remove(f) + # only checks children + children = [f.path for f in os.scandir(newpath)] + for c in children: + if c in workdir_files: + workdir_files.remove(c) + else: + if newpath in workdir_files: + workdir_files.remove(newpath) + for w in workdir_files: + line = '=> \"{}\" does not exist in dotdrop' + LOG.log(line.format(w)) + return len(workdir_files) + + def cmd_compare(opts, tmp): """compare dotfiles and return True if all identical""" dotfiles = opts.dotfiles @@ -416,6 +455,10 @@ def cmd_compare(opts, tmp): same = False cnt += 1 + # TODO + if _workdir_enum(opts) > 0: + same = False + LOG.log('\n{} dotfile(s) compared.'.format(cnt)) return same diff --git a/dotdrop/installer.py b/dotdrop/installer.py index fd2a69a..db05773 100644 --- a/dotdrop/installer.py +++ b/dotdrop/installer.py @@ -224,7 +224,7 @@ class Installer: self.totemp = None # install the dotfile to a temp directory - tmpdst = self._pivot_path(dst, tmpdir) + tmpdst = utils.pivot_path(dst, tmpdir, logger=self.log) ret, err = self.install(templater, src, tmpdst, LinkTypes.NOLINK, is_template=is_template, @@ -260,7 +260,8 @@ class Installer: if is_template: self.log.dbg('is a template') self.log.dbg('install to {}'.format(self.workdir)) - tmp = self._pivot_path(dst, self.workdir, striphome=True) + tmp = utils.pivot_path(dst, self.workdir, + striphome=True, logger=self.log) ret, err = self.install(templater, src, tmp, LinkTypes.NOLINK, actionexec=actionexec, @@ -326,7 +327,8 @@ class Installer: self.log.dbg('child is a template') self.log.dbg('install to {} and symlink' .format(self.workdir)) - tmp = self._pivot_path(subdst, self.workdir, striphome=True) + tmp = utils.pivot_path(subdst, self.workdir, + striphome=True, logger=self.log) ret2, err2 = self.install(templater, subsrc, tmp, LinkTypes.NOLINK, actionexec=actionexec, @@ -698,17 +700,6 @@ class Installer: self.log.log('backup {} to {}'.format(path, dst)) os.rename(path, dst) - def _pivot_path(self, path, newdir, striphome=False): - """change path to be under newdir""" - self.log.dbg('pivot new dir: \"{}\"'.format(newdir)) - self.log.dbg('strip home: {}'.format(striphome)) - if striphome: - path = utils.strip_home(path) - sub = path.lstrip(os.sep) - new = os.path.join(newdir, sub) - self.log.dbg('pivot \"{}\" to \"{}\"'.format(path, new)) - return new - def _exec_pre_actions(self, actionexec): """execute action executor""" if self.action_executed: diff --git a/dotdrop/utils.py b/dotdrop/utils.py index 67798ae..38261f6 100644 --- a/dotdrop/utils.py +++ b/dotdrop/utils.py @@ -478,3 +478,17 @@ def check_version(): if version.parse(VERSION) < version.parse(latest): msg = 'A new version of dotdrop is available ({})' LOG.warn(msg.format(latest)) + + +def pivot_path(path, newdir, striphome=False, logger=None): + """change path to be under newdir""" + if logger: + logger.dbg('pivot new dir: \"{}\"'.format(newdir)) + logger.dbg('strip home: {}'.format(striphome)) + if striphome: + path = strip_home(path) + sub = path.lstrip(os.sep) + new = os.path.join(newdir, sub) + if logger: + logger.dbg('pivot \"{}\" to \"{}\"'.format(path, new)) + return new diff --git a/tests-ng/workdir-compare.sh b/tests-ng/workdir-compare.sh new file mode 100755 index 0000000..2be1873 --- /dev/null +++ b/tests-ng/workdir-compare.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2021, deadc0de6 +# +# test workdir compare and warn on untracked files +# 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 +################################################################ +unset DOTDROP_WORKDIR +string="blabla" + +# the dotfile source +tmp=`mktemp -d --suffix='-dotdrop-tests' || 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 --suffix='-dotdrop-tests' || mktemp -d` +echo "dotfiles destination: ${tmpd}" + +clear_on_exit "${tmp}" +clear_on_exit "${tmpd}" + +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + workdir: ${tmpw} +dotfiles: + f_a: + dst: ${tmpd}/a + src: a + link: link + f_b: + dst: ${tmpd}/b + src: b + link: nolink + d_c: + dst: ${tmpd}/c + src: c + link: link_children +profiles: + p1: + dotfiles: + - f_a + - f_b + - d_c +_EOF +#cat ${cfg} + +# create the dotfile +echo "{{@@ profile @@}}" > ${tmpf}/a +echo "{{@@ profile @@}}" > ${tmpf}/b +mkdir -p ${tmpf}/c +echo "{{@@ profile @@}}" > ${tmpf}/c/a +echo "{{@@ profile @@}}" > ${tmpf}/c/b +mkdir ${tmpf}/c/x +echo "{{@@ profile @@}}" > ${tmpf}/c/x/a +echo "{{@@ profile @@}}" > ${tmpf}/c/x/b + +# install +cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -b + +# compare (no diff) +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V + +# add file +touch ${tmpw}/untrack + +# compare (one diff) +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (1)" && exit 1 +set -e + +# clean +rm ${tmpw}/untrack +# add sub file +touch ${tmpw}/${tmpd}/c/x/untrack + +# compare (two diff) +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (2)" && exit 1 +set -e + +# clean +rm ${tmpw}/${tmpd}/c/x/untrack +# add dir +mkdir ${tmpw}/d_untrack +touch ${tmpw}/d_untrack/untrack + +# compare (three diffs) +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (3)" && exit 1 +set -e + +# clean +rm -r ${tmpw}/d_untrack +# add sub dir +mkdir ${tmpw}/${tmpd}/c/x/d_untrack +touch ${tmpw}/${tmpd}/c/x/d_untrack/untrack + +# compare +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (4)" && exit 1 +set -e + +## CLEANING +rm -rf ${tmp} ${tmpd} + +echo "OK" +exit 0 From f07c32426636d580394809c78bef0acf60b35c01 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 21:39:42 +0100 Subject: [PATCH 2/7] linting --- dotdrop/dotdrop.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 1e15c23..22dc87f 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -374,7 +374,7 @@ def cmd_install(opts): def _workdir_enum(opts): workdir_files = [] - for root, dirs, files in os.walk(opts.workdir): + for root, _, files in os.walk(opts.workdir): for file in files: fpath = os.path.join(root, file) workdir_files.append(fpath) @@ -393,20 +393,20 @@ def _workdir_enum(opts): # recursive pattern = '{}/*'.format(newpath) files = workdir_files.copy() - for f in files: - if fnmatch.fnmatch(f, pattern): - workdir_files.remove(f) + for file in files: + if fnmatch.fnmatch(file, pattern): + workdir_files.remove(file) # only checks children children = [f.path for f in os.scandir(newpath)] - for c in children: - if c in workdir_files: - workdir_files.remove(c) + for child in children: + if child in workdir_files: + workdir_files.remove(child) else: if newpath in workdir_files: workdir_files.remove(newpath) - for w in workdir_files: + for wfile in workdir_files: line = '=> \"{}\" does not exist in dotdrop' - LOG.log(line.format(w)) + LOG.log(line.format(wfile)) return len(workdir_files) @@ -455,8 +455,7 @@ def cmd_compare(opts, tmp): same = False cnt += 1 - # TODO - if _workdir_enum(opts) > 0: + if _workdir_enum(opts) > 0: same = False LOG.log('\n{} dotfile(s) compared.'.format(cnt)) From 42dc86366ecfb7d6ceac216fd286e851918e3555 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 21:36:30 +0100 Subject: [PATCH 3/7] workdir compare --- dotdrop/dotdrop.py | 45 +++++++++- dotdrop/installer.py | 19 ++--- dotdrop/utils.py | 14 +++ tests-ng/workdir-compare.sh | 165 ++++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 15 deletions(-) create mode 100755 tests-ng/workdir-compare.sh diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index d41a16a..733f0db 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -8,6 +8,7 @@ entry point import os import sys import time +import fnmatch from concurrent import futures # local imports @@ -20,7 +21,7 @@ from dotdrop.comparator import Comparator from dotdrop.importer import Importer from dotdrop.utils import get_tmpdir, removepath, \ uniq_list, patch_ignores, dependencies_met, \ - adapt_workers, check_version + adapt_workers, check_version, pivot_path from dotdrop.linktypes import LinkTypes from dotdrop.exceptions import YamlException, \ UndefinedException, UnmetDependency @@ -379,6 +380,44 @@ def cmd_install(opts): return True +def _workdir_enum(opts): + workdir_files = [] + for root, dirs, files in os.walk(opts.workdir): + for file in files: + fpath = os.path.join(root, file) + workdir_files.append(fpath) + + for dotfile in opts.dotfiles: + src = os.path.join(opts.dotpath, dotfile.src) + if dotfile.link == LinkTypes.NOLINK: + # ignore not link files + continue + if not Templategen.is_template(src): + # ignore not template + continue + newpath = pivot_path(dotfile.dst, opts.workdir, + striphome=True, logger=None) + if os.path.isdir(newpath): + # recursive + pattern = '{}/*'.format(newpath) + files = workdir_files.copy() + for f in files: + if fnmatch.fnmatch(f, pattern): + workdir_files.remove(f) + # only checks children + children = [f.path for f in os.scandir(newpath)] + for c in children: + if c in workdir_files: + workdir_files.remove(c) + else: + if newpath in workdir_files: + workdir_files.remove(newpath) + for w in workdir_files: + line = '=> \"{}\" does not exist in dotdrop' + LOG.log(line.format(w)) + return len(workdir_files) + + def cmd_compare(opts, tmp): """compare dotfiles and return True if all identical""" dotfiles = opts.dotfiles @@ -424,6 +463,10 @@ def cmd_compare(opts, tmp): same = False cnt += 1 + # TODO + if _workdir_enum(opts) > 0: + same = False + LOG.log('\n{} dotfile(s) compared.'.format(cnt)) return same diff --git a/dotdrop/installer.py b/dotdrop/installer.py index fd2a69a..db05773 100644 --- a/dotdrop/installer.py +++ b/dotdrop/installer.py @@ -224,7 +224,7 @@ class Installer: self.totemp = None # install the dotfile to a temp directory - tmpdst = self._pivot_path(dst, tmpdir) + tmpdst = utils.pivot_path(dst, tmpdir, logger=self.log) ret, err = self.install(templater, src, tmpdst, LinkTypes.NOLINK, is_template=is_template, @@ -260,7 +260,8 @@ class Installer: if is_template: self.log.dbg('is a template') self.log.dbg('install to {}'.format(self.workdir)) - tmp = self._pivot_path(dst, self.workdir, striphome=True) + tmp = utils.pivot_path(dst, self.workdir, + striphome=True, logger=self.log) ret, err = self.install(templater, src, tmp, LinkTypes.NOLINK, actionexec=actionexec, @@ -326,7 +327,8 @@ class Installer: self.log.dbg('child is a template') self.log.dbg('install to {} and symlink' .format(self.workdir)) - tmp = self._pivot_path(subdst, self.workdir, striphome=True) + tmp = utils.pivot_path(subdst, self.workdir, + striphome=True, logger=self.log) ret2, err2 = self.install(templater, subsrc, tmp, LinkTypes.NOLINK, actionexec=actionexec, @@ -698,17 +700,6 @@ class Installer: self.log.log('backup {} to {}'.format(path, dst)) os.rename(path, dst) - def _pivot_path(self, path, newdir, striphome=False): - """change path to be under newdir""" - self.log.dbg('pivot new dir: \"{}\"'.format(newdir)) - self.log.dbg('strip home: {}'.format(striphome)) - if striphome: - path = utils.strip_home(path) - sub = path.lstrip(os.sep) - new = os.path.join(newdir, sub) - self.log.dbg('pivot \"{}\" to \"{}\"'.format(path, new)) - return new - def _exec_pre_actions(self, actionexec): """execute action executor""" if self.action_executed: diff --git a/dotdrop/utils.py b/dotdrop/utils.py index 67798ae..38261f6 100644 --- a/dotdrop/utils.py +++ b/dotdrop/utils.py @@ -478,3 +478,17 @@ def check_version(): if version.parse(VERSION) < version.parse(latest): msg = 'A new version of dotdrop is available ({})' LOG.warn(msg.format(latest)) + + +def pivot_path(path, newdir, striphome=False, logger=None): + """change path to be under newdir""" + if logger: + logger.dbg('pivot new dir: \"{}\"'.format(newdir)) + logger.dbg('strip home: {}'.format(striphome)) + if striphome: + path = strip_home(path) + sub = path.lstrip(os.sep) + new = os.path.join(newdir, sub) + if logger: + logger.dbg('pivot \"{}\" to \"{}\"'.format(path, new)) + return new diff --git a/tests-ng/workdir-compare.sh b/tests-ng/workdir-compare.sh new file mode 100755 index 0000000..2be1873 --- /dev/null +++ b/tests-ng/workdir-compare.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2021, deadc0de6 +# +# test workdir compare and warn on untracked files +# 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 +################################################################ +unset DOTDROP_WORKDIR +string="blabla" + +# the dotfile source +tmp=`mktemp -d --suffix='-dotdrop-tests' || 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 --suffix='-dotdrop-tests' || mktemp -d` +echo "dotfiles destination: ${tmpd}" + +clear_on_exit "${tmp}" +clear_on_exit "${tmpd}" + +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + workdir: ${tmpw} +dotfiles: + f_a: + dst: ${tmpd}/a + src: a + link: link + f_b: + dst: ${tmpd}/b + src: b + link: nolink + d_c: + dst: ${tmpd}/c + src: c + link: link_children +profiles: + p1: + dotfiles: + - f_a + - f_b + - d_c +_EOF +#cat ${cfg} + +# create the dotfile +echo "{{@@ profile @@}}" > ${tmpf}/a +echo "{{@@ profile @@}}" > ${tmpf}/b +mkdir -p ${tmpf}/c +echo "{{@@ profile @@}}" > ${tmpf}/c/a +echo "{{@@ profile @@}}" > ${tmpf}/c/b +mkdir ${tmpf}/c/x +echo "{{@@ profile @@}}" > ${tmpf}/c/x/a +echo "{{@@ profile @@}}" > ${tmpf}/c/x/b + +# install +cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -b + +# compare (no diff) +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V + +# add file +touch ${tmpw}/untrack + +# compare (one diff) +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (1)" && exit 1 +set -e + +# clean +rm ${tmpw}/untrack +# add sub file +touch ${tmpw}/${tmpd}/c/x/untrack + +# compare (two diff) +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (2)" && exit 1 +set -e + +# clean +rm ${tmpw}/${tmpd}/c/x/untrack +# add dir +mkdir ${tmpw}/d_untrack +touch ${tmpw}/d_untrack/untrack + +# compare (three diffs) +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (3)" && exit 1 +set -e + +# clean +rm -r ${tmpw}/d_untrack +# add sub dir +mkdir ${tmpw}/${tmpd}/c/x/d_untrack +touch ${tmpw}/${tmpd}/c/x/d_untrack/untrack + +# compare +set +e +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -b -V +[ "$?" != "1" ] && echo "not found untracked file in workdir (4)" && exit 1 +set -e + +## CLEANING +rm -rf ${tmp} ${tmpd} + +echo "OK" +exit 0 From 9d9077cc3f9c9694680ab8fc42b148252844e1af Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 21:39:42 +0100 Subject: [PATCH 4/7] linting --- dotdrop/dotdrop.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 733f0db..5efe485 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -382,7 +382,7 @@ def cmd_install(opts): def _workdir_enum(opts): workdir_files = [] - for root, dirs, files in os.walk(opts.workdir): + for root, _, files in os.walk(opts.workdir): for file in files: fpath = os.path.join(root, file) workdir_files.append(fpath) @@ -401,20 +401,20 @@ def _workdir_enum(opts): # recursive pattern = '{}/*'.format(newpath) files = workdir_files.copy() - for f in files: - if fnmatch.fnmatch(f, pattern): - workdir_files.remove(f) + for file in files: + if fnmatch.fnmatch(file, pattern): + workdir_files.remove(file) # only checks children children = [f.path for f in os.scandir(newpath)] - for c in children: - if c in workdir_files: - workdir_files.remove(c) + for child in children: + if child in workdir_files: + workdir_files.remove(child) else: if newpath in workdir_files: workdir_files.remove(newpath) - for w in workdir_files: + for wfile in workdir_files: line = '=> \"{}\" does not exist in dotdrop' - LOG.log(line.format(w)) + LOG.log(line.format(wfile)) return len(workdir_files) @@ -463,8 +463,7 @@ def cmd_compare(opts, tmp): same = False cnt += 1 - # TODO - if _workdir_enum(opts) > 0: + if _workdir_enum(opts) > 0: same = False LOG.log('\n{} dotfile(s) compared.'.format(cnt)) From 43ab41bb1f10c0d2f2b71acc428b84c56f0ed3c9 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 21:49:05 +0100 Subject: [PATCH 5/7] add config option workdir_compare --- dotdrop/dotdrop.py | 2 +- dotdrop/settings.py | 6 +++++- tests-ng/workdir-compare.sh | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 5efe485..9fdfab1 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -463,7 +463,7 @@ def cmd_compare(opts, tmp): same = False cnt += 1 - if _workdir_enum(opts) > 0: + if opts.compare_workdir and _workdir_enum(opts) > 0: same = False LOG.log('\n{} dotfile(s) compared.'.format(cnt)) diff --git a/dotdrop/settings.py b/dotdrop/settings.py index 54554d2..eb36cbd 100644 --- a/dotdrop/settings.py +++ b/dotdrop/settings.py @@ -47,6 +47,7 @@ class Settings(DictParser): key_chmod_on_import = 'chmod_on_import' key_check_version = 'check_version' key_clear_workdir = 'clear_workdir' + key_compare_workdir = 'compare_workdir' # import keys key_import_actions = 'import_actions' @@ -67,7 +68,8 @@ class Settings(DictParser): template_dotfile_default=True, ignore_missing_in_dotdrop=False, force_chmod=False, chmod_on_import=False, - check_version=False, clear_workdir=False): + check_version=False, clear_workdir=False, + compare_workdir=False): self.backup = backup self.banner = banner self.create = create @@ -99,6 +101,7 @@ class Settings(DictParser): self.chmod_on_import = chmod_on_import self.check_version = check_version self.clear_workdir = clear_workdir + self.compare_workdir = compare_workdir def _serialize_seq(self, name, dic): """serialize attribute 'name' into 'dic'""" @@ -127,6 +130,7 @@ class Settings(DictParser): self.key_chmod_on_import: self.chmod_on_import, self.key_check_version: self.check_version, self.key_clear_workdir: self.clear_workdir, + self.key_compare_workdir: self.compare_workdir, } self._serialize_seq(self.key_default_actions, dic) self._serialize_seq(self.key_import_actions, dic) diff --git a/tests-ng/workdir-compare.sh b/tests-ng/workdir-compare.sh index 2be1873..ddcfe9f 100755 --- a/tests-ng/workdir-compare.sh +++ b/tests-ng/workdir-compare.sh @@ -76,6 +76,7 @@ config: create: true dotpath: dotfiles workdir: ${tmpw} + workdir_compare: true dotfiles: f_a: dst: ${tmpd}/a From 4296168a9e2bcb9db73336923540a14c4fa8fd18 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 21:59:56 +0100 Subject: [PATCH 6/7] fix test --- tests-ng/workdir-compare.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-ng/workdir-compare.sh b/tests-ng/workdir-compare.sh index ddcfe9f..e7371de 100755 --- a/tests-ng/workdir-compare.sh +++ b/tests-ng/workdir-compare.sh @@ -76,7 +76,7 @@ config: create: true dotpath: dotfiles workdir: ${tmpw} - workdir_compare: true + compare_workdir: true dotfiles: f_a: dst: ${tmpd}/a From 79bb785424602c72c5d07fd92ebb359434c0fe39 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Mon, 1 Nov 2021 22:00:14 +0100 Subject: [PATCH 7/7] add doc for compare_workdir --- docs/config-format.md | 1 + docs/usage.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/docs/config-format.md b/docs/config-format.md index 36ea314..d9d2b56 100644 --- a/docs/config-format.md +++ b/docs/config-format.md @@ -16,6 +16,7 @@ Entry | Description | Default `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` | On `install` clear the `workdir` before installing dotfiles (see `--workdir-clear`) | false +`compare_workdir` | On `compare` notify on files in `workdir` not tracked by dotdrop | 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 298a810..fef175b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -112,6 +112,9 @@ To ignore specific patterns, see [the ignore patterns](config.md#ignore-patterns To completely ignore all files not present in `dotpath` see [Ignore missing](#ignore-missing). +If you want to get notified on files present in the `workdir` but not tracked +by dotdrop see the [compare_workdir](config-format.md). + For more options, see the usage with `dotdrop --help`. ## List profiles