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

support nested variables

This commit is contained in:
deadc0de6
2023-04-11 21:34:32 +02:00
committed by deadc0de
parent d4345e181f
commit 02cb9708e1
5 changed files with 94 additions and 33 deletions

View File

@@ -1398,11 +1398,11 @@ class CfgYaml:
template an item using the templategen
will raise an exception if template failed and exc_if_fail
"""
if not Templategen.var_is_template(item):
if not Templategen.string_is_template(item):
return item
try:
val = item
while Templategen.var_is_template(val):
while Templategen.string_is_template(val):
val = self._tmpl.generate_string(val)
except UndefinedException as exc:
if exc_if_fail:
@@ -1502,14 +1502,21 @@ class CfgYaml:
templ = Templategen(variables=var,
func_file=func_files,
filter_file=filter_files)
newvars = variables.copy()
for k in variables.keys():
val = variables[k]
while Templategen.var_is_template(val):
val = templ.generate_string(val)
variables[k] = val
templ.update_variables(variables)
if variables is self.variables:
val = templ.generate_string_or_dict(val)
if isinstance(val, dict):
for sub in val:
subkey = f'{k}.{sub}'
newvars[subkey] = val[sub]
else:
newvars[k] = val
templ.update_variables(newvars)
if newvars is self.variables:
self._redefine_templater()
variables = newvars
def _get_profile_included_vars(self):
"""

View File

