1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-04 17:24:46 +00:00

adding ability to provide diff command for #203

This commit is contained in:
deadc0de6
2020-01-22 17:41:48 +01:00
parent 0da393cef2
commit d4375c5d04
8 changed files with 153 additions and 20 deletions

View File

@@ -15,12 +15,12 @@ from dotdrop.utils import must_ignore, uniq_list, diff
class Comparator: class Comparator:
def __init__(self, diffopts='', debug=False): def __init__(self, diff_cmd='', debug=False):
"""constructor """constructor
@diffopts: switches to pass to unix diff @diff_cmd: diff command to use
@debug: enable debug @debug: enable debug
""" """
self.diffopts = diffopts self.diff_cmd = diff_cmd
self.debug = debug self.debug = debug
self.log = Logger() self.log = Logger()
@@ -122,9 +122,9 @@ class Comparator:
return ''.join(ret) return ''.join(ret)
def _diff(self, left, right, header=False): def _diff(self, left, right, header=False):
"""diff using the unix tool diff""" """diff two files"""
out = diff(modified=left, original=right, raw=False, out = diff(modified=left, original=right, raw=False,
opts=self.diffopts, debug=self.debug) diff_cmd=self.diff_cmd, debug=self.debug)
if header: if header:
lshort = os.path.basename(left) lshort = os.path.basename(left)
out = '=> diff \"{}\":\n{}'.format(lshort, out) out = '=> diff \"{}\":\n{}'.format(lshort, out)

View File

@@ -96,7 +96,8 @@ def cmd_install(o):
diff=o.install_diff, debug=o.debug, diff=o.install_diff, debug=o.debug,
totemp=tmpdir, totemp=tmpdir,
showdiff=o.install_showdiff, showdiff=o.install_showdiff,
backup_suffix=o.install_backup_suffix) backup_suffix=o.install_backup_suffix,
diff_cmd=o.diff_command)
installed = 0 installed = 0
tvars = t.add_tmp_vars() tvars = t.add_tmp_vars()
@@ -211,8 +212,9 @@ def cmd_compare(o, tmp):
inst = Installer(create=o.create, backup=o.backup, inst = Installer(create=o.create, backup=o.backup,
dry=o.dry, base=o.dotpath, dry=o.dry, base=o.dotpath,
workdir=o.workdir, debug=o.debug, workdir=o.workdir, debug=o.debug,
backup_suffix=o.install_backup_suffix) backup_suffix=o.install_backup_suffix,
comp = Comparator(diffopts=o.compare_dopts, debug=o.debug) diff_cmd=o.diff_command)
comp = Comparator(diff_cmd=o.diff_command, debug=o.debug)
for dotfile in selected: for dotfile in selected:
if o.debug: if o.debug:
@@ -362,7 +364,7 @@ def cmd_importer(o):
if os.path.exists(srcf): if os.path.exists(srcf):
overwrite = True overwrite = True
if o.safe: if o.safe:
c = Comparator(debug=o.debug) c = Comparator(debug=o.debug, diff_cmd=o.diff_command)
diff = c.compare(srcf, dst) diff = c.compare(srcf, dst)
if diff != '': if diff != '':
# files are different, dunno what to do # files are different, dunno what to do

View File

@@ -19,7 +19,7 @@ class Installer:
def __init__(self, base='.', create=True, backup=True, def __init__(self, base='.', create=True, backup=True,
dry=False, safe=False, workdir='~/.config/dotdrop', dry=False, safe=False, workdir='~/.config/dotdrop',
debug=False, diff=True, totemp=None, showdiff=False, debug=False, diff=True, totemp=None, showdiff=False,
backup_suffix='.dotdropbak'): backup_suffix='.dotdropbak', diff_cmd=''):
"""constructor """constructor
@base: directory path where to search for templates @base: directory path where to search for templates
@create: create directory hierarchy if missing when installing @create: create directory hierarchy if missing when installing
@@ -32,6 +32,7 @@ class Installer:
@totemp: deploy to this path instead of dotfile dst if not None @totemp: deploy to this path instead of dotfile dst if not None
@showdiff: show the diff before overwriting (or asking for) @showdiff: show the diff before overwriting (or asking for)
@backup_suffix: suffix for dotfile backup file @backup_suffix: suffix for dotfile backup file
@diff_cmd: diff command to use
""" """
self.create = create self.create = create
self.backup = backup self.backup = backup
@@ -44,6 +45,7 @@ class Installer:
self.totemp = totemp self.totemp = totemp
self.showdiff = showdiff self.showdiff = showdiff
self.backup_suffix = backup_suffix self.backup_suffix = backup_suffix
self.diff_cmd = diff_cmd
self.comparing = False self.comparing = False
self.action_executed = False self.action_executed = False
self.log = Logger() self.log = Logger()
@@ -437,7 +439,8 @@ class Installer:
if content: if content:
tmp = utils.write_to_tmpfile(content) tmp = utils.write_to_tmpfile(content)
src = tmp src = tmp
diff = utils.diff(modified=src, original=dst, raw=False) diff = utils.diff(modified=src, original=dst, raw=False,
diff_cmd=self.diff_cmd)
if tmp: if tmp:
utils.remove(tmp, quiet=True) utils.remove(tmp, quiet=True)

