1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-05 17:53:52 +00:00

implement recursive variables for #83

This commit is contained in:
deadc0de6
2019-02-02 20:16:44 +01:00
parent 45f29679b2
commit 8e9f1b2468
5 changed files with 197 additions and 15 deletions

View File

@@ -543,7 +543,8 @@ The second symlink method is a little more complicated. It creates a symlink in
`dst` for every file/directory in `src`.
### Why would I use `link_children`?
This feature can be very useful dotfiles such as vim where you may not want
This feature can be very useful for dotfiles such as vim where you may not want
plugins cluttering your dotfiles repository. First, the simpler `link: true` is
shown for comparison. With the `config.yaml` entry shown below, `~/.vim` gets
symlinked to `~/.dotfiles/vim/`. This means that using vim will now pollute the
@@ -793,6 +794,27 @@ Following template variables are available:
* defined variables (see [Variables](#variables))
* interpreted variables (see [Interpreted variables](#interpreted-variables))
All variables are recursively evaluated what means that
a config similar to:
```yaml
variables:
var1: "var1"
var2: "{{@@ var1 @@}} var2"
var3: "{{@@ var2 @@}} var3"
var4: "{{@@ dvar4 @@}}"
dynvariables:
dvar1: "echo dvar1"
dvar2: "{{@@ dvar1 @@}} dvar2"
dvar3: "{{@@ dvar2 @@}} dvar3"
dvar4: "echo {{@@ var3 @@}}"
```
will result in
* var3: `var1 var2 var3`
* dvar3: `dvar1 dvar2 dvar3`
* var4: `echo var1 var2 var3`
* dvar4: `var1 var2 var3`
## Variables
Variables can be added in the config file under the `variables` entry.

View File

@@ -119,9 +119,8 @@ class Cfg:
raise ValueError('config is not valid')
def eval_dotfiles(self, profile, debug=False):
"""resolve dotfiles src/dst templating"""
t = Templategen(variables=self.get_variables(profile),
debug=debug)
"""resolve dotfiles src/dst templating for this profile"""
t = Templategen(variables=self.get_variables(profile, debug=debug))
for d in self.get_dotfiles(profile):
d.src = t.generate_string(d.src)
d.dst = t.generate_string(d.dst)
@@ -622,8 +621,44 @@ class Cfg:
"""return all defined settings"""
return self.lnk_settings.copy()
def get_variables(self, profile):
def get_variables(self, profile, debug=False):
"""return the variables for this profile"""
# get flat variables
variables = self._get_variables(profile)
# get interpreted variables
dvariables = self._get_dynvariables(profile)
# recursive resolve variables
allvars = variables.copy()
allvars.update(dvariables)
var = self._rec_resolve_vars(allvars)
# execute dynvariables
for k in dvariables.keys():
var[k] = shell(var[k])
if debug:
self.log.dbg('variables:')
for k, v in var.items():
self.log.dbg('\t\"{}\": {}'.format(k, v))
return var
def _rec_resolve_vars(self, variables):
"""recursive resolve all variables"""
t = Templategen(variables=variables)
for k in variables.keys():
val = variables[k]
while Templategen.var_is_template(val):
val = t.generate_string(val)
variables[k] = val
t.update_variables(variables)
return variables
def _get_variables(self, profile):
"""return the flat variables"""
variables = {}
# profile variable
@@ -633,13 +668,6 @@ class Cfg:
if self.key_variables in self.content:
variables.update(self.content[self.key_variables])
# global dynvariables
if self.key_dynvariables in self.content:
# interpret dynamic variables
dynvars = self.content[self.key_dynvariables]
for k, v in dynvars.items():
variables[k] = shell(v)
if profile not in self.lnk_profiles:
return variables
@@ -649,10 +677,24 @@ class Cfg:
for k, v in var[self.key_variables].items():
variables[k] = v
return variables
def _get_dynvariables(self, profile):
"""return the dyn variables"""
variables = {}
# global dynvariables
if self.key_dynvariables in self.content:
# interpret dynamic variables
variables.update(self.content[self.key_dynvariables])
if profile not in self.lnk_profiles:
return variables
# profile dynvariables
var = self.lnk_profiles[profile]
if self.key_dynvariables in var.keys():
for k, v in var[self.key_dynvariables].items():
variables[k] = shell(v)
variables.update(var[self.key_dynvariables])
return variables

View File

@@ -449,7 +449,8 @@ def main():
opts['link'] = LinkTypes.NOLINK
opts['debug'] = args['--verbose']
opts['variables'] = conf.get_variables(opts['profile'])
opts['variables'] = conf.get_variables(opts['profile'],
debug=opts['debug'])
opts['showdiff'] = opts['showdiff'] or args['--showdiff']
if opts['debug']:

View File

@@ -57,6 +57,10 @@ class Templategen:
return ''
return self.env.from_string(string).render()
def update_variables(self, variables):
"""update variables"""
self.env.globals.update(variables)
def _header(self, prepend=''):
"""add a comment usually in the header of a dotfile"""
return '{}{}'.format(prepend, utils.header())
@@ -125,6 +129,11 @@ class Templategen:
return True
return False
@staticmethod
def var_is_template(string):
"""check if variable contains template(s)"""
return VAR_START in str(string)
@staticmethod
def _is_template(path):
"""test if file pointed by path is a template"""

108
tests-ng/recvariables.sh Executable file
View File

@@ -0,0 +1,108 @@
#!/usr/bin/env bash
# author: deadc0de6 (https://github.com/deadc0de6)
# Copyright (c) 2017, deadc0de6
#
# test recursive variables
# 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 dotfile source
tmps=`mktemp -d`
mkdir -p ${tmps}/dotfiles
# the dotfile destination
tmpd=`mktemp -d`
#echo "dotfile destination: ${tmpd}"
# create the config file
cfg="${tmps}/config.yaml"
cat > ${cfg} << _EOF
config:
backup: true
create: true
dotpath: dotfiles
variables:
var1: "var1"
var2: "{{@@ var1 @@}} var2"
var3: "{{@@ var2 @@}} var3"
var4: "{{@@ dvar4 @@}}"
dynvariables:
dvar1: "echo dvar1"
dvar2: "{{@@ dvar1 @@}} dvar2"
dvar3: "{{@@ dvar2 @@}} dvar3"
dvar4: "echo {{@@ var3 @@}}"
dotfiles:
f_abc:
dst: ${tmpd}/abc
src: abc
profiles:
p1:
dotfiles:
- f_abc
_EOF
cat ${cfg}
# create the dotfile
echo "var3: {{@@ var3 @@}}" > ${tmps}/dotfiles/abc
echo "dvar3: {{@@ dvar3 @@}}" >> ${tmps}/dotfiles/abc
echo "var4: {{@@ var4 @@}}" >> ${tmps}/dotfiles/abc
echo "dvar4: {{@@ dvar4 @@}}" >> ${tmps}/dotfiles/abc
#cat ${tmps}/dotfiles/abc
# install
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
#cat ${tmpd}/abc
grep '^var3: var1 var2 var3' ${tmpd}/abc >/dev/null
grep '^dvar3: dvar1 dvar2 dvar3' ${tmpd}/abc >/dev/null
grep '^var4: echo var1 var2 var3' ${tmpd}/abc >/dev/null
grep '^dvar4: var1 var2 var3' ${tmpd}/abc >/dev/null
#cat ${tmpd}/abc
## CLEANING
rm -rf ${tmps} ${tmpd} ${scr}
echo "OK"
exit 0