1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-12 22:45:13 +00:00

implement relative upignore/cmpignore for #149 and some import refactoring

This commit is contained in:
deadc0de6
2019-06-04 21:50:11 +02:00
parent ba93547ea0
commit d4b3ed2229
6 changed files with 315 additions and 26 deletions

View File

@@ -10,7 +10,7 @@ import filecmp
# local imports # local imports
from dotdrop.logger import Logger from dotdrop.logger import Logger
import dotdrop.utils as utils from dotdrop.utils import must_ignore, uniq_list, diff
class Comparator: class Comparator:
@@ -43,7 +43,7 @@ class Comparator:
"""compare a file""" """compare a file"""
if self.debug: if self.debug:
self.log.dbg('compare file {} with {}'.format(left, right)) self.log.dbg('compare file {} with {}'.format(left, right))
if utils.must_ignore([left, right], ignore, debug=self.debug): if must_ignore([left, right], ignore, debug=self.debug):
if self.debug: if self.debug:
self.log.dbg('ignoring diff {} and {}'.format(left, right)) self.log.dbg('ignoring diff {} and {}'.format(left, right))
return '' return ''
@@ -55,7 +55,7 @@ class Comparator:
self.log.dbg('compare directory {} with {}'.format(left, right)) self.log.dbg('compare directory {} with {}'.format(left, right))
if not os.path.exists(right): if not os.path.exists(right):
return '' return ''
if utils.must_ignore([left, right], ignore, debug=self.debug): if must_ignore([left, right], ignore, debug=self.debug):
if self.debug: if self.debug:
self.log.dbg('ignoring diff {} and {}'.format(left, right)) self.log.dbg('ignoring diff {} and {}'.format(left, right))
return '' return ''
@@ -68,15 +68,15 @@ class Comparator:
# handle files only in deployed dir # handle files only in deployed dir
for i in comp.left_only: for i in comp.left_only:
if utils.must_ignore([os.path.join(left, i)], if must_ignore([os.path.join(left, i)],
ignore, debug=self.debug): ignore, debug=self.debug):
continue continue
ret.append('=> \"{}\" does not exist on local\n'.format(i)) ret.append('=> \"{}\" does not exist on local\n'.format(i))
# handle files only in dotpath dir # handle files only in dotpath dir
for i in comp.right_only: for i in comp.right_only:
if utils.must_ignore([os.path.join(right, i)], if must_ignore([os.path.join(right, i)],
ignore, debug=self.debug): ignore, debug=self.debug):
continue continue
ret.append('=> \"{}\" does not exist in dotdrop\n'.format(i)) ret.append('=> \"{}\" does not exist in dotdrop\n'.format(i))
@@ -85,8 +85,8 @@ class Comparator:
for i in funny: for i in funny:
lfile = os.path.join(left, i) lfile = os.path.join(left, i)
rfile = os.path.join(right, i) rfile = os.path.join(right, i)
if utils.must_ignore([lfile, rfile], if must_ignore([lfile, rfile],
ignore, debug=self.debug): ignore, debug=self.debug):
continue continue
short = os.path.basename(lfile) short = os.path.basename(lfile)
# file vs dir # file vs dir
@@ -95,12 +95,12 @@ class Comparator:
# content is different # content is different
funny = comp.diff_files funny = comp.diff_files
funny.extend(comp.funny_files) funny.extend(comp.funny_files)
funny = utils.uniq_list(funny) funny = uniq_list(funny)
for i in funny: for i in funny:
lfile = os.path.join(left, i) lfile = os.path.join(left, i)
rfile = os.path.join(right, i) rfile = os.path.join(right, i)
if utils.must_ignore([lfile, rfile], if must_ignore([lfile, rfile],
ignore, debug=self.debug): ignore, debug=self.debug):
continue continue
diff = self._diff(lfile, rfile, header=True) diff = self._diff(lfile, rfile, header=True)
ret.append(diff) ret.append(diff)
@@ -115,9 +115,9 @@ class Comparator:
def _diff(self, left, right, header=False): def _diff(self, left, right, header=False):
"""diff using the unix tool diff""" """diff using the unix tool diff"""
diff = utils.diff(left, right, raw=False, d = diff(left, right, raw=False,
opts=self.diffopts, debug=self.debug) opts=self.diffopts, debug=self.debug)
if header: if header:
lshort = os.path.basename(left) lshort = os.path.basename(left)
diff = '=> diff \"{}\":\n{}'.format(lshort, diff) d = '=> diff \"{}\":\n{}'.format(lshort, diff)
return diff return d

