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

adding relative symlink for #348

This commit is contained in:
deadc0de6
2022-05-28 23:31:20 +02:00
committed by deadc0de
parent 6a2b77ecf1
commit a547f0f72b
5 changed files with 191 additions and 28 deletions

View File

@@ -97,9 +97,12 @@ class CfgYaml:
lnk_nolink = LinkTypes.NOLINK.name.lower()
lnk_link = LinkTypes.LINK.name.lower()
lnk_children = LinkTypes.LINK_CHILDREN.name.lower()
lnk_absolute = LinkTypes.ABSOLUTE.name.lower()
lnk_relative = LinkTypes.RELATIVE.name.lower()
# checks
allowed_link_val = [lnk_nolink, lnk_link, lnk_children]
allowed_link_val = [lnk_nolink, lnk_link, lnk_children,
lnk_absolute, lnk_relative]
top_entries = [key_dotfiles, key_settings, key_profiles]
def __init__(self, path, profile=None, addprofiles=None,
@@ -297,8 +300,9 @@ class CfgYaml:
newlink = self._template_item(link)
# check link value
if newlink not in self.allowed_link_val:
err = 'bad value: {}'.format(newlink)
err = 'bad link value: {}'.format(newlink)
self._log.err(err)
self._log.err('allowed: {}'.format(self.allowed_link_val))
raise YamlException('config content error: {}'.format(err))
return newlink
@@ -1216,8 +1220,9 @@ class CfgYaml:
return
val = settings[self.key_settings_link_dotfile_default]
if val not in self.allowed_link_val:
err = 'bad value: {}'.format(val)
err = 'bad link value: {}'.format(val)
self._log.err(err)
self._log.err('allowed: {}'.format(self.allowed_link_val))
raise YamlException('config content error: {}'.format(err))
@classmethod

View File

@@ -220,8 +220,11 @@ def _dotfile_install(opts, dotfile, tmpdir=None):
dotfile.src,
ignore=ignores,
)
if hasattr(dotfile, 'link') and dotfile.link == LinkTypes.LINK:
# link
if hasattr(dotfile, 'link') and dotfile.link in (
LinkTypes.LINK, LinkTypes.LINK_CHILDREN,
LinkTypes.RELATIVE, LinkTypes.ABSOLUTE
):
# link|relative|absolute|link_children
ret, err = inst.install(templ, dotfile.src, dotfile.dst,
dotfile.link,
actionexec=pre_actions_exec,
@@ -229,16 +232,6 @@ def _dotfile_install(opts, dotfile, tmpdir=None):
ignore=ignores,
chmod=dotfile.chmod,
force_chmod=opts.install_force_chmod)
elif hasattr(dotfile, 'link') and \
dotfile.link == LinkTypes.LINK_CHILDREN:
# link_children
ret, err = inst.install(templ, dotfile.src, dotfile.dst,
dotfile.link,
actionexec=pre_actions_exec,
is_template=is_template,
chmod=dotfile.chmod,
ignore=ignores,
force_chmod=opts.install_force_chmod)
else:
# nolink
src = dotfile.src

View File

