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:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
125
tests-ng/diff-cmd.sh
Executable 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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user