@@ -141,9 +141,10 @@ def _dotfile_compare(opts, dotfile, tmp):
ignores = patch_ignores(ignores, dotfile.dst, debug=opts.debug)
insttmp = None
if dotfile.template and Templategen.is_template(src,
ignore=ignores,
debug=opts.debug):
if dotfile.template and \
Templategen.path_is_template(src,
ignore=ignores,
debug=opts.debug):
# install dotfile to temporary dir for compare
ret, err, insttmp = inst.install_to_temp(templ, tmp, src, dotfile.dst,
is_template=True,
@@ -217,7 +218,7 @@ def _dotfile_install(opts, dotfile, tmpdir=None):
ignores = list(set(opts.install_ignore + dotfile.instignore))
ignores = patch_ignores(ignores, dotfile.dst, debug=opts.debug)
is_template = dotfile.template and Templategen.is_template(
is_template = dotfile.template and Templategen.path_is_template(
dotfile.src,
ignore=ignores,
)
@@ -243,7 +244,7 @@ def _dotfile_install(opts, dotfile, tmpdir=None):
return False, dotfile.key, None
src = tmp
# make sure to re-evaluate if is template
is_template = dotfile.template and Templategen.is_template(
is_template = dotfile.template and Templategen.path_is_template(
src,
ignore=ignores,
)
@@ -389,7 +390,7 @@ def _workdir_enum(opts):
if dotfile.link == LinkTypes.NOLINK:
# ignore not link files
continue
if not Templategen.is_template(src):
if not Templategen.path_is_template(src):
# ignore not template
continue
newpath = pivot_path(dotfile.dst, opts.workdir,
@@ -582,7 +583,7 @@ def cmd_files(opts):
for dotfile in opts.dotfiles:
if opts.files_templateonly:
src = os.path.join(opts.dotpath, dotfile.src)
if not Templategen.is_template(src):
if not Templategen.path_is_template(src):
continue
if opts.files_grepable:
fmt = f'{dotfile.key},'
@@ -746,7 +747,7 @@ def _detail(dotpath, dotfile):
path = os.path.join(dotpath, os.path.expanduser(dotfile.src))
if not os.path.isdir(path):
template = 'no'
if dotfile.template and Templategen.is_template(path):
if dotfile.template and Templategen.path_is_template(path):
template = 'yes'
LOG.sub(f'{path} (template:{template})')
else:
@@ -754,7 +755,7 @@ def _detail(dotpath, dotfile):
for file in files:
fpath = os.path.join(root, file)
template = 'no'
if dotfile.template and Templategen.is_template(fpath):
if dotfile.template and Templategen.path_is_template(fpath):
template = 'yes'
LOG.sub(f'{fpath} (template:{template})')

View File

@@ -110,6 +110,38 @@ class Templategen:
err = f'undefined variable: {exc.message}'
raise UndefinedException(err) from exc
def generate_dict(self, dic):
"""
template each entry of the dict where only
the value of each entry is templated (recursively)
may raise a UndefinedException
in case a variable is undefined
"""
if not dic:
return dic
for key in dic:
value = dic[key]
if isinstance(value, str):
dic[key] = self.generate_string(value)
continue
if isinstance(value, dict):
dic[key] = self.generate_dict(value)
continue
continue
return dic
def generate_string_or_dict(self, content):
"""
render template from string or dict
may raise a UndefinedException
in case a variable is undefined
"""
if isinstance(content, str):
return self.generate_string(content)
if isinstance(content, dict):
return self.generate_dict(content)
raise UndefinedError(f'could not template {content}')
def add_tmp_vars(self, newvars=None):
"""add vars to the globals, make sure to call restore_vars"""
saved_variables = self.variables.copy()
@@ -217,7 +249,7 @@ class Templategen:
return data.decode('utf-8', 'replace')
@staticmethod
def is_template(path, ignore=None, debug=False):
def path_is_template(path, ignore=None, debug=False):
"""recursively check if any file is a template within path"""
if debug:
LOG.dbg(f'is template: {path}', force=True)
@@ -240,19 +272,45 @@ class Templategen:
fpath = os.path.join(path, entry)
if not os.path.isfile(fpath):
# recursively explore directory
if Templategen.is_template(fpath, ignore=ignore, debug=debug):
if Templategen.path_is_template(fpath,
ignore=ignore,
debug=debug):
return True
else:
# check if file is a template
if Templategen._is_template(fpath, ignore=ignore, debug=debug):
if Templategen._is_template(fpath,
ignore=ignore,
debug=debug):
return True
return False
@staticmethod
def var_is_template(string):
def string_is_template(string):
"""check if variable contains template(s)"""
return VAR_START in str(string)
@staticmethod
def dict_is_template(dic):
"""check if dict contains template(s)"""
for key in dic:
value = dic[key]
if isinstance(value, str):
isit = Templategen.string_is_template(value)
if isit:
return True
elif isinstance(value, dict):
return Templategen.dict_is_template(value)
return False
@staticmethod
def var_is_template(something):
"""check if string or dict is template"""
if isinstance(something, str):
return Templategen.string_is_template(something)
if isinstance(something, dict):
return Templategen.dict_is_template(something)
return False
@staticmethod
def _is_template(path, ignore, debug=False):
"""test if file pointed by path is a template"""

View File

@@ -166,8 +166,9 @@ class Updater:
return tmp
def _is_template(self, path):
if not Templategen.is_template(path, ignore=self.ignores,
debug=self.debug):
if not Templategen.path_is_template(path,
ignore=self.ignores,
debug=self.debug):
self.log.dbg(f'{path} is NO template')
return False
self.log.warn(f'{path} uses template, update manually')

View File

@@ -8,7 +8,7 @@
## start-cookie
set -e
cur=$(cd "$(dirname "${BASH_SOURCE:-$0}")" && pwd)
cur=$(cd "$(dirname "${0}")" && pwd)
ddpath="${cur}/../"
export PYTHONPATH="${ddpath}:${PYTHONPATH}"
altbin="python3 -m dotdrop.dotdrop"
@@ -61,23 +61,17 @@ _EOF
#cat ${cfg}
# create the dotfile
echo "wow1: {{@@ wow1 @@}}" > "${tmps}"/dotfiles/abc
echo "wow2: {{@@ wow2 @@}}" >> "${tmps}"/dotfiles/abc
echo "wow1={{@@ wow1 @@}}" > "${tmps}"/dotfiles/abc
echo "wow2={{@@ z2.wow2 @@}}" >> "${tmps}"/dotfiles/abc
# install
cd "${ddpath}" | ${bin} install -f -c "${cfg}" -p p1 --verbose
cat "${tmpd}"/abc
#[ ! -e "${tmpd}"/abc ] && echo "abc not installed" && exit 1
#grep '^this is some test' "${tmpd}"/abc >/dev/null
#grep '^12' "${tmpd}"/abc >/dev/null
#grep '^another test' "${tmpd}"/abc >/dev/null
#
#[ ! -e "${tmpd}"/def ] && echo "def not installed" && exit 1
#grep '^test_def' "${tmpd}"/def >/dev/null
#cat ${tmpd}/abc
[ ! -e "${tmpd}"/abc ] && echo "abc not installed" && exit 1
grep '^wow1=hello1' "${tmpd}"/abc >/dev/null
grep '^wow2=hello2' "${tmpd}"/abc >/dev/null
echo "OK"
exit 0