1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-16 03:46:10 +00:00

adding default_actions and dotfile src/dst paths to template these (for #125)

This commit is contained in:
deadc0de6
2019-05-01 15:55:51 +02:00
parent a4432b5696
commit 44a26a261d
10 changed files with 480 additions and 72 deletions

View File

@@ -68,13 +68,16 @@ class Action(Cmd):
def __repr__(self): def __repr__(self):
return 'action({})'.format(self.__str__()) return 'action({})'.format(self.__str__())
def execute(self): def execute(self, templater=None, newvars={}):
"""execute the action in the shell""" """execute the action in the shell"""
ret = 1 ret = 1
action = self.action
if templater:
action = templater.generate_string(self.action, tmpvars=newvars)
try: try:
cmd = self.action.format(*self.args) cmd = action.format(*self.args)
except IndexError: except IndexError:
err = 'bad action: \"{}\"'.format(self.action) err = 'bad action: \"{}\"'.format(action)
err += ' with \"{}\"'.format(self.args) err += ' with \"{}\"'.format(self.args)
self.log.warn(err) self.log.warn(err)
return False return False

View File

@@ -40,6 +40,7 @@ class Cfg:
key_workdir = 'workdir' key_workdir = 'workdir'
key_cmpignore = 'cmpignore' key_cmpignore = 'cmpignore'
key_upignore = 'upignore' key_upignore = 'upignore'
key_defactions = 'default_actions'
# import keys # import keys
key_import_vars = 'import_variables' key_import_vars = 'import_variables'
@@ -148,14 +149,22 @@ class Cfg:
self.prodots = {} self.prodots = {}
# represents all variables from external files # represents all variables from external files
# NOT linked inside the yaml dict (self.content)
self.ext_variables = {} self.ext_variables = {}
self.ext_dynvariables = {} self.ext_dynvariables = {}
# cmpignore patterns # cmpignore patterns
# NOT linked inside the yaml dict (self.content)
self.cmpignores = [] self.cmpignores = []
# upignore patterns # upignore patterns
# NOT linked inside the yaml dict (self.content)
self.upignores = [] self.upignores = []
# default actions
# NOT linked inside the yaml dict (self.content)
self.defactions = {}
if not self._load_config(profile=profile): if not self._load_config(profile=profile):
raise ValueError('config is not valid') raise ValueError('config is not valid')
@@ -171,13 +180,16 @@ class Cfg:
d.src = t.generate_string(d.src) d.src = t.generate_string(d.src)
d.dst = t.generate_string(d.dst) d.dst = t.generate_string(d.dst)
# pre actions # pre actions
var = d.get_vars()
if self.key_actions_pre in d.actions: if self.key_actions_pre in d.actions:
for action in d.actions[self.key_actions_pre]: for action in d.actions[self.key_actions_pre]:
action.action = t.generate_string(action.action) action.action = t.generate_string(action.action,
tmpvars=var)
# post actions # post actions
if self.key_actions_post in d.actions: if self.key_actions_post in d.actions:
for action in d.actions[self.key_actions_post]: for action in d.actions[self.key_actions_post]:
action.action = t.generate_string(action.action) action.action = t.generate_string(action.action,
tmpvars=var)
return dotfiles return dotfiles
def _load_config(self, profile=None): def _load_config(self, profile=None):
@@ -263,11 +275,13 @@ class Cfg:
# load global upignore # load global upignore
if self.key_upignore in self.lnk_settings: if self.key_upignore in self.lnk_settings:
self.upignores = self.lnk_settings[self.key_upignore] or [] key = self.key_upignore
self.upignores = self.lnk_settings[key].copy() or []
# load global cmpignore # load global cmpignore
if self.key_cmpignore in self.lnk_settings: if self.key_cmpignore in self.lnk_settings:
self.cmpignores = self.lnk_settings[self.key_cmpignore] or [] key = self.key_cmpignore
self.cmpignores = self.lnk_settings[key].copy() or []
# parse external actions # parse external actions
try: try:
@@ -324,6 +338,17 @@ class Cfg:
except KeyError: except KeyError:
pass pass
# load default actions
try:
dactions = self.lnk_settings[self.key_defactions].copy() or []
self.defactions = self._parse_actions_list(dactions,
profile=profile)
except KeyError:
self.defactions = {
self.key_actions_pre: [],
self.key_actions_post: [],
}
# parse read transformations # parse read transformations
# If read transformations are None, replaces them with empty dict # If read transformations are None, replaces them with empty dict
try: try:
@@ -385,7 +410,7 @@ class Cfg:
# parse actions # parse actions
itsactions = v.get(self.key_dotfiles_actions, []) itsactions = v.get(self.key_dotfiles_actions, [])
actions = self._parse_actions(itsactions, profile=profile) actions = self._parse_actions_list(itsactions, profile=profile)
if self.debug: if self.debug:
self.log.dbg('action for {}'.format(k)) self.log.dbg('action for {}'.format(k))
for t in [self.key_actions_pre, self.key_actions_post]: for t in [self.key_actions_pre, self.key_actions_post]:
@@ -722,7 +747,7 @@ class Cfg:
dotfiles.extend(self.prodots[other]) dotfiles.extend(self.prodots[other])
return True, dotfiles return True, dotfiles
def _parse_actions(self, entries, profile=None): def _parse_actions_list(self, entries, profile=None):
"""parse actions specified for an element """parse actions specified for an element
where entries are the ones defined for this dotfile""" where entries are the ones defined for this dotfile"""
res = { res = {
@@ -1052,6 +1077,9 @@ class Cfg:
settings[key] = self._string_to_linktype(settings[key]) settings[key] = self._string_to_linktype(settings[key])
key = self.key_dotfile_link key = self.key_dotfile_link
settings[key] = self._string_to_linktype(settings[key]) settings[key] = self._string_to_linktype(settings[key])
# patch defactions
key = self.key_defactions
settings[key] = self.defactions
return settings return settings
def get_variables(self, profile, debug=False): def get_variables(self, profile, debug=False):

View File

@@ -27,6 +27,48 @@ TRANS_SUFFIX = 'trans'
########################################################### ###########################################################
def action_executor(o, dotfile, actions, defactions, templater, post=False):
"""closure for action execution"""
def execute():
"""
execute actions and return
True, None if ok
False, errstring if issue
"""
s = 'pre' if not post else 'post'
# execute default actions
for action in defactions:
if o.dry:
LOG.dry('would execute def-{}-action: {}'.format(s,
action))
continue
if o.debug:
LOG.dbg('executing def-{}-action {}'.format(s, action))
newvars = dotfile.get_vars()
ret = action.execute(templater=templater, newvars=newvars)
if not ret:
err = 'def-{}-action \"{}\" failed'.format(s, action.key)
LOG.err(err)
return False, err
# execute actions
for action in actions:
if o.dry:
LOG.dry('would execute {}-action: {}'.format(s, action))
continue
if o.debug:
LOG.dbg('executing {}-action {}'.format(s, action))
newvars = dotfile.get_vars()
ret = action.execute(templater=templater, newvars=newvars)
if not ret:
err = '{}-action \"{}\" failed'.format(s, action.key)
LOG.err(err)
return False, err
return True, None
return execute
def cmd_install(o): def cmd_install(o):
"""install dotfiles for this profile""" """install dotfiles for this profile"""
dotfiles = o.dotfiles dotfiles = o.dotfiles
@@ -57,14 +99,19 @@ def cmd_install(o):
and Cfg.key_actions_pre in dotfile.actions: and Cfg.key_actions_pre in dotfile.actions:
for action in dotfile.actions[Cfg.key_actions_pre]: for action in dotfile.actions[Cfg.key_actions_pre]:
preactions.append(action) preactions.append(action)
defactions = o.install_default_actions[Cfg.key_actions_pre]
pre_actions_exec = action_executor(o, dotfile, preactions,
defactions, t, post=False)
if o.debug: if o.debug:
LOG.dbg('installing {}'.format(dotfile)) LOG.dbg('installing {}'.format(dotfile))
if hasattr(dotfile, 'link') and dotfile.link == LinkTypes.LINK: if hasattr(dotfile, 'link') and dotfile.link == LinkTypes.LINK:
r = inst.link(t, dotfile.src, dotfile.dst, actions=preactions) r = inst.link(t, dotfile.src, dotfile.dst,
actionexec=pre_actions_exec)
elif hasattr(dotfile, 'link') and \ elif hasattr(dotfile, 'link') and \
dotfile.link == LinkTypes.LINK_CHILDREN: dotfile.link == LinkTypes.LINK_CHILDREN:
r = inst.link_children(t, dotfile.src, dotfile.dst, r = inst.link_children(t, dotfile.src, dotfile.dst,
actions=preactions) actionexec=pre_actions_exec)
else: else:
src = dotfile.src src = dotfile.src
tmp = None tmp = None
@@ -73,7 +120,8 @@ def cmd_install(o):
if not tmp: if not tmp:
continue continue
src = tmp src = tmp
r, err = inst.install(t, src, dotfile.dst, actions=preactions, r, err = inst.install(t, src, dotfile.dst,
actionexec=pre_actions_exec,
noempty=dotfile.noempty) noempty=dotfile.noempty)
if tmp: if tmp:
tmp = os.path.join(o.dotpath, tmp) tmp = os.path.join(o.dotpath, tmp)
@@ -82,15 +130,11 @@ def cmd_install(o):
if r: if r:
if not o.install_temporary and \ if not o.install_temporary and \
Cfg.key_actions_post in dotfile.actions: Cfg.key_actions_post in dotfile.actions:
actions = dotfile.actions[Cfg.key_actions_post] defactions = o.install_default_actions[Cfg.key_actions_post]
# execute post action postactions = dotfile.actions[Cfg.key_actions_post]
for action in actions: post_actions_exec = action_executor(o, dotfile, postactions,
if o.dry: defactions, t, post=True)
LOG.dry('would execute action: {}'.format(action)) post_actions_exec()
else:
if o.debug:
LOG.dbg('executing post action {}'.format(action))
action.execute()
installed += 1 installed += 1
elif not r and err: elif not r and err:
LOG.err('installing \"{}\" failed: {}'.format(dotfile.key, err)) LOG.err('installing \"{}\" failed: {}'.format(dotfile.key, err))

View File

@@ -40,6 +40,13 @@ class Dotfile:
self.noempty = noempty self.noempty = noempty
self.upignore = upignore self.upignore = upignore
def get_vars(self):
"""return this dotfile templating vars"""
_vars = {}
_vars['_dotfile_src'] = self.src
_vars['_dotfile_dst'] = self.dst
return _vars
def __str__(self): def __str__(self):
msg = 'key:\"{}\", src:\"{}\", dst:\"{}\", link:\"{}\"' msg = 'key:\"{}\", src:\"{}\", dst:\"{}\", link:\"{}\"'
return msg.format(self.key, self.src, self.dst, self.link.name.lower()) return msg.format(self.key, self.src, self.dst, self.link.name.lower())

View File

@@ -49,13 +49,19 @@ class Installer:
self.action_executed = False self.action_executed = False
self.log = Logger() self.log = Logger()
def install(self, templater, src, dst, actions=[], noempty=False): def install(self, templater, src, dst, actionexec=None, noempty=False):
""" """
install src to dst using a template install src to dst using a template
@templater: the templater object
@src: dotfile source path in dotpath
@dst: dotfile destination path in the FS
@actionexec: action executor callback
@noempty: render empty template flag
return return
- True, None : success - True, None : success
- False, error_msg : error - False, error_msg : error
- False, None, ignored - False, None : ignored
""" """
if self.debug: if self.debug:
self.log.dbg('install {} to {}'.format(src, dst)) self.log.dbg('install {} to {}'.format(src, dst))
@@ -76,18 +82,24 @@ class Installer:
self.log.dbg('install {} to {}'.format(src, dst)) self.log.dbg('install {} to {}'.format(src, dst))
self.log.dbg('is \"{}\" a directory: {}'.format(src, isdir)) self.log.dbg('is \"{}\" a directory: {}'.format(src, isdir))
if isdir: if isdir:
return self._handle_dir(templater, src, dst, actions=actions, return self._handle_dir(templater, src, dst,
actionexec=actionexec,
noempty=noempty) noempty=noempty)
return self._handle_file(templater, src, dst, return self._handle_file(templater, src, dst,
actions=actions, noempty=noempty) actionexec=actionexec, noempty=noempty)
def link(self, templater, src, dst, actions=[]): def link(self, templater, src, dst, actionexec=None):
""" """
set src as the link target of dst set src as the link target of dst
@templater: the templater
@src: dotfile source path in dotpath
@dst: dotfile destination path in the FS
@actionexec: action executor callback
return return
- True, None : success - True, None : success
- False, error_msg : error - False, error_msg : error
- False, None, ignored - False, None : ignored
""" """
if self.debug: if self.debug:
self.log.dbg('link {} to {}'.format(src, dst)) self.log.dbg('link {} to {}'.format(src, dst))
@@ -100,22 +112,27 @@ class Installer:
dst = os.path.normpath(os.path.expanduser(dst)) dst = os.path.normpath(os.path.expanduser(dst))
if self.totemp: if self.totemp:
# ignore actions # ignore actions
return self.install(templater, src, dst, actions=[]) return self.install(templater, src, dst, actionexec=None)
if Templategen.is_template(src): if Templategen.is_template(src):
if self.debug: if self.debug:
self.log.dbg('dotfile is a template') self.log.dbg('dotfile is a template')
self.log.dbg('install to {} and symlink'.format(self.workdir)) self.log.dbg('install to {} and symlink'.format(self.workdir))
tmp = self._pivot_path(dst, self.workdir, striphome=True) tmp = self._pivot_path(dst, self.workdir, striphome=True)
i, err = self.install(templater, src, tmp, actions=actions) i, err = self.install(templater, src, tmp, actionexec=actionexec)
if not i and not os.path.exists(tmp): if not i and not os.path.exists(tmp):
return i, err return i, err
src = tmp src = tmp
return self._link(src, dst, actions=actions) return self._link(src, dst, actionexec=actionexec)
def link_children(self, templater, src, dst, actions=[]): def link_children(self, templater, src, dst, actionexec=None):
""" """
link all dotfiles in a given directory link all dotfiles in a given directory
@templater: the templater
@src: dotfile source path in dotpath
@dst: dotfile destination path in the FS
@actionexec: action executor callback
return return
- True, None: success - True, None: success
- False, error_msg: error - False, error_msg: error
@@ -175,21 +192,21 @@ class Installer:
self.log.dbg('install to {} and symlink' self.log.dbg('install to {} and symlink'
.format(self.workdir)) .format(self.workdir))
tmp = self._pivot_path(dst, self.workdir, striphome=True) tmp = self._pivot_path(dst, self.workdir, striphome=True)
r, e = self.install(templater, src, tmp, actions=actions) r, e = self.install(templater, src, tmp, actionexec=actionexec)
if not r and e and not os.path.exists(tmp): if not r and e and not os.path.exists(tmp):
continue continue
src = tmp src = tmp
result = self._link(src, dst, actions) result = self._link(src, dst, actionexec=actionexec)
# Empty actions if dotfile installed # void actionexec if dotfile installed
# This prevents from running actions multiple times # to prevent from running actions multiple times
if len(result): if len(result):
actions = [] actionexec = None
return True, None return True, None
def _link(self, src, dst, actions=[]): def _link(self, src, dst, actionexec=None):
"""set src as a link target of dst""" """set src as a link target of dst"""
overwrite = not self.safe overwrite = not self.safe
if os.path.lexists(dst): if os.path.lexists(dst):
@@ -216,7 +233,7 @@ class Installer:
if not self._create_dirs(base): if not self._create_dirs(base):
err = 'creating directory for {}'.format(dst) err = 'creating directory for {}'.format(dst)
return False, err return False, err
r, e = self._exec_pre_actions(actions) r, e = self._exec_pre_actions(actionexec)
if not r: if not r:
return False, e return False, e
# re-check in case action created the file # re-check in case action created the file
@@ -234,7 +251,8 @@ class Installer:
self.log.sub('linked {} to {}'.format(dst, src)) self.log.sub('linked {} to {}'.format(dst, src))
return True, None return True, None
def _handle_file(self, templater, src, dst, actions=[], noempty=False): def _handle_file(self, templater, src, dst,
actionexec=None, noempty=False):
"""install src to dst when is a file""" """install src to dst when is a file"""
if self.debug: if self.debug:
self.log.dbg('generate template for {}'.format(src)) self.log.dbg('generate template for {}'.format(src))
@@ -254,7 +272,8 @@ class Installer:
err = 'source dotfile does not exist: {}'.format(src) err = 'source dotfile does not exist: {}'.format(src)
return False, err return False, err
st = os.stat(src) st = os.stat(src)
ret, err = self._write(src, dst, content, st.st_mode, actions=actions) ret, err = self._write(src, dst, content,
st.st_mode, actionexec=actionexec)
if ret < 0: if ret < 0:
return False, err return False, err
if ret > 0: if ret > 0:
@@ -268,7 +287,7 @@ class Installer:
err = 'installing {} to {}'.format(src, dst) err = 'installing {} to {}'.format(src, dst)
return False, err return False, err
def _handle_dir(self, templater, src, dst, actions=[], noempty=False): def _handle_dir(self, templater, src, dst, actionexec=None, noempty=False):
"""install src to dst when is a directory""" """install src to dst when is a directory"""
if self.debug: if self.debug:
self.log.dbg('install dir {}'.format(src)) self.log.dbg('install dir {}'.format(src))
@@ -285,7 +304,7 @@ class Installer:
# is file # is file
res, err = self._handle_file(templater, f, res, err = self._handle_file(templater, f,
os.path.join(dst, entry), os.path.join(dst, entry),
actions=actions, actionexec=actionexec,
noempty=noempty) noempty=noempty)
if not res and err: if not res and err:
# error occured # error occured
@@ -298,7 +317,7 @@ class Installer:
# is directory # is directory
res, err = self._handle_dir(templater, f, res, err = self._handle_dir(templater, f,
os.path.join(dst, entry), os.path.join(dst, entry),
actions=actions, actionexec=actionexec,
noempty=noempty) noempty=noempty)
if not res and err: if not res and err:
# error occured # error occured
@@ -316,7 +335,7 @@ class Installer:
cur = f.read() cur = f.read()
return cur == content return cur == content
def _write(self, src, dst, content, rights, actions=[]): def _write(self, src, dst, content, rights, actionexec=None):
"""write content to file """write content to file
return 0, None: for success, return 0, None: for success,
1, None: when already exists 1, None: when already exists
@@ -353,7 +372,7 @@ class Installer:
if not self._create_dirs(base): if not self._create_dirs(base):
err = 'creating directory for {}'.format(dst) err = 'creating directory for {}'.format(dst)
return -1, err return -1, err
r, e = self._exec_pre_actions(actions) r, e = self._exec_pre_actions(actionexec)
if not r: if not r:
return -1, e return -1, e
if self.debug: if self.debug:
@@ -422,21 +441,15 @@ class Installer:
self.log.dbg('pivot \"{}\" to \"{}\"'.format(path, new)) self.log.dbg('pivot \"{}\" to \"{}\"'.format(path, new))
return new return new
def _exec_pre_actions(self, actions): def _exec_pre_actions(self, actionexec):
"""execute pre-actions if any""" """execute action executor"""
if self.action_executed: if self.action_executed:
return True, None return True, None
for action in actions: if not actionexec:
if self.dry:
self.log.dry('would execute action: {}'.format(action))
else:
if self.debug:
self.log.dbg('executing pre action {}'.format(action))
if not action.execute():
err = 'pre-action \"{}\" failed'.format(action.key)
return False, err
self.action_executed = True
return True, None return True, None
ret, err = actionexec()
self.action_executed = True
return ret, err
def _install_to_temp(self, templater, src, dst, tmpdir): def _install_to_temp(self, templater, src, dst, tmpdir):
"""install a dotfile to a tempdir""" """install a dotfile to a tempdir"""

View File

@@ -182,7 +182,7 @@ class Options(AttrMonitor):
def _read_config(self, profile=None): def _read_config(self, profile=None):
"""read the config file""" """read the config file"""
self.conf = Cfg(self.confpath, profile=profile, debug=self.debug) self.conf = Cfg(self.confpath, profile=profile, debug=self.debug)
# transform the configs in attribute # transform the config settings to self attribute
for k, v in self.conf.get_settings().items(): for k, v in self.conf.get_settings().items():
if self.debug: if self.debug:
self.log.dbg('setting: {}={}'.format(k, v)) self.log.dbg('setting: {}={}'.format(k, v))
@@ -223,6 +223,7 @@ class Options(AttrMonitor):
self.install_diff = not self.args['--nodiff'] self.install_diff = not self.args['--nodiff']
self.install_showdiff = self.showdiff or self.args['--showdiff'] self.install_showdiff = self.showdiff or self.args['--showdiff']
self.install_backup_suffix = BACKUP_SUFFIX self.install_backup_suffix = BACKUP_SUFFIX
self.install_default_actions = self.default_actions
# "compare" specifics # "compare" specifics
self.compare_dopts = self.args['--dopts'] self.compare_dopts = self.args['--dopts']
self.compare_focus = self.args['--file'] self.compare_focus = self.args['--file']

View File

@@ -51,17 +51,37 @@ class Templategen:
self.env.globals['exists'] = jhelpers.exists self.env.globals['exists'] = jhelpers.exists
self.env.globals['exists_in_path'] = jhelpers.exists_in_path self.env.globals['exists_in_path'] = jhelpers.exists_in_path
def generate(self, src): def generate(self, src, tmpvars={}):
"""render template from path""" """render template from path"""
if not os.path.exists(src): if not os.path.exists(src):
return '' return ''
return self._handle_file(src) saved = self._patch_globals(tmpvars)
ret = self._handle_file(src)
self._restore_globals(saved)
return ret
def generate_string(self, string): def generate_string(self, string, tmpvars={}):
"""render template from string""" """render template from string"""
if not string: if not string:
return '' return ''
return self.env.from_string(string).render() saved = self._patch_globals(tmpvars)
if self.debug:
self.log.dbg('new vars: {}'.format(tmpvars))
ret = self.env.from_string(string).render()
self._restore_globals(saved)
return ret
def _patch_globals(self, newvars={}):
"""add vars to the globals, make sure to call _restore_globals"""
saved_globals = self.env.globals.copy()
if not newvars:
return saved_globals
self.env.globals.update(newvars)
return saved_globals
def _restore_globals(self, saved_globals):
"""restore globals from _patch_globals"""
self.env.globals = saved_globals.copy()
def update_variables(self, variables): def update_variables(self, variables):
"""update variables""" """update variables"""

150
tests-ng/actions-default.sh Executable file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2017, deadc0de6
#
# test default action execution
# 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
################################################################
# the action temp
tmpa=`mktemp -d --suffix='-dotdrop-tests'`
# the dotfile source
tmps=`mktemp -d --suffix='-dotdrop-tests'`
mkdir -p ${tmps}/dotfiles
# the dotfile destination
tmpd=`mktemp -d --suffix='-dotdrop-tests'`
# create the config file
cfg="${tmps}/config.yaml"
cat > ${cfg} << _EOF
actions:
pre:
failpre: "false"
preaction: echo 'pre' > ${tmpa}/pre
preaction1: echo 'preinside' > ${tmpa}/preinside
post:
failpost: "false"
postaction: echo 'post' > ${tmpa}/post
postaction1: echo 'postinside' > ${tmpa}/postinside
nakedaction: echo 'naked' > ${tmpa}/naked
nakedaction1: echo 'nakedinside' > ${tmpa}/nakedinside
config:
backup: true
create: true
dotpath: dotfiles
default_actions:
- preaction
- postaction
- nakedaction
dotfiles:
f_abc:
dst: ${tmpd}/abc
src: abc
actions:
- preaction1
- nakedaction1
- postaction1
profiles:
p1:
dotfiles:
- f_abc
_EOF
#cat ${cfg}
# create the dotfile
echo 'test' > ${tmps}/dotfiles/abc
# install
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
# checks pre action
[ ! -e ${tmpa}/pre ] && echo 'pre action not executed' && exit 1
[ ! -e ${tmpa}/preinside ] && echo 'pre action not executed' && exit 1
grep pre ${tmpa}/pre >/dev/null
grep preinside ${tmpa}/preinside >/dev/null
# checks post action
[ ! -e ${tmpa}/post ] && echo 'post action not executed' && exit 1
[ ! -e ${tmpa}/postinside ] && echo 'post action not executed' && exit 1
grep post ${tmpa}/post >/dev/null
grep postinside ${tmpa}/postinside >/dev/null
# checks naked action
[ ! -e ${tmpa}/naked ] && echo 'naked action not executed' && exit 1
[ ! -e ${tmpa}/nakedinside ] && echo 'naked action not executed' && exit 1
grep naked ${tmpa}/naked >/dev/null
grep nakedinside ${tmpa}/nakedinside >/dev/null
# clear
rm -f ${tmpa}/naked* ${tmpa}/pre* ${tmpa}/post* ${tmpd}/abc
cat > ${cfg} << _EOF
actions:
pre:
failpre: "false"
config:
backup: true
create: true
dotpath: dotfiles
default_actions:
- failpre
dotfiles:
f_abc:
dst: ${tmpd}/abc
src: abc
profiles:
p1:
dotfiles:
- f_abc
_EOF
# ensure failing actions make the installation fail
# install
set +e
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
set -e
[ -e ${tmpd}/abc ] && exit 1
## CLEANING
rm -rf ${tmps} ${tmpd} ${tmpa}
echo "OK"
exit 0

142
tests-ng/actions-template.sh Executable file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2017, deadc0de6
#
# test action template execution
# 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
################################################################
# the action temp
tmpa=`mktemp -d --suffix='-dotdrop-tests'`
# the dotfile source
tmps=`mktemp -d --suffix='-dotdrop-tests'`
mkdir -p ${tmps}/dotfiles
# the dotfile destination
tmpd=`mktemp -d --suffix='-dotdrop-tests'`
# create the config file
cfg="${tmps}/config.yaml"
cat > ${cfg} << _EOF
actions:
pre:
preaction: "echo {{@@ _dotfile_src @@}} > ${tmpa}/pre"
post:
postaction: "echo {{@@ _dotfile_src @@}} > ${tmpa}/post"
nakedaction: "echo {{@@ _dotfile_src @@}} > ${tmpa}/naked"
config:
backup: true
create: true
dotpath: dotfiles
default_actions:
- preaction
- postaction
- nakedaction
dotfiles:
f_abc:
dst: ${tmpd}/abc
src: abc
profiles:
p1:
dotfiles:
- f_abc
_EOF
#cat ${cfg}
# create the dotfile
echo 'test' > ${tmps}/dotfiles/abc
# install
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
# checks action
[ ! -e ${tmpa}/pre ] && echo 'pre action not executed' && exit 1
[ ! -e ${tmpa}/post ] && echo 'post action not executed' && exit 1
[ ! -e ${tmpa}/naked ] && echo 'naked action not executed' && exit 1
grep abc ${tmpa}/pre >/dev/null
grep abc ${tmpa}/post >/dev/null
grep abc ${tmpa}/naked >/dev/null
# clear
rm -f ${tmpa}/naked* ${tmpa}/pre* ${tmpa}/post* ${tmpd}/abc
cat > ${cfg} << _EOF
actions:
pre:
preaction: "echo {{@@ _dotfile_dst @@}} > ${tmpa}/pre"
post:
postaction: "echo {{@@ _dotfile_dst @@}} > ${tmpa}/post"
nakedaction: "echo {{@@ _dotfile_dst @@}} > ${tmpa}/naked"
config:
backup: true
create: true
dotpath: dotfiles
dotfiles:
f_abc:
dst: ${tmpd}/abc
src: abc
actions:
- preaction
- nakedaction
- postaction
profiles:
p1:
dotfiles:
- f_abc
_EOF
# install
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
# checks action
[ ! -e ${tmpa}/pre ] && echo 'pre action not executed' && exit 1
[ ! -e ${tmpa}/post ] && echo 'post action not executed' && exit 1
[ ! -e ${tmpa}/naked ] && echo 'naked action not executed' && exit 1
grep "${tmpd}/abc" ${tmpa}/pre >/dev/null
grep "${tmpd}/abc" ${tmpa}/post >/dev/null
grep "${tmpd}/abc" ${tmpa}/naked >/dev/null
## CLEANING
rm -rf ${tmps} ${tmpd} ${tmpa}
echo "OK"
exit 0

View File

@@ -350,7 +350,7 @@ exec bspwm
installer = Installer() installer = Installer()
installer.link_children(templater=MagicMock(), src=src_dir, installer.link_children(templater=MagicMock(), src=src_dir,
dst=dst_dir, actions=[]) dst=dst_dir, actionexec=None)
# Ensure all destination files point to source # Ensure all destination files point to source
for src in srcs: for src in srcs:
@@ -366,7 +366,7 @@ exec bspwm
installer.log.err = logger installer.log.err = logger
res, err = installer.link_children(templater=MagicMock(), src=src, res, err = installer.link_children(templater=MagicMock(), src=src,
dst='/dev/null', actions=[]) dst='/dev/null', actionexec=None)
self.assertFalse(res) self.assertFalse(res)
e = 'source dotfile does not exist: {}'.format(src) e = 'source dotfile does not exist: {}'.format(src)
@@ -388,7 +388,7 @@ exec bspwm
# pass src file not src dir # pass src file not src dir
res, err = installer.link_children(templater=templater, src=src, res, err = installer.link_children(templater=templater, src=src,
dst='/dev/null', actions=[]) dst='/dev/null', actionexec=None)
# ensure nothing performed # ensure nothing performed
self.assertFalse(res) self.assertFalse(res)
@@ -411,7 +411,7 @@ exec bspwm
installer = Installer() installer = Installer()
installer.link_children(templater=MagicMock(), src=src_dir, installer.link_children(templater=MagicMock(), src=src_dir,
dst=dst_dir, actions=[]) dst=dst_dir, actionexec=None)
# ensure dst dir created # ensure dst dir created
self.assertTrue(os.path.exists(dst_dir)) self.assertTrue(os.path.exists(dst_dir))
@@ -443,7 +443,7 @@ exec bspwm
installer.log.ask = ask installer.log.ask = ask
installer.link_children(templater=MagicMock(), src=src_dir, dst=dst, installer.link_children(templater=MagicMock(), src=src_dir, dst=dst,
actions=[]) actionexec=None)
# ensure destination now a directory # ensure destination now a directory
self.assertTrue(os.path.isdir(dst)) self.assertTrue(os.path.isdir(dst))
@@ -477,7 +477,7 @@ exec bspwm
mocked_templategen.is_template.return_value = True mocked_templategen.is_template.return_value = True
installer.link_children(templater=templater, src=src_dir, dst=dst_dir, installer.link_children(templater=templater, src=src_dir, dst=dst_dir,
actions=[]) actionexec=None)
for src in srcs: for src in srcs:
dst = os.path.join(dst_dir, os.path.basename(src)) dst = os.path.join(dst_dir, os.path.basename(src))