View File

@@ -55,7 +55,7 @@ Usage:
dotdrop import [-Vbdf] [-c <path>] [-p <profile>] dotdrop import [-Vbdf] [-c <path>] [-p <profile>]
[-l <link>] <path>... [-l <link>] <path>...
dotdrop compare [-Vb] [-c <path>] [-p <profile>] dotdrop compare [-Vb] [-c <path>] [-p <profile>]
[-o <opts>] [-C <file>...] [-i <pattern>...] [-C <file>...] [-i <pattern>...]
dotdrop update [-VbfdkP] [-c <path>] [-p <profile>] dotdrop update [-VbfdkP] [-c <path>] [-p <profile>]
[-i <pattern>...] [<path>...] [-i <pattern>...] [<path>...]
dotdrop remove [-Vbfdk] [-c <path>] [-p <profile>] [<path>...] dotdrop remove [-Vbfdk] [-c <path>] [-p <profile>] [<path>...]
@@ -70,7 +70,6 @@ Options:
-c --cfg=<path> Path to the config. -c --cfg=<path> Path to the config.
-C --file=<path> Path of dotfile to compare. -C --file=<path> Path of dotfile to compare.
-i --ignore=<pattern> Pattern to ignore. -i --ignore=<pattern> Pattern to ignore.
-o --dopts=<opts> Diff options [default: ].
-l --link=<link> "link_on_import" (nolink|link|link_children). -l --link=<link> "link_on_import" (nolink|link|link_children).
-n --nodiff Do not diff when installing. -n --nodiff Do not diff when installing.
-t --temp Install to a temporary directory for review. -t --temp Install to a temporary directory for review.
@@ -231,7 +230,6 @@ class Options(AttrMonitor):
if a.kind == Action.post] if a.kind == Action.post]
self.install_ignore = self.instignore self.install_ignore = self.instignore
# "compare" specifics # "compare" specifics
self.compare_dopts = self.args['--dopts']
self.compare_focus = self.args['--file'] self.compare_focus = self.args['--file']
self.compare_ignore = self.args['--ignore'] self.compare_ignore = self.args['--ignore']
self.compare_ignore.extend(self.cmpignore) self.compare_ignore.extend(self.cmpignore)

View File

@@ -33,6 +33,7 @@ class Settings(DictParser):
key_minversion = 'minversion' key_minversion = 'minversion'
key_func_file = 'func_file' key_func_file = 'func_file'
key_filter_file = 'filter_file' key_filter_file = 'filter_file'
key_diff_command = 'diff_command'
# import keys # import keys
key_import_actions = 'import_actions' key_import_actions = 'import_actions'
@@ -47,7 +48,8 @@ class Settings(DictParser):
link_on_import=LinkTypes.NOLINK, longkey=False, link_on_import=LinkTypes.NOLINK, longkey=False,
upignore=[], cmpignore=[], instignore=[], upignore=[], cmpignore=[], instignore=[],
workdir='~/.config/dotdrop', showdiff=False, workdir='~/.config/dotdrop', showdiff=False,
minversion=None, func_file=[], filter_file=[]): minversion=None, func_file=[], filter_file=[],
diff_command='diff -r {0} {1}'):
self.backup = backup self.backup = backup
self.banner = banner self.banner = banner
self.create = create self.create = create
@@ -69,6 +71,7 @@ class Settings(DictParser):
self.minversion = minversion self.minversion = minversion
self.func_file = func_file self.func_file = func_file
self.filter_file = filter_file self.filter_file = filter_file
self.diff_command = diff_command
def _serialize_seq(self, name, dic): def _serialize_seq(self, name, dic):
"""serialize attribute 'name' into 'dic'""" """serialize attribute 'name' into 'dic'"""
@@ -77,7 +80,6 @@ class Settings(DictParser):
def serialize(self): def serialize(self):
"""Return key-value pair representation of the settings""" """Return key-value pair representation of the settings"""
# Tedious, but less error-prone than introspection
dic = { dic = {
self.key_backup: self.backup, self.key_backup: self.backup,
self.key_banner: self.banner, self.key_banner: self.banner,
@@ -91,6 +93,7 @@ class Settings(DictParser):
self.key_showdiff: self.showdiff, self.key_showdiff: self.showdiff,
self.key_workdir: self.workdir, self.key_workdir: self.workdir,
self.key_minversion: self.minversion, self.key_minversion: self.minversion,
self.key_diff_command: self.diff_command,
} }
self._serialize_seq(self.key_default_actions, dic) self._serialize_seq(self.key_default_actions, dic)
self._serialize_seq(self.key_import_actions, dic) self._serialize_seq(self.key_import_actions, dic)

