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

Merge pull request #257 from deadc0de6/bug250

Bug250
This commit is contained in:
deadc0de
2020-09-12 13:30:11 +02:00
committed by GitHub
98 changed files with 1787 additions and 704 deletions

View File

@@ -11,6 +11,7 @@ import os
# local imports
from dotdrop.dictparser import DictParser
from dotdrop.exceptions import UndefinedException
class Cmd(DictParser):
@@ -32,7 +33,12 @@ class Cmd(DictParser):
ret = 1
action = self.action
if templater:
action = templater.generate_string(self.action)
try:
action = templater.generate_string(self.action)
except UndefinedException as e:
err = 'bad {}: {}'.format(self.descr, e)
self.log.warn(err)
return False
if debug:
self.log.dbg('{}:'.format(self.descr))
self.log.dbg(' - raw \"{}\"'.format(self.action))
@@ -42,7 +48,12 @@ class Cmd(DictParser):
if self.args:
args = self.args
if templater:
args = [templater.generate_string(a) for a in args]
try:
args = [templater.generate_string(a) for a in args]
except UndefinedException as e:
err = 'bad arguments for {}: {}'.format(self.descr, e)
self.log.warn(err)
return False
if debug and args:
self.log.dbg('action args:')
for cnt, arg in enumerate(args):

View File