View File

@@ -15,7 +15,8 @@ from dotdrop.templategen import Templategen
from dotdrop.installer import Installer from dotdrop.installer import Installer
from dotdrop.updater import Updater from dotdrop.updater import Updater
from dotdrop.comparator import Comparator from dotdrop.comparator import Comparator
from dotdrop.utils import get_tmpdir, remove, strip_home, run, uniq_list from dotdrop.utils import get_tmpdir, remove, strip_home, \
run, uniq_list, patch_ignores
from dotdrop.linktypes import LinkTypes from dotdrop.linktypes import LinkTypes
from dotdrop.exceptions import YamlException from dotdrop.exceptions import YamlException
@@ -225,6 +226,7 @@ def cmd_compare(o, tmp):
same = False same = False
continue continue
ignores = list(set(o.compare_ignore + dotfile.cmpignore)) ignores = list(set(o.compare_ignore + dotfile.cmpignore))
ignores = patch_ignores(ignores, dotfile.src)
diff = comp.compare(insttmp, dotfile.dst, ignore=ignores) diff = comp.compare(insttmp, dotfile.dst, ignore=ignores)
if tmpsrc: if tmpsrc:
# clean tmp transformed dotfile if any # clean tmp transformed dotfile if any

View File

@@ -12,7 +12,8 @@ import filecmp
# local imports # local imports
from dotdrop.logger import Logger from dotdrop.logger import Logger
from dotdrop.templategen import Templategen from dotdrop.templategen import Templategen
import dotdrop.utils as utils from dotdrop.utils import patch_ignores, remove, get_unique_tmp_name, \
write_to_tmpfile, must_ignore
TILD = '~' TILD = '~'
@@ -76,7 +77,8 @@ class Updater:
"""update dotfile from file pointed by path""" """update dotfile from file pointed by path"""
ret = False ret = False
new_path = None new_path = None
self.ignores = list(set(self.ignore + dotfile.upignore)) ignores = list(set(self.ignore + dotfile.upignore))
self.ignores = patch_ignores(ignores, dotfile.dst)
if self.debug: if self.debug:
self.log.dbg('ignore pattern(s): {}'.format(self.ignores)) self.log.dbg('ignore pattern(s): {}'.format(self.ignores))
@@ -98,7 +100,7 @@ class Updater:
ret = self._handle_file(path, dtpath) ret = self._handle_file(path, dtpath)
# clean temporary files # clean temporary files
if new_path and os.path.exists(new_path): if new_path and os.path.exists(new_path):
utils.remove(new_path) remove(new_path)
return ret return ret
def _apply_trans_w(self, path, dotfile): def _apply_trans_w(self, path, dotfile):
@@ -108,12 +110,12 @@ class Updater:
return path return path
if self.debug: if self.debug:
self.log.dbg('executing write transformation {}'.format(trans)) self.log.dbg('executing write transformation {}'.format(trans))
tmp = utils.get_unique_tmp_name() tmp = get_unique_tmp_name()
if not trans.transform(path, tmp): if not trans.transform(path, tmp):
msg = 'transformation \"{}\" failed for {}' msg = 'transformation \"{}\" failed for {}'
self.log.err(msg.format(trans.key, dotfile.key)) self.log.err(msg.format(trans.key, dotfile.key))
if os.path.exists(tmp): if os.path.exists(tmp):
utils.remove(tmp) remove(tmp)
return None return None
return tmp return tmp
@@ -128,7 +130,7 @@ class Updater:
def _show_patch(self, fpath, tpath): def _show_patch(self, fpath, tpath):
"""provide a way to manually patch the template""" """provide a way to manually patch the template"""
content = self._resolve_template(tpath) content = self._resolve_template(tpath)
tmp = utils.write_to_tmpfile(content) tmp = write_to_tmpfile(content)
cmds = ['diff', '-u', tmp, fpath, '|', 'patch', tpath] cmds = ['diff', '-u', tmp, fpath, '|', 'patch', tpath]
self.log.warn('try patching with: \"{}\"'.format(' '.join(cmds))) self.log.warn('try patching with: \"{}\"'.format(' '.join(cmds)))
return False return False
@@ -231,7 +233,7 @@ class Updater:
self.log.dbg('rm -r {}'.format(old)) self.log.dbg('rm -r {}'.format(old))
if not self._confirm_rm_r(old): if not self._confirm_rm_r(old):
continue continue
utils.remove(old) remove(old)
self.log.sub('\"{}\" dir removed'.format(old)) self.log.sub('\"{}\" dir removed'.format(old))
# handle files diff # handle files diff
@@ -283,7 +285,7 @@ class Updater:
continue continue
if self.debug: if self.debug:
self.log.dbg('rm {}'.format(new)) self.log.dbg('rm {}'.format(new))
utils.remove(new) remove(new)
self.log.sub('\"{}\" removed'.format(new)) self.log.sub('\"{}\" removed'.format(new))
# Recursively decent into common subdirectories. # Recursively decent into common subdirectories.
@@ -308,7 +310,7 @@ class Updater:
return True return True
def _ignore(self, paths): def _ignore(self, paths):
if utils.must_ignore(paths, self.ignores, debug=self.debug): if must_ignore(paths, self.ignores, debug=self.debug):
if self.debug: if self.debug:
self.log.dbg('ignoring update for {}'.format(paths)) self.log.dbg('ignoring update for {}'.format(paths))
return True return True