View File

@@ -70,9 +70,12 @@ def shell(cmd, debug=False):
return ret == 0, out return ret == 0, out
def diff(original, modified, raw=True, opts='', debug=False): def diff(original, modified, raw=True,
"""call unix diff to compare two files""" diff_cmd='diff -r {0} {1}', debug=False):
cmd = 'diff -r {} \"{}\" \"{}\"'.format(opts, original, modified) """compare two files"""
if not diff_cmd:
diff_cmd = 'diff -r {0} {1}'
cmd = diff_cmd.format(original, modified)
_, out = run(shlex.split(cmd), raw=raw, debug=debug) _, out = run(shlex.split(cmd), raw=raw, debug=debug)
return out return out

125
tests-ng/diff-cmd.sh Executable file
View File

@@ -0,0 +1,125 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2017, deadc0de6
#
# test diff cmd
# 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
echo "original" > ${tmpd}/singlefile
# create the config file
cfg="${basedir}/config.yaml"
cat > ${cfg} << _EOF
config:
backup: true
create: true
dotpath: dotfiles
dotfiles:
profiles:
_EOF
# import
echo "[+] import"
cd ${ddpath} | ${bin} import -c ${cfg} ${tmpd}/singlefile
# modify the file
echo "modified" > ${tmpd}/singlefile
# normal diff
echo "[+] comparing with normal diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg} 2>&1 | grep -v '=>' > ${tmpd}/normal
diff -r ${tmpd}/singlefile ${basedir}/dotfiles/${tmpd}/singlefile > ${tmpd}/real
set -e
# verify
#cat ${tmpd}/normal
#cat ${tmpd}/real
diff ${tmpd}/normal ${tmpd}/real || exit 1
# adding unified diff
cfg2="${basedir}/config2.yaml"
sed '/dotpath: dotfiles/a \ \ diff_command: "diff -u {0} {1}"' ${cfg} > ${cfg2}
#cat ${cfg2}
# unified diff
echo "[+] comparing with unified diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg2} 2>&1 | grep -v '=>' | grep -v '^+++\|^---' > ${tmpd}/unified
diff -u ${tmpd}/singlefile ${basedir}/dotfiles/${tmpd}/singlefile | grep -v '^+++\|^---' > ${tmpd}/real
set -e
# verify
#cat ${tmpd}/unified
#cat ${tmpd}/real
diff ${tmpd}/unified ${tmpd}/real || exit 1
# adding fake diff
cfg3="${basedir}/config3.yaml"
sed '/dotpath: dotfiles/a \ \ diff_command: "echo fakediff"' ${cfg} > ${cfg3}
cat ${cfg3}
# fake diff
echo "[+] comparing with fake diff"
set +e
cd ${ddpath} | ${bin} compare -c ${cfg3} 2>&1 | grep -v '=>' > ${tmpd}/fake
set -e
# verify
cat ${tmpd}/fake
grep fakediff ${tmpd}/fake || exit 1
## CLEANING
rm -rf ${basedir} ${tmpd}
echo "OK"
exit 0

View File

@@ -157,7 +157,6 @@ def load_options(confpath, profile):
o.import_link = LinkTypes.NOLINK o.import_link = LinkTypes.NOLINK
o.install_showdiff = True o.install_showdiff = True
o.debug = True o.debug = True
o.compare_dopts = ''
o.variables = {} o.variables = {}
return o return o