mirror of
https://github.com/deadc0de6/dotdrop.git
synced 2026-02-16 21:59:11 +00:00
adding ability to add custom functions and filters for #200
This commit is contained in:
@@ -85,6 +85,7 @@ def cmd_install(o):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
t = Templategen(base=o.dotpath, variables=o.variables,
|
t = Templategen(base=o.dotpath, variables=o.variables,
|
||||||
|
func_file=o.func_file, filter_file=o.filter_file,
|
||||||
debug=o.debug)
|
debug=o.debug)
|
||||||
tmpdir = None
|
tmpdir = None
|
||||||
if o.install_temporary:
|
if o.install_temporary:
|
||||||
@@ -205,6 +206,7 @@ def cmd_compare(o, tmp):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
t = Templategen(base=o.dotpath, variables=o.variables,
|
t = Templategen(base=o.dotpath, variables=o.variables,
|
||||||
|
func_file=o.func_file, filter_file=o.filter_file,
|
||||||
debug=o.debug)
|
debug=o.debug)
|
||||||
inst = Installer(create=o.create, backup=o.backup,
|
inst = Installer(create=o.create, backup=o.backup,
|
||||||
dry=o.dry, base=o.dotpath,
|
dry=o.dry, base=o.dotpath,
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ class Settings(DictParser):
|
|||||||
key_instignore = 'instignore'
|
key_instignore = 'instignore'
|
||||||
key_workdir = 'workdir'
|
key_workdir = 'workdir'
|
||||||
key_minversion = 'minversion'
|
key_minversion = 'minversion'
|
||||||
|
key_func_file = 'func_file'
|
||||||
|
key_filter_file = 'filter_file'
|
||||||
|
|
||||||
# import keys
|
# import keys
|
||||||
key_import_actions = 'import_actions'
|
key_import_actions = 'import_actions'
|
||||||
@@ -45,7 +47,7 @@ class Settings(DictParser):
|
|||||||
link_on_import=LinkTypes.NOLINK, longkey=False,
|
link_on_import=LinkTypes.NOLINK, longkey=False,
|
||||||
upignore=[], cmpignore=[], instignore=[],
|
upignore=[], cmpignore=[], instignore=[],
|
||||||
workdir='~/.config/dotdrop', showdiff=False,
|
workdir='~/.config/dotdrop', showdiff=False,
|
||||||
minversion=None):
|
minversion=None, func_file=[], filter_file=[]):
|
||||||
self.backup = backup
|
self.backup = backup
|
||||||
self.banner = banner
|
self.banner = banner
|
||||||
self.create = create
|
self.create = create
|
||||||
@@ -65,6 +67,8 @@ class Settings(DictParser):
|
|||||||
self.link_dotfile_default = LinkTypes.get(link_dotfile_default)
|
self.link_dotfile_default = LinkTypes.get(link_dotfile_default)
|
||||||
self.link_on_import = LinkTypes.get(link_on_import)
|
self.link_on_import = LinkTypes.get(link_on_import)
|
||||||
self.minversion = minversion
|
self.minversion = minversion
|
||||||
|
self.func_file = func_file
|
||||||
|
self.filter_file = filter_file
|
||||||
|
|
||||||
def _serialize_seq(self, name, dic):
|
def _serialize_seq(self, name, dic):
|
||||||
"""serialize attribute 'name' into 'dic'"""
|
"""serialize attribute 'name' into 'dic'"""
|
||||||
@@ -95,5 +99,7 @@ class Settings(DictParser):
|
|||||||
self._serialize_seq(self.key_cmpignore, dic)
|
self._serialize_seq(self.key_cmpignore, dic)
|
||||||
self._serialize_seq(self.key_upignore, dic)
|
self._serialize_seq(self.key_upignore, dic)
|
||||||
self._serialize_seq(self.key_instignore, dic)
|
self._serialize_seq(self.key_instignore, dic)
|
||||||
|
self._serialize_seq(self.key_func_file, dic)
|
||||||
|
self._serialize_seq(self.key_filter_file, dic)
|
||||||
|
|
||||||
return {self.key_yaml: dic}
|
return {self.key_yaml: dic}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ jinja2 template generator
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import inspect
|
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
@@ -24,10 +23,13 @@ COMMENT_END = '@@#}'
|
|||||||
|
|
||||||
class Templategen:
|
class Templategen:
|
||||||
|
|
||||||
def __init__(self, base='.', variables={}, debug=False):
|
def __init__(self, base='.', variables={},
|
||||||
|
func_file=[], filter_file=[], debug=False):
|
||||||
"""constructor
|
"""constructor
|
||||||
@base: directory path where to search for templates
|
@base: directory path where to search for templates
|
||||||
@variables: dictionary of variables for templates
|
@variables: dictionary of variables for templates
|
||||||
|
@func_file: file path to load functions from
|
||||||
|
@filter_file: file path to load filters from
|
||||||
@debug: enable debug
|
@debug: enable debug
|
||||||
"""
|
"""
|
||||||
self.base = base.rstrip(os.sep)
|
self.base = base.rstrip(os.sep)
|
||||||
@@ -50,20 +52,22 @@ class Templategen:
|
|||||||
# adding header method
|
# adding header method
|
||||||
self.env.globals['header'] = self._header
|
self.env.globals['header'] = self._header
|
||||||
# adding helper methods
|
# adding helper methods
|
||||||
|
if self.debug:
|
||||||
|
self.log.dbg('load global functions:')
|
||||||
self._load_funcs_to_dic(jhelpers, self.env.globals)
|
self._load_funcs_to_dic(jhelpers, self.env.globals)
|
||||||
|
if func_file:
|
||||||
|
for f in func_file:
|
||||||
|
if self.debug:
|
||||||
|
self.log.dbg('load custom functions from {}'.format(f))
|
||||||
|
self._load_path_to_dic(f, self.env.globals)
|
||||||
|
if filter_file:
|
||||||
|
for f in filter_file:
|
||||||
|
if self.debug:
|
||||||
|
self.log.dbg('load custom filters from {}'.format(f))
|
||||||
|
self._load_path_to_dic(f, self.env.filters)
|
||||||
if self.debug:
|
if self.debug:
|
||||||
self.log.dbg('template additional variables: {}'.format(variables))
|
self.log.dbg('template additional variables: {}'.format(variables))
|
||||||
|
|
||||||
def _load_funcs_to_dic(self, mod, dic):
|
|
||||||
"""dynamically load functions from module to dic"""
|
|
||||||
for m in inspect.getmembers(mod):
|
|
||||||
name, func = m
|
|
||||||
if not inspect.isfunction(func):
|
|
||||||
continue
|
|
||||||
if self.debug:
|
|
||||||
self.log.dbg('load function \"{}\"'.format(name))
|
|
||||||
dic[name] = func
|
|
||||||
|
|
||||||
def generate(self, src):
|
def generate(self, src):
|
||||||
"""render template from path"""
|
"""render template from path"""
|
||||||
if not os.path.exists(src):
|
if not os.path.exists(src):
|
||||||
@@ -92,6 +96,23 @@ class Templategen:
|
|||||||
"""update variables"""
|
"""update variables"""
|
||||||
self.env.globals.update(variables)
|
self.env.globals.update(variables)
|
||||||
|
|
||||||
|
def _load_path_to_dic(self, path, dic):
|
||||||
|
mod = utils.get_module_from_path(path)
|
||||||
|
if not mod:
|
||||||
|
self.log.warn('cannot load module \"{}\"'.format(path))
|
||||||
|
return
|
||||||
|
self._load_funcs_to_dic(mod, dic)
|
||||||
|
|
||||||
|
def _load_funcs_to_dic(self, mod, dic):
|
||||||
|
"""dynamically load functions from module to dic"""
|
||||||
|
if not mod or not dic:
|
||||||
|
return
|
||||||
|
funcs = utils.get_module_functions(mod)
|
||||||
|
for name, func in funcs:
|
||||||
|
if self.debug:
|
||||||
|
self.log.dbg('load function \"{}\"'.format(name))
|
||||||
|
dic[name] = func
|
||||||
|
|
||||||
def _header(self, prepend=''):
|
def _header(self, prepend=''):
|
||||||
"""add a comment usually in the header of a dotfile"""
|
"""add a comment usually in the header of a dotfile"""
|
||||||
return '{}{}'.format(prepend, utils.header())
|
return '{}{}'.format(prepend, utils.header())
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import os
|
|||||||
import uuid
|
import uuid
|
||||||
import shlex
|
import shlex
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import inspect
|
||||||
|
import importlib
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
|
|
||||||
# local import
|
# local import
|
||||||
@@ -192,3 +194,24 @@ def patch_ignores(ignores, prefix, debug=False):
|
|||||||
if debug:
|
if debug:
|
||||||
LOG.dbg('ignores after patching: {}'.format(new))
|
LOG.dbg('ignores after patching: {}'.format(new))
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_functions(mod):
|
||||||
|
"""return a list of fonction from a module"""
|
||||||
|
funcs = []
|
||||||
|
for m in inspect.getmembers(mod):
|
||||||
|
name, func = m
|
||||||
|
if not inspect.isfunction(func):
|
||||||
|
continue
|
||||||
|
funcs.append((name, func))
|
||||||
|
return funcs
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_from_path(path):
|
||||||
|
"""get module from path"""
|
||||||
|
if not path or not os.path.exists(path):
|
||||||
|
return None
|
||||||
|
module_name = os.path.basename(path).rstrip('.py')
|
||||||
|
loader = importlib.machinery.SourceFileLoader(module_name, path)
|
||||||
|
mod = loader.load_module()
|
||||||
|
return mod
|
||||||
|
|||||||
112
tests-ng/filter_file.sh
Executable file
112
tests-ng/filter_file.sh
Executable file
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# author: deadc0de6 (https://github.com/deadc0de6)
|
||||||
|
# Copyright (c) 2017, deadc0de6
|
||||||
|
#
|
||||||
|
# test jinja2 filters from filter_file
|
||||||
|
# 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 "$(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}"
|
||||||
|
filter_file=`mktemp`
|
||||||
|
filter_file2=`mktemp`
|
||||||
|
|
||||||
|
# create the config file
|
||||||
|
cfg="${tmps}/config.yaml"
|
||||||
|
|
||||||
|
cat > ${cfg} << _EOF
|
||||||
|
config:
|
||||||
|
backup: true
|
||||||
|
create: true
|
||||||
|
dotpath: dotfiles
|
||||||
|
filter_file:
|
||||||
|
- ${filter_file}
|
||||||
|
- ${filter_file2}
|
||||||
|
dotfiles:
|
||||||
|
f_abc:
|
||||||
|
dst: ${tmpd}/abc
|
||||||
|
src: abc
|
||||||
|
profiles:
|
||||||
|
p1:
|
||||||
|
dotfiles:
|
||||||
|
- f_abc
|
||||||
|
_EOF
|
||||||
|
#cat ${cfg}
|
||||||
|
|
||||||
|
cat << _EOF > ${filter_file}
|
||||||
|
def filter1(arg1):
|
||||||
|
return "filtered"
|
||||||
|
def filter2(arg1, arg2=''):
|
||||||
|
return arg2
|
||||||
|
_EOF
|
||||||
|
|
||||||
|
cat << _EOF > ${filter_file2}
|
||||||
|
def filter3(integer):
|
||||||
|
return str(int(integer) - 10)
|
||||||
|
_EOF
|
||||||
|
|
||||||
|
# create the dotfile
|
||||||
|
echo "this is the test dotfile" > ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
# test imported function
|
||||||
|
echo "{{@@ "abc" | filter1 @@}}" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "{{@@ "arg1" | filter2('arg2') @@}}" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "{{@@ "13" | filter3() @@}}" >> ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
# install
|
||||||
|
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
|
||||||
|
|
||||||
|
#cat ${tmpd}/abc
|
||||||
|
|
||||||
|
grep '^filtered$' ${tmpd}/abc >/dev/null
|
||||||
|
grep '^arg2$' ${tmpd}/abc >/dev/null
|
||||||
|
grep '^3$' ${tmpd}/abc >/dev/null
|
||||||
|
|
||||||
|
## CLEANING
|
||||||
|
rm -rf ${tmps} ${tmpd} ${filter_file} ${filter_file2}
|
||||||
|
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
127
tests-ng/func_file.sh
Executable file
127
tests-ng/func_file.sh
Executable file
@@ -0,0 +1,127 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# author: deadc0de6 (https://github.com/deadc0de6)
|
||||||
|
# Copyright (c) 2017, deadc0de6
|
||||||
|
#
|
||||||
|
# test jinja2 functions from func_file
|
||||||
|
# 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 "$(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}"
|
||||||
|
func_file=`mktemp`
|
||||||
|
func_file2=`mktemp`
|
||||||
|
|
||||||
|
# create the config file
|
||||||
|
cfg="${tmps}/config.yaml"
|
||||||
|
|
||||||
|
cat > ${cfg} << _EOF
|
||||||
|
config:
|
||||||
|
backup: true
|
||||||
|
create: true
|
||||||
|
dotpath: dotfiles
|
||||||
|
func_file:
|
||||||
|
- ${func_file}
|
||||||
|
- ${func_file2}
|
||||||
|
dotfiles:
|
||||||
|
f_abc:
|
||||||
|
dst: ${tmpd}/abc
|
||||||
|
src: abc
|
||||||
|
profiles:
|
||||||
|
p1:
|
||||||
|
dotfiles:
|
||||||
|
- f_abc
|
||||||
|
_EOF
|
||||||
|
#cat ${cfg}
|
||||||
|
|
||||||
|
cat << _EOF > ${func_file}
|
||||||
|
def func1(something):
|
||||||
|
if something:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
_EOF
|
||||||
|
|
||||||
|
cat << _EOF > ${func_file2}
|
||||||
|
def func2(inp):
|
||||||
|
return not inp
|
||||||
|
_EOF
|
||||||
|
|
||||||
|
# create the dotfile
|
||||||
|
echo "this is the test dotfile" > ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
# test imported function
|
||||||
|
echo "{%@@ if func1(True) @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "this should exist" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "{%@@ endif @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
echo "{%@@ if not func1(False) @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "this should exist too" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "{%@@ endif @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
echo "{%@@ if func2(True) @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "nope" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "{%@@ endif @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
echo "{%@@ if func2(False) @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "yes" >> ${tmps}/dotfiles/abc
|
||||||
|
echo "{%@@ endif @@%}" >> ${tmps}/dotfiles/abc
|
||||||
|
|
||||||
|
# install
|
||||||
|
cd ${ddpath} | ${bin} install -f -c ${cfg} -p p1 -V
|
||||||
|
|
||||||
|
#cat ${tmpd}/abc
|
||||||
|
|
||||||
|
grep '^this should exist$' ${tmpd}/abc >/dev/null
|
||||||
|
grep '^this should exist too$' ${tmpd}/abc >/dev/null
|
||||||
|
grep '^yes$' ${tmpd}/abc >/dev/null
|
||||||
|
set +e
|
||||||
|
grep '^nope$' ${tmpd}/abc >/dev/null && exit 1
|
||||||
|
set -e
|
||||||
|
|
||||||
|
## CLEANING
|
||||||
|
rm -rf ${tmps} ${tmpd} ${func_file} ${func_file2}
|
||||||
|
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user