From 1910514981b00a2b971fd72053fac18d881bf3ea Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Sat, 16 Nov 2019 19:28:33 +0100 Subject: [PATCH] add instignore for #195 --- dotdrop/dotdrop.py | 5 +- dotdrop/dotfile.py | 11 ++-- dotdrop/installer.py | 30 ++++++--- dotdrop/options.py | 1 + dotdrop/settings.py | 14 +++-- tests-ng/install-ignore.sh | 122 +++++++++++++++++++++++++++++++++++++ 6 files changed, 166 insertions(+), 17 deletions(-) create mode 100755 tests-ng/install-ignore.sh diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 4a3c201..1e8b7d1 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -137,9 +137,12 @@ def cmd_install(o): if not tmp: continue src = tmp + ignores = list(set(o.install_ignore + dotfile.instignore)) + ignores = patch_ignores(ignores, dotfile.dst, debug=o.debug) r, err = inst.install(t, src, dotfile.dst, actionexec=pre_actions_exec, - noempty=dotfile.noempty) + noempty=dotfile.noempty, + ignore=ignores) if tmp: tmp = os.path.join(o.dotpath, tmp) if os.path.exists(tmp): diff --git a/dotdrop/dotfile.py b/dotdrop/dotfile.py index 04d2f7d..8a61cae 100644 --- a/dotdrop/dotfile.py +++ b/dotdrop/dotfile.py @@ -19,8 +19,9 @@ class Dotfile(DictParser): def __init__(self, key, dst, src, actions=[], trans_r=None, trans_w=None, - link=LinkTypes.NOLINK, cmpignore=[], - noempty=False, upignore=[]): + link=LinkTypes.NOLINK, noempty=False, + cmpignore=[], upignore=[], + instignore=[]): """ constructor @key: dotfile key @@ -30,12 +31,12 @@ class Dotfile(DictParser): @trans_r: transformation to change dotfile before it is installed @trans_w: transformation to change dotfile before updating it @link: link behavior - @cmpignore: patterns to ignore when comparing @noempty: ignore empty template if True @upignore: patterns to ignore when updating + @cmpignore: patterns to ignore when comparing + @instignore: patterns to ignore when installing """ self.actions = actions - self.cmpignore = cmpignore self.dst = dst self.key = key self.link = LinkTypes.get(link) @@ -44,6 +45,8 @@ class Dotfile(DictParser): self.trans_r = trans_r self.trans_w = trans_w self.upignore = upignore + self.cmpignore = cmpignore + self.instignore = instignore if self.link != LinkTypes.NOLINK and \ ( diff --git a/dotdrop/installer.py b/dotdrop/installer.py index 564b30b..a08cbc1 100644 --- a/dotdrop/installer.py +++ b/dotdrop/installer.py @@ -48,7 +48,9 @@ class Installer: self.action_executed = False self.log = Logger() - def install(self, templater, src, dst, actionexec=None, noempty=False): + def install(self, templater, src, dst, + actionexec=None, noempty=False, + ignore=[]): """ install src to dst using a template @templater: the templater object @@ -56,6 +58,7 @@ class Installer: @dst: dotfile destination path in the FS @actionexec: action executor callback @noempty: render empty template flag + @ignore: pattern to ignore when installing return - True, None : success @@ -83,9 +86,10 @@ class Installer: if isdir: return self._handle_dir(templater, src, dst, actionexec=actionexec, - noempty=noempty) + noempty=noempty, ignore=ignore) return self._handle_file(templater, src, dst, - actionexec=actionexec, noempty=noempty) + actionexec=actionexec, + noempty=noempty, ignore=ignore) def link(self, templater, src, dst, actionexec=None): """ @@ -272,11 +276,19 @@ class Installer: return tmp def _handle_file(self, templater, src, dst, - actionexec=None, noempty=False): + actionexec=None, noempty=False, + ignore=[]): """install src to dst when is a file""" if self.debug: self.log.dbg('generate template for {}'.format(src)) self.log.dbg('ignore empty: {}'.format(noempty)) + self.log.dbg('ignore pattern: {}'.format(ignore)) + + if utils.must_ignore([src, dst], ignore, debug=self.debug): + if self.debug: + self.log.dbg('ignoring install of {} to {}'.format(src, dst)) + return False, None + if utils.samefile(src, dst): # symlink loop err = 'dotfile points to itself: {}'.format(dst) @@ -310,7 +322,9 @@ class Installer: err = 'installing {} to {}'.format(src, dst) return False, err - def _handle_dir(self, templater, src, dst, actionexec=None, noempty=False): + def _handle_dir(self, templater, src, dst, + actionexec=None, noempty=False, + ignore=[]): """install src to dst when is a directory""" if self.debug: self.log.dbg('install dir {}'.format(src)) @@ -328,7 +342,8 @@ class Installer: res, err = self._handle_file(templater, f, os.path.join(dst, entry), actionexec=actionexec, - noempty=noempty) + noempty=noempty, + ignore=ignore) if not res and err: # error occured ret = res, err @@ -341,7 +356,8 @@ class Installer: res, err = self._handle_dir(templater, f, os.path.join(dst, entry), actionexec=actionexec, - noempty=noempty) + noempty=noempty, + ignore=ignore) if not res and err: # error occured ret = res, err diff --git a/dotdrop/options.py b/dotdrop/options.py index 4933076..80e04b0 100644 --- a/dotdrop/options.py +++ b/dotdrop/options.py @@ -225,6 +225,7 @@ class Options(AttrMonitor): if a.kind == Action.pre] self.install_default_actions_post = [a for a in self.default_actions if a.kind == Action.post] + self.install_ignore = self.instignore # "compare" specifics self.compare_dopts = self.args['--dopts'] self.compare_focus = self.args['--file'] diff --git a/dotdrop/settings.py b/dotdrop/settings.py index b42ed0b..a6b3634 100644 --- a/dotdrop/settings.py +++ b/dotdrop/settings.py @@ -17,7 +17,6 @@ class Settings(DictParser): # settings item keys key_backup = 'backup' key_banner = 'banner' - key_cmpignore = 'cmpignore' key_create = 'create' key_default_actions = 'default_actions' key_dotpath = 'dotpath' @@ -28,6 +27,8 @@ class Settings(DictParser): key_link_on_import = 'link_on_import' key_showdiff = 'showdiff' key_upignore = 'upignore' + key_cmpignore = 'cmpignore' + key_instignore = 'instignore' key_workdir = 'workdir' key_minversion = 'minversion' @@ -36,18 +37,18 @@ class Settings(DictParser): key_import_configs = 'import_configs' key_import_variables = 'import_variables' - def __init__(self, backup=True, banner=True, cmpignore=[], + def __init__(self, backup=True, banner=True, create=True, default_actions=[], dotpath='dotfiles', ignoreempty=True, import_actions=[], import_configs=[], import_variables=[], keepdot=False, link_dotfile_default=LinkTypes.NOLINK, link_on_import=LinkTypes.NOLINK, longkey=False, - showdiff=False, upignore=[], workdir='~/.config/dotdrop', + upignore=[], cmpignore=[], instignore=[], + workdir='~/.config/dotdrop', showdiff=False, minversion=None): self.backup = backup self.banner = banner self.create = create - self.cmpignore = cmpignore self.default_actions = default_actions self.dotpath = dotpath self.ignoreempty = ignoreempty @@ -58,6 +59,8 @@ class Settings(DictParser): self.longkey = longkey self.showdiff = showdiff self.upignore = upignore + self.cmpignore = cmpignore + self.instignore = instignore self.workdir = workdir self.link_dotfile_default = LinkTypes.get(link_dotfile_default) self.link_on_import = LinkTypes.get(link_on_import) @@ -85,11 +88,12 @@ class Settings(DictParser): self.key_workdir: self.workdir, self.key_minversion: self.minversion, } - self._serialize_seq(self.key_cmpignore, dic) self._serialize_seq(self.key_default_actions, dic) self._serialize_seq(self.key_import_actions, dic) self._serialize_seq(self.key_import_configs, dic) self._serialize_seq(self.key_import_variables, dic) + self._serialize_seq(self.key_cmpignore, dic) self._serialize_seq(self.key_upignore, dic) + self._serialize_seq(self.key_instignore, dic) return {self.key_yaml: dic} diff --git a/tests-ng/install-ignore.sh b/tests-ng/install-ignore.sh new file mode 100755 index 0000000..edae408 --- /dev/null +++ b/tests-ng/install-ignore.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2019, deadc0de6 +# +# test install ignore absolute/relative +# 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 "$(tput setaf 6)==> RUNNING $(basename $BASH_SOURCE) <==$(tput sgr0)" + +################################################################ +# this is the test +################################################################ + +# dotdrop directory +basedir=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` +echo "[+] dotdrop dir: ${basedir}" +echo "[+] dotpath dir: ${basedir}/dotfiles" + +# the dotfile to be imported +tmpd=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` + +# some files +mkdir -p ${tmpd}/{program,config,vscode} +echo "some data" > ${tmpd}/program/a +echo "some data" > ${tmpd}/config/a +echo "some data" > ${tmpd}/vscode/extensions.txt +echo "some data" > ${tmpd}/vscode/keybindings.json + +# create the config file +cfg="${basedir}/config.yaml" +create_conf ${cfg} # sets token + +# import +echo "[+] import" +cd ${ddpath} | ${bin} import -c ${cfg} ${tmpd}/program +cd ${ddpath} | ${bin} import -c ${cfg} ${tmpd}/config +cd ${ddpath} | ${bin} import -c ${cfg} ${tmpd}/vscode + +# add files on filesystem +echo "[+] add files" +echo "new data" > ${basedir}/dotfiles/${tmpd}/README.md +echo "new data" > ${basedir}/dotfiles/${tmpd}/vscode/README.md +echo "new data" > ${basedir}/dotfiles/${tmpd}/program/README.md +mkdir -p ${basedir}/dotfiles/${tmpd}/readmes +echo "new data" > ${basedir}/dotfiles/${tmpd}/readmes/README.md + +# install +rm -rf ${tmpd} +echo "[+] install normal" +cd ${ddpath} | ${bin} install -c ${cfg} --verbose +[ "$?" != "0" ] && exit 1 +nb=`find ${tmpd} -iname 'README.md' | wc -l` +echo "(1) found ${nb} README.md file(s)" +[ "${nb}" != "2" ] && exit 1 + +# adding ignore in dotfile +cfg2="${basedir}/config2.yaml" +sed '/d_program:/a \ \ \ \ instignore:\n\ \ \ \ - "README.md"' ${cfg} > ${cfg2} +cat ${cfg2} + +# install +rm -rf ${tmpd} +echo "[+] install with ignore in dotfile" +cd ${ddpath} | ${bin} install -c ${cfg2} --verbose +[ "$?" != "0" ] && exit 1 +nb=`find ${tmpd} -iname 'README.md' | wc -l` +echo "(2) found ${nb} README.md file(s)" +[ "${nb}" != "1" ] && exit 1 + +# adding ignore in config +cfg2="${basedir}/config2.yaml" +sed '/^config:/a \ \ instignore:\n\ \ - "README.md"' ${cfg} > ${cfg2} +cat ${cfg2} + +# install +rm -rf ${tmpd} +echo "[+] install with ignore in config" +cd ${ddpath} | ${bin} install -c ${cfg2} --verbose +[ "$?" != "0" ] && exit 1 +nb=`find ${tmpd} -iname 'README.md' | wc -l` +echo "(3) found ${nb} README.md file(s)" +[ "${nb}" != "0" ] && exit 1 + +## CLEANING +rm -rf ${basedir} ${tmpd} + +echo "OK" +exit 0