View File

@@ -17,6 +17,7 @@ from shutil import rmtree
from dotdrop.logger import Logger from dotdrop.logger import Logger
LOG = Logger() LOG = Logger()
STAR = '*'
def run(cmd, raw=True, debug=False, checkerr=False): def run(cmd, raw=True, debug=False, checkerr=False):
@@ -139,3 +140,21 @@ def uniq_list(a_list):
if a not in new: if a not in new:
new.append(a) new.append(a)
return new return new
def patch_ignores(ignores, prefix):
"""allow relative ignore pattern"""
new = []
for ignore in ignores:
if STAR in ignore:
# is glob
new.append(ignore)
continue
if os.path.isabs(ignore):
# is absolute
new.append(ignore)
continue
# patch upignore
path = os.path.join(prefix, ignore)
new.append(path)
return new

View File

@@ -0,0 +1,159 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2019, deadc0de6
#
# test compare ignore 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 "\e[96m\e[1m==> RUNNING $(basename $BASH_SOURCE) <==\e[0m"
################################################################
# this is the test
################################################################
# dotdrop directory
basedir=`mktemp -d --suffix='-dotdrop-tests'`
echo "[+] dotdrop dir: ${basedir}"
echo "[+] dotpath dir: ${basedir}/dotfiles"
# the dotfile to be imported
tmpd=`mktemp -d --suffix='-dotdrop-tests'`
# some files
mkdir -p ${tmpd}/{program,config}
touch ${tmpd}/program/a
touch ${tmpd}/config/a
mkdir ${tmpd}/vscode
touch ${tmpd}/vscode/extensions.txt
touch ${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
echo "[+] add files"
touch ${tmpd}/program/b
touch ${tmpd}/config/b
# expects diff
echo "[+] comparing normal - 2 diffs"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg} --verbose
[ "$?" = "0" ] && exit 1
set -e
# expects one diff
patt="${tmpd}/config/b"
echo "[+] comparing with ignore (pattern: ${patt}) - 1 diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg} --verbose --ignore=${patt}
[ "$?" = "0" ] && exit 1
set -e
# expects no diff
patt="*b"
echo "[+] comparing with ignore (pattern: ${patt}) - 0 diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg} --verbose --ignore=${patt}
[ "$?" != "0" ] && exit 1
set -e
# expects one diff
patt="*/config/*b"
echo "[+] comparing with ignore (pattern: ${patt}) - 1 diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg} --verbose --ignore=${patt}
[ "$?" = "0" ] && exit 1
set -e
#cat ${cfg}
# adding ignore in dotfile
cfg2="${basedir}/config2.yaml"
sed '/d_config:/a \ \ \ \ cmpignore:\n\ \ \ \ - "config/b"' ${cfg} > ${cfg2}
#cat ${cfg2}
# expects one diff
echo "[+] comparing with ignore in dotfile - 1 diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg2} --verbose
[ "$?" = "0" ] && exit 1
set -e
# adding ignore in dotfile
cfg2="${basedir}/config2.yaml"
sed '/d_config:/a \ \ \ \ cmpignore:\n\ \ \ \ - "b"' ${cfg} > ${cfg2}
sed -i '/d_program:/a \ \ \ \ cmpignore:\n\ \ \ \ - "b"' ${cfg2}
#cat ${cfg2}
# expects no diff
patt="*b"
echo "[+] comparing with ignore in dotfile - 0 diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg2} --verbose
[ "$?" != "0" ] && exit 1
set -e
# update files
echo touched > ${tmpd}/vscode/extensions.txt
echo touched > ${tmpd}/vscode/keybindings.json
# expect two diffs
set +e
cd ${ddpath} | ${bin} compare -c ${cfg} --verbose -C ${tmpd}/vscode
[ "$?" = "0" ] && exit 1
set -e
# expects no diff
sed '/d_vscode:/a \ \ \ \ cmpignore:\n\ \ \ \ - "extensions.txt"\n\ \ \ \ - "keybindings.json"' ${cfg} > ${cfg2}
set +e
cd ${ddpath} | ${bin} compare -c ${cfg2} --verbose -C ${tmpd}/vscode
[ "$?" != "0" ] && exit 1
set -e
## CLEANING
rm -rf ${basedir} ${tmpd}
echo "OK"
exit 0

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2019, deadc0de6
#
# test ignore update relative pattern
# 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
################################################################
# dotdrop directory
tmps=`mktemp -d --suffix='-dotdrop-tests'`
dt="${tmps}/dotfiles"
mkdir -p ${dt}
mkdir -p ${dt}/a/{b,c}
echo 'a' > ${dt}/a/b/abfile
echo 'a' > ${dt}/a/c/acfile
# fs dotfiles
tmpd=`mktemp -d --suffix='-dotdrop-tests'`
cp -r ${dt}/a ${tmpd}/
# create the config file
cfg="${tmps}/config.yaml"
cat > ${cfg} << _EOF
config:
backup: false
create: true
dotpath: dotfiles
dotfiles:
f_abc:
dst: ${tmpd}/a
src: a
upignore:
- "cfile"
- "newfile"
- "newdir"
profiles:
p1:
dotfiles:
- f_abc
_EOF
#cat ${cfg}
#tree ${dt}
# edit/add files
echo "[+] edit/add files"
touch ${tmpd}/a/newfile
echo 'b' > ${tmpd}/a/c/acfile
mkdir -p ${tmpd}/a/newdir/b
touch ${tmpd}/a/newdir/b/c
#tree ${tmpd}/a
# update
echo "[+] update"
cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=p1 --key f_abc
#tree ${dt}
# check files haven't been updated
grep 'b' ${dt}/a/c/acfile >/dev/null
[ -e ${dt}/a/newfile ] && exit 1
## CLEANING
rm -rf ${tmps} ${tmpd}
echo "OK"
exit 0