@@ -17,6 +17,7 @@ from dotdrop.profile import Profile
from dotdrop.action import Action, Transform
from dotdrop.logger import Logger
from dotdrop.utils import strip_home
from dotdrop.exceptions import UndefinedException
TILD = '~'
@@ -77,7 +78,7 @@ class CfgAggregator:
self._debug_list('trans_w', self.trans_w)
# variables
self.variables = self.cfgyaml.get_variables()
self.variables = self.cfgyaml.variables
if self.debug:
self._debug_dict('variables', self.variables)
@@ -134,8 +135,9 @@ class CfgAggregator:
objects.append(o)
if not islist:
objects = objects[0]
if self.debug:
self.log.dbg('patching {}.{} with {}'.format(c, keys, objects))
# if self.debug:
# er = 'patching {}.{} with {}'
# self.log.dbg(er.format(c, keys, objects))
setattr(c, keys, objects)
def del_dotfile(self, dotfile):
@@ -281,7 +283,12 @@ class CfgAggregator:
@src: dotfile src (in dotpath)
@dst: dotfile dst (on filesystem)
"""
src = self.cfgyaml.resolve_dotfile_src(src)
try:
src = self.cfgyaml.resolve_dotfile_src(src)
except UndefinedException as e:
err = 'unable to resolve {}: {}'
self.log.err(err.format(src, e))
return None
dotfiles = self.get_dotfile_by_dst(dst)
for d in dotfiles:
if d.src == src:

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@ from dotdrop.comparator import Comparator
from dotdrop.utils import get_tmpdir, remove, strip_home, \
run, uniq_list, patch_ignores, dependencies_met
from dotdrop.linktypes import LinkTypes
from dotdrop.exceptions import YamlException
from dotdrop.exceptions import YamlException, UndefinedException
LOG = Logger()
TRANS_SUFFIX = 'trans'
@@ -230,6 +230,7 @@ def cmd_compare(o, tmp):
newvars = dotfile.get_dotfile_variables()
t.add_tmp_vars(newvars=newvars)
# dotfiles does not exist / not installed
if o.debug:
LOG.dbg('comparing {}'.format(dotfile))
src = dotfile.src
@@ -239,9 +240,9 @@ def cmd_compare(o, tmp):
same = False
continue
# apply transformation
tmpsrc = None
if dotfile.trans_r:
# apply transformation
if o.debug:
LOG.dbg('applying transformation before comparing')
tmpsrc = apply_trans(o.dotpath, dotfile, t, debug=o.debug)
@@ -261,20 +262,26 @@ def cmd_compare(o, tmp):
LOG.dbg('points to itself')
continue
# install dotfile to temporary dir
ret, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst)
# install dotfile to temporary dir and compare
ret, err, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst)
if not ret:
# failed to install to tmp
line = '=> compare {}: error'
LOG.log(line.format(dotfile.key, err))
LOG.err(err)
same = False
continue
ignores = list(set(o.compare_ignore + dotfile.cmpignore))
ignores = patch_ignores(ignores, dotfile.dst, debug=o.debug)
diff = comp.compare(insttmp, dotfile.dst, ignore=ignores)
# clean tmp transformed dotfile if any
if tmpsrc:
# clean tmp transformed dotfile if any
tmpsrc = os.path.join(o.dotpath, tmpsrc)
if os.path.exists(tmpsrc):
remove(tmpsrc)
# print diff result
if diff == '':
if o.debug:
line = '=> compare {}: diffing with \"{}\"'
@@ -655,7 +662,10 @@ def main():
try:
o = Options()
except YamlException as e:
LOG.err('config file error: {}'.format(str(e)))
LOG.err('config error: {}'.format(str(e)))
return False
except UndefinedException as e:
LOG.err('config error: {}'.format(str(e)))
return False
if o.debug:

View File

@@ -9,3 +9,8 @@ diverse exceptions
class YamlException(Exception):
"""exception in CfgYaml"""
pass
class UndefinedException(Exception):
"""exception in templating"""
pass

View File

@@ -12,6 +12,7 @@ import errno
from dotdrop.logger import Logger
from dotdrop.templategen import Templategen
import dotdrop.utils as utils
from dotdrop.exceptions import UndefinedException
class Installer:
@@ -239,7 +240,6 @@ class Installer:
actionexec = None
else:
if err:
return ret, err
return self._log_install(ret, err)
return self._log_install(installed > 0, None)
@@ -325,8 +325,12 @@ class Installer:
err = 'dotfile points to itself: {}'.format(dst)
return False, err
saved = templater.add_tmp_vars(self._get_tmp_file_vars(src, dst))
content = templater.generate(src)
templater.restore_vars(saved)
try:
content = templater.generate(src)
except UndefinedException as e:
return False, str(e)
finally:
templater.restore_vars(saved)
if noempty and utils.content_empty(content):
if self.debug:
self.log.dbg('ignoring empty template: {}'.format(src))
@@ -547,9 +551,10 @@ class Installer:
src = os.path.expanduser(src)
dst = os.path.expanduser(dst)
if self.debug:
self.log.dbg('tmp install {} to {}'.format(src, dst))
self.log.dbg('tmp install {} (defined dst: {})'.format(src, dst))
# install the dotfile to a temp directory for comparing
ret, tmpdst = self._install_to_temp(templater, src, dst, tmpdir)
r, tmpdst = self._install_to_temp(templater, src, dst, tmpdir)
ret, err = r
if self.debug:
self.log.dbg('tmp installed in {}'.format(tmpdst))
# reset flags
@@ -557,4 +562,4 @@ class Installer:
self.diff = diffsaved
self.comparing = False
self.create = createsaved
return ret, tmpdst
return ret, err, tmpdst

View File

@@ -109,9 +109,11 @@ class Options(AttrMonitor):
"""constructor
@args: argument dictionary (if None use sys)
"""
self.args = args
self.args = {}
if not args:
self.args = docopt(USAGE, version=VERSION)
if args:
self.args = args.copy()
self.log = Logger()
self.debug = self.args['--verbose'] or ENV_DEBUG in os.environ
self.dry = self.args['--dry']
@@ -122,6 +124,7 @@ class Options(AttrMonitor):
self.confpath = self._get_config_path()
if self.debug:
self.log.dbg('version: {}'.format(VERSION))
self.log.dbg('command: {}'.format(' '.join(sys.argv)))
self.log.dbg('config file: {}'.format(self.confpath))
self._read_config()

View File

@@ -7,12 +7,16 @@ jinja2 template generator
import os
from jinja2 import Environment, FileSystemLoader, \
ChoiceLoader, FunctionLoader, TemplateNotFound
ChoiceLoader, FunctionLoader, TemplateNotFound, \
StrictUndefined
from jinja2.exceptions import UndefinedError
# local imports
import dotdrop.utils as utils
from dotdrop.logger import Logger
import dotdrop.jhelpers as jhelpers
from dotdrop.exceptions import UndefinedException
BLOCK_START = '{%@@'
BLOCK_END = '@@%}'
@@ -36,6 +40,7 @@ class Templategen:
self.base = base.rstrip(os.sep)
self.debug = debug
self.log = Logger()
self.variables = {}
loader1 = FileSystemLoader(self.base)
loader2 = FunctionLoader(self._template_loader)
loader = ChoiceLoader([loader1, loader2])
@@ -47,11 +52,14 @@ class Templategen:
variable_start_string=VAR_START,
variable_end_string=VAR_END,
comment_start_string=COMMENT_START,
comment_end_string=COMMENT_END)
comment_end_string=COMMENT_END,
undefined=StrictUndefined)
# adding variables
self.env.globals['env'] = os.environ
self.variables['env'] = os.environ
if variables:
self.env.globals.update(variables)
self.variables.update(variables)
# adding header method
self.env.globals['header'] = self._header
# adding helper methods
@@ -72,32 +80,48 @@ class Templategen:
self._debug_dict('template additional variables', variables)
def generate(self, src):
"""render template from path"""
"""
render template from path
may raise a UndefinedException
in case a variable is undefined
"""
if not os.path.exists(src):
return ''
return self._handle_file(src)
try:
return self._handle_file(src)
except UndefinedError as e:
err = 'undefined variable: {}'.format(e.message)
raise UndefinedException(err)
def generate_string(self, string):
"""render template from string"""
"""
render template from string
may raise a UndefinedException
in case a variable is undefined
"""
if not string:
return ''
return self.env.from_string(string).render()
try:
return self.env.from_string(string).render(self.variables)
except UndefinedError as e:
err = 'undefined variable: {}'.format(e.message)
raise UndefinedException(err)
def add_tmp_vars(self, newvars={}):
"""add vars to the globals, make sure to call restore_vars"""
saved_globals = self.env.globals.copy()
saved_variables = self.variables.copy()
if not newvars:
return saved_globals
self.env.globals.update(newvars)
return saved_globals
return saved_variables
self.variables.update(newvars)
return saved_variables
def restore_vars(self, saved_globals):
"""restore globals from add_tmp_vars"""
self.env.globals = saved_globals.copy()
self.variables = saved_globals.copy()
def update_variables(self, variables):
"""update variables"""
self.env.globals.update(variables)
self.variables.update(variables)
def _load_path_to_dic(self, path, dic):
mod = utils.get_module_from_path(path)
@@ -160,7 +184,7 @@ class Templategen:
template_rel_path = os.path.relpath(src, self.base)
try:
template = self.env.get_template(template_rel_path)
content = template.render()
content = template.render(self.variables)
except UnicodeDecodeError:
data = self._read_bad_encoded_text(src)
content = self.generate_string(data)

View File

@@ -14,6 +14,7 @@ from dotdrop.logger import Logger
from dotdrop.templategen import Templategen
from dotdrop.utils import patch_ignores, remove, get_unique_tmp_name, \
write_to_tmpfile, must_ignore, mirror_file_rights
from dotdrop.exceptions import UndefinedException
TILD = '~'
@@ -186,7 +187,11 @@ class Updater:
if self.debug:
self.log.dbg('{} is a template'.format(dtpath))
if self.showpatch:
self._show_patch(path, dtpath)
try:
self._show_patch(path, dtpath)
except UndefinedException as e:
msg = 'unable to show patch for {}: {}'.format(path, e)
self.log.warn(msg)
return False
if compare and filecmp.cmp(path, dtpath, shallow=False) and \
self._same_rights(path, dtpath):