mirror of
https://github.com/deadc0de6/dotdrop.git
synced 2026-02-11 03:14:15 +00:00
handle symlink of templates through working directory
This commit is contained in:
@@ -513,9 +513,10 @@ the following entries:
|
|||||||
* `longkey`: use long keys for dotfiles when importing (default *false*)
|
* `longkey`: use long keys for dotfiles when importing (default *false*)
|
||||||
* `keepdot`: preserve leading dot when importing hidden file in the `dotpath` (default *false*)
|
* `keepdot`: preserve leading dot when importing hidden file in the `dotpath` (default *false*)
|
||||||
* `link_by_default`: when importing a dotfile set `link` to that value per default (default *false*)
|
* `link_by_default`: when importing a dotfile set `link` to that value per default (default *false*)
|
||||||
|
* `workdir`: directory where templates are installed before being symlink when using `link` (default *~/.config/dotdrop*)
|
||||||
|
|
||||||
* **dotfiles** entry: a list of dotfiles
|
* **dotfiles** entry: a list of dotfiles
|
||||||
* When `link` is true, dotdrop will create a symlink instead of copying. Template generation (as in [template](#template)) is not supported when `link` is true (default *false*).
|
* When `link` is true, dotdrop will create a symlink instead of copying (default *false*).
|
||||||
* `actions` contains a list of action keys that need to be defined in the **actions** entry below.
|
* `actions` contains a list of action keys that need to be defined in the **actions** entry below.
|
||||||
* `trans` contains a list of transformation keys that need to be defined in the **trans** entry below.
|
* `trans` contains a list of transformation keys that need to be defined in the **trans** entry below.
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class Cfg:
|
|||||||
key_long = 'longkey'
|
key_long = 'longkey'
|
||||||
key_keepdot = 'keepdot'
|
key_keepdot = 'keepdot'
|
||||||
key_deflink = 'link_by_default'
|
key_deflink = 'link_by_default'
|
||||||
|
key_workdir = 'workdir'
|
||||||
|
|
||||||
# actions keys
|
# actions keys
|
||||||
key_actions = 'actions'
|
key_actions = 'actions'
|
||||||
@@ -62,6 +63,7 @@ class Cfg:
|
|||||||
default_longkey = False
|
default_longkey = False
|
||||||
default_keepdot = False
|
default_keepdot = False
|
||||||
default_link_by_default = False
|
default_link_by_default = False
|
||||||
|
default_workdir = '~/.config/dotdrop'
|
||||||
|
|
||||||
def __init__(self, cfgpath):
|
def __init__(self, cfgpath):
|
||||||
if not os.path.exists(cfgpath):
|
if not os.path.exists(cfgpath):
|
||||||
@@ -295,6 +297,8 @@ class Cfg:
|
|||||||
self.lnk_settings[self.key_keepdot] = self.default_keepdot
|
self.lnk_settings[self.key_keepdot] = self.default_keepdot
|
||||||
if self.key_deflink not in self.lnk_settings:
|
if self.key_deflink not in self.lnk_settings:
|
||||||
self.lnk_settings[self.key_deflink] = self.default_link_by_default
|
self.lnk_settings[self.key_deflink] = self.default_link_by_default
|
||||||
|
if self.key_workdir not in self.lnk_settings:
|
||||||
|
self.lnk_settings[self.key_workdir] = self.default_workdir
|
||||||
|
|
||||||
def abs_dotpath(self, path):
|
def abs_dotpath(self, path):
|
||||||
"""transform path to an absolute path based on config path"""
|
"""transform path to an absolute path based on config path"""
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ def install(opts, conf):
|
|||||||
variables=opts['variables'], debug=opts['debug'])
|
variables=opts['variables'], debug=opts['debug'])
|
||||||
inst = Installer(create=opts['create'], backup=opts['backup'],
|
inst = Installer(create=opts['create'], backup=opts['backup'],
|
||||||
dry=opts['dry'], safe=opts['safe'], base=opts['dotpath'],
|
dry=opts['dry'], safe=opts['safe'], base=opts['dotpath'],
|
||||||
diff=opts['installdiff'], debug=opts['debug'])
|
workdir=opts['workdir'], diff=opts['installdiff'],
|
||||||
|
debug=opts['debug'])
|
||||||
installed = []
|
installed = []
|
||||||
for dotfile in dotfiles:
|
for dotfile in dotfiles:
|
||||||
if dotfile.actions and Cfg.key_actions_pre in dotfile.actions:
|
if dotfile.actions and Cfg.key_actions_pre in dotfile.actions:
|
||||||
@@ -99,7 +100,7 @@ def install(opts, conf):
|
|||||||
if opts['debug']:
|
if opts['debug']:
|
||||||
LOG.dbg('installing {}'.format(dotfile))
|
LOG.dbg('installing {}'.format(dotfile))
|
||||||
if hasattr(dotfile, 'link') and dotfile.link:
|
if hasattr(dotfile, 'link') and dotfile.link:
|
||||||
r = inst.link(dotfile.src, dotfile.dst)
|
r = inst.link(t, dotfile.src, dotfile.dst)
|
||||||
else:
|
else:
|
||||||
src = dotfile.src
|
src = dotfile.src
|
||||||
tmp = None
|
tmp = None
|
||||||
@@ -189,7 +190,7 @@ def compare(opts, conf, tmp, focus=None, ignore=[]):
|
|||||||
variables=opts['variables'], debug=opts['debug'])
|
variables=opts['variables'], debug=opts['debug'])
|
||||||
inst = Installer(create=opts['create'], backup=opts['backup'],
|
inst = Installer(create=opts['create'], backup=opts['backup'],
|
||||||
dry=opts['dry'], base=opts['dotpath'],
|
dry=opts['dry'], base=opts['dotpath'],
|
||||||
debug=opts['debug'])
|
workdir=opts['workdir'], debug=opts['debug'])
|
||||||
comp = Comparator(diffopts=opts['dopts'], debug=opts['debug'],
|
comp = Comparator(diffopts=opts['dopts'], debug=opts['debug'],
|
||||||
ignore=ignore)
|
ignore=ignore)
|
||||||
|
|
||||||
|
|||||||
@@ -17,28 +17,25 @@ import dotdrop.utils as utils
|
|||||||
class Installer:
|
class Installer:
|
||||||
|
|
||||||
BACKUP_SUFFIX = '.dotdropbak'
|
BACKUP_SUFFIX = '.dotdropbak'
|
||||||
# TODO get this from the config file with a default
|
|
||||||
DOTDROP_WORK = '{}/.config/dotdrop'.format(os.path.expanduser('~'))
|
|
||||||
|
|
||||||
def __init__(self, base='.', create=True, backup=True,
|
def __init__(self, base='.', create=True, backup=True,
|
||||||
dry=False, safe=False, debug=False, diff=True):
|
dry=False, safe=False, workdir='~/.config/dotdrop',
|
||||||
|
debug=False, diff=True):
|
||||||
self.create = create
|
self.create = create
|
||||||
self.backup = backup
|
self.backup = backup
|
||||||
self.dry = dry
|
self.dry = dry
|
||||||
self.safe = safe
|
self.safe = safe
|
||||||
|
self.workdir = os.path.expanduser(workdir)
|
||||||
self.base = base
|
self.base = base
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.diff = diff
|
self.diff = diff
|
||||||
self.comparing = False
|
self.comparing = False
|
||||||
self.log = Logger()
|
self.log = Logger()
|
||||||
|
|
||||||
def _dotdrop_work(self):
|
|
||||||
os.makedirs(self.DOTDROP_WORK, exist_ok=True)
|
|
||||||
|
|
||||||
def install(self, templater, src, dst):
|
def install(self, templater, src, dst):
|
||||||
"""install the src to dst using a template"""
|
"""install the src to dst using a template"""
|
||||||
src = os.path.join(self.base, os.path.expanduser(src))
|
src = os.path.join(self.base, os.path.expanduser(src))
|
||||||
dst = os.path.join(self.base, os.path.expanduser(dst))
|
dst = os.path.expanduser(dst)
|
||||||
if utils.samefile(src, dst):
|
if utils.samefile(src, dst):
|
||||||
# symlink loop
|
# symlink loop
|
||||||
self.log.err('dotfile points to itself: {}'.format(dst))
|
self.log.err('dotfile points to itself: {}'.format(dst))
|
||||||
@@ -49,22 +46,19 @@ class Installer:
|
|||||||
return self._handle_dir(templater, src, dst)
|
return self._handle_dir(templater, src, dst)
|
||||||
return self._handle_file(templater, src, dst)
|
return self._handle_file(templater, src, dst)
|
||||||
|
|
||||||
def link(self, src, dst):
|
def link(self, templater, src, dst):
|
||||||
"""set src as the link target of dst"""
|
"""set src as the link target of dst"""
|
||||||
src = os.path.join(self.base, os.path.expanduser(src))
|
src = os.path.join(self.base, os.path.expanduser(src))
|
||||||
dst = os.path.join(self.base, os.path.expanduser(dst))
|
dst = os.path.expanduser(dst)
|
||||||
|
|
||||||
if Templategen.is_template(src):
|
if Templategen.is_template(src):
|
||||||
# TODO
|
if self.debug:
|
||||||
# first make sure the template is generated in the working dir
|
self.log.dbg('dotfile is a template')
|
||||||
|
self.log.dbg('install to {} and symlink'.format(self.workdir))
|
||||||
# if it's not generate it
|
tmp = self._pivot_path(dst, self.workdir, striphome=True)
|
||||||
|
if not self.install(templater, src, tmp):
|
||||||
# and then symlink it as any other file
|
return []
|
||||||
# by udating src and dst
|
src = tmp
|
||||||
return []
|
|
||||||
|
|
||||||
# is not a template
|
|
||||||
return self._link(src, dst)
|
return self._link(src, dst)
|
||||||
|
|
||||||
def _link(self, src, dst):
|
def _link(self, src, dst):
|
||||||
@@ -95,7 +89,7 @@ class Installer:
|
|||||||
self.log.err('creating directory for \"{}\"'.format(dst))
|
self.log.err('creating directory for \"{}\"'.format(dst))
|
||||||
return []
|
return []
|
||||||
os.symlink(src, dst)
|
os.symlink(src, dst)
|
||||||
self.log.sub('linked {} to {}'.format(dst, src))
|
self.log.sub('linked \"{}\" to \"{}\"'.format(dst, src))
|
||||||
return [(src, dst)]
|
return [(src, dst)]
|
||||||
|
|
||||||
def _handle_file(self, templater, src, dst):
|
def _handle_file(self, templater, src, dst):
|
||||||
@@ -206,19 +200,24 @@ class Installer:
|
|||||||
self.log.log('backup {} to {}'.format(path, dst))
|
self.log.log('backup {} to {}'.format(path, dst))
|
||||||
os.rename(path, dst)
|
os.rename(path, dst)
|
||||||
|
|
||||||
|
def _pivot_path(self, path, newdir, striphome=False):
|
||||||
|
"""change path to be under newdir"""
|
||||||
|
if striphome:
|
||||||
|
home = os.path.expanduser('~')
|
||||||
|
path = path.lstrip(home)
|
||||||
|
sub = path.lstrip(os.sep)
|
||||||
|
return os.path.join(newdir, sub)
|
||||||
|
|
||||||
def _install_to_temp(self, templater, src, dst, tmpdir):
|
def _install_to_temp(self, templater, src, dst, tmpdir):
|
||||||
"""install a dotfile to a tempdir for comparing"""
|
"""install a dotfile to a tempdir"""
|
||||||
sub = dst
|
tmpdst = self._pivot_path(dst, tmpdir)
|
||||||
if dst[0] == os.sep:
|
|
||||||
sub = dst[1:]
|
|
||||||
tmpdst = os.path.join(tmpdir, sub)
|
|
||||||
return self.install(templater, src, tmpdst), tmpdst
|
return self.install(templater, src, tmpdst), tmpdst
|
||||||
|
|
||||||
def install_to_temp(self, templater, tmpdir, src, dst):
|
def install_to_temp(self, templater, tmpdir, src, dst):
|
||||||
"""compare a temporary generated dotfile with the local one"""
|
"""install a dotfile to a tempdir"""
|
||||||
ret = False
|
ret = False
|
||||||
tmpdst = ''
|
tmpdst = ''
|
||||||
# saved some flags while comparing
|
# save some flags while comparing
|
||||||
self.comparing = True
|
self.comparing = True
|
||||||
drysaved = self.dry
|
drysaved = self.dry
|
||||||
self.dry = False
|
self.dry = False
|
||||||
|
|||||||
96
tests-ng/link-templates.sh
Executable file
96
tests-ng/link-templates.sh
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# author: deadc0de6 (https://github.com/deadc0de6)
|
||||||
|
# Copyright (c) 2017, deadc0de6
|
||||||
|
#
|
||||||
|
# test link of templates
|
||||||
|
# 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 "RUNNING $(basename $BASH_SOURCE)"
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# this is the test
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# the dotfile source
|
||||||
|
tmps=`mktemp -d`
|
||||||
|
mkdir -p ${tmps}/dotfiles
|
||||||
|
echo "dotfiles source (dotpath): ${tmps}"
|
||||||
|
# the dotfile destination
|
||||||
|
tmpd=`mktemp -d`
|
||||||
|
echo "dotfiles destination: ${tmpd}"
|
||||||
|
# the workdir
|
||||||
|
tmpw=`mktemp -d`
|
||||||
|
echo "workdir: ${tmpw}"
|
||||||
|
|
||||||
|
|
||||||
|
# create the config file
|
||||||
|
cfg="${tmps}/config.yaml"
|
||||||
|
|
||||||
|
cat > ${cfg} << _EOF
|
||||||
|
config:
|
||||||
|
backup: true
|
||||||
|
create: true
|
||||||
|
dotpath: dotfiles
|
||||||
|
workdir: ${tmpw}
|
||||||
|
dotfiles:
|
||||||
|
f_abc:
|
||||||
|
dst: ${tmpd}/abc
|
||||||
|
src: abc
|
||||||
|
link: true
|
||||||
|
profiles:
|
||||||
|
p1:
|
||||||
|
dotfiles:
|
||||||
|
- f_abc
|
||||||
|
_EOF
|
||||||
|
cat ${cfg}
|
||||||
|
|
||||||
|
# create the dotfile
|
||||||
|
echo "{{@@ profile @@}}" > ${tmps}/dotfiles/abc
|
||||||
|
echo "blabla" >> ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
# install
|
||||||
|
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -b -V
|
||||||
|
|
||||||
|
# checks
|
||||||
|
[ ! -e ${tmpd}/abc ] && echo "[ERROR] dotfile not installed" && exit 1
|
||||||
|
[ ! -h ${tmpd}/abc ] && echo "[ERROR] dotfile is not a symlink" && exit 1
|
||||||
|
|
||||||
|
## CLEANING
|
||||||
|
rm -rf ${tmps} ${tmpd} ${tmpw}
|
||||||
|
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
@@ -89,7 +89,7 @@ grep '^this is some test' ${tmpd}/abc >/dev/null
|
|||||||
grep '^12' ${tmpd}/abc >/dev/null
|
grep '^12' ${tmpd}/abc >/dev/null
|
||||||
grep '^another test' ${tmpd}/abc >/dev/null
|
grep '^another test' ${tmpd}/abc >/dev/null
|
||||||
|
|
||||||
cat ${tmpd}/abc
|
#cat ${tmpd}/abc
|
||||||
|
|
||||||
## CLEANING
|
## CLEANING
|
||||||
rm -rf ${tmps} ${tmpd}
|
rm -rf ${tmps} ${tmpd}
|
||||||
|
|||||||
@@ -98,11 +98,13 @@ def create_fake_config(directory, configname='config.yaml',
|
|||||||
dotpath='dotfiles', backup=True, create=True):
|
dotpath='dotfiles', backup=True, create=True):
|
||||||
'''Create a fake config file'''
|
'''Create a fake config file'''
|
||||||
path = os.path.join(directory, configname)
|
path = os.path.join(directory, configname)
|
||||||
|
workdir = os.path.join(directory, 'workdir')
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
f.write('config:\n')
|
f.write('config:\n')
|
||||||
f.write(' backup: {}\n'.format(str(backup)))
|
f.write(' backup: {}\n'.format(str(backup)))
|
||||||
f.write(' create: {}\n'.format(str(create)))
|
f.write(' create: {}\n'.format(str(create)))
|
||||||
f.write(' dotpath: {}\n'.format(dotpath))
|
f.write(' dotpath: {}\n'.format(dotpath))
|
||||||
|
f.write(' workdir: {}\n'.format(workdir))
|
||||||
f.write('dotfiles:\n')
|
f.write('dotfiles:\n')
|
||||||
f.write('profiles:\n')
|
f.write('profiles:\n')
|
||||||
f.write('actions:\n')
|
f.write('actions:\n')
|
||||||
|
|||||||
Reference in New Issue
Block a user