@@ -133,12 +133,18 @@ class Installer:
actionexec=actionexec,
noempty=noempty, ignore=ignore,
is_template=is_template)
elif linktype == LinkTypes.LINK:
elif linktype in (LinkTypes.LINK, LinkTypes.ABSOLUTE):
# symlink
ret, err = self._link(templater, src, dst,
actionexec=actionexec,
is_template=is_template,
ignore=ignore)
ret, err = self._link_absolute(templater, src, dst,
actionexec=actionexec,
is_template=is_template,
ignore=ignore)
elif linktype == LinkTypes.RELATIVE:
# symlink
ret, err = self._link_relative(templater, src, dst,
actionexec=actionexec,
is_template=is_template,
ignore=ignore)
elif linktype == LinkTypes.LINK_CHILDREN:
# symlink direct children
if not isdir:
@@ -246,10 +252,48 @@ class Installer:
# low level accessors for public methods
########################################################
def _link(self, templater, src, dst, actionexec=None,
is_template=True, ignore=None):
def _link_absolute(self, templater, src, dst,
actionexec=None,
is_template=True,
ignore=None):
"""
install link:link
install link:absolute|link
return
- True, None : success
- False, error_msg : error
- False, None : ignored
- False, 'aborted' : user aborted
"""
return self._link_dotfile(templater, src, dst,
actionexec=actionexec,
is_template=is_template,
ignore=ignore,
absolute=True)
def _link_relative(self, templater, src, dst,
actionexec=None,
is_template=True,
ignore=None):
"""
install link:relative
return
- True, None : success
- False, error_msg : error
- False, None : ignored
- False, 'aborted' : user aborted
"""
return self._link_dotfile(templater, src, dst,
actionexec=actionexec,
is_template=is_template,
ignore=ignore,
absolute=False)
def _link_dotfile(self, templater, src, dst, actionexec=None,
is_template=True, ignore=None, absolute=True):
"""
symlink
return
- True, None : success
@@ -270,7 +314,8 @@ class Installer:
if not ret and not os.path.exists(tmp):
return ret, err
src = tmp
ret, err = self._symlink(src, dst, actionexec=actionexec)
ret, err = self._symlink(src, dst, actionexec=actionexec,
absolute=absolute)
return ret, err
def _link_children(self, templater, src, dst,
@@ -354,7 +399,7 @@ class Installer:
# file operations
########################################################
def _symlink(self, src, dst, actionexec=None):
def _symlink(self, src, dst, actionexec=None, absolute=True):
"""
set src as a link target of dst
@@ -415,9 +460,20 @@ class Installer:
return False, err
# create symlink
os.symlink(src, dst)
if not self.comparing:
self.log.sub('linked {} to {}'.format(dst, src))
if absolute:
# absolute symlink pointing to src named dst
os.symlink(src, dst)
if not self.comparing:
self.log.sub('linked {} to {}'.format(dst, src))
else:
# relative symlink
dstrel = dst
if not os.path.isdir(dstrel):
dstrel = os.path.dirname(dstrel)
rel = os.path.relpath(src, dstrel)
os.symlink(rel, dst)
if not self.comparing:
self.log.sub('linked {} to {}'.format(dst, rel))
return True, None
def _copy_file(self, templater, src, dst,

View File

@@ -16,6 +16,8 @@ class LinkTypes(IntEnum):
NOLINK = 0
LINK = 1
LINK_CHILDREN = 2
ABSOLUTE = 3
RELATIVE = 4
@classmethod
def get(cls, key, default=None):

107
tests-ng/symlink-relative.sh Executable file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2022, deadc0de6
#
# test relative symlink
#
# 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"
hash coverage 2>/dev/null && bin="coverage run -a --source=dotdrop -m dotdrop.dotdrop" || true
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
################################################################
# the dotfile source
tmps=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d`
mkdir -p ${tmps}/dotfiles
# the dotfile destination
tmpd=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d`
#echo "dotfile destination: ${tmpd}"
clear_on_exit "${tmps}"
clear_on_exit "${tmpd}"
##################################################
# test symlink directory
##################################################
# create the dotfile
echo "file1" > ${tmps}/dotfiles/abc
# create the config file
cfg="${tmps}/config.yaml"
cat > ${cfg} << _EOF
config:
backup: true
create: true
dotpath: dotfiles
link_dotfile_default: nolink
dotfiles:
d_abc:
dst: ${tmpd}/abc
src: abc
link: relative
d_abc2:
dst: ${tmpd}/abc2
src: abc
link: absolute
profiles:
p1:
dotfiles:
- d_abc
- d_abc2
_EOF
#cat ${cfg}
# install
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
# ensure exists and is link
[ ! -h ${tmpd}/abc ] && echo "not a symlink" && exit 1
[ ! -h ${tmpd}/abc2 ] && echo "not a symlink" && exit 1
ls -l ${tmpd}/abc | grep '..' || exit 1
ls -l ${tmpd}/abc2
grep 'file1' ${tmpd}/abc
grep 'file1' ${tmpd}/abc2
## TODO with templates
echo "TODO with templates"
exit 1
echo "OK"
exit 0