1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-08 14:19:16 +00:00

debug log improvements

This commit is contained in:
deadc0de6
2020-06-23 10:25:30 +02:00
parent 2a67c49edd
commit e8f4d9afe8
8 changed files with 196 additions and 74 deletions

View File

@@ -34,15 +34,19 @@ class Cmd(DictParser):
if templater:
action = templater.generate_string(self.action)
if debug:
self.log.dbg('{} \"{}\" -> \"{}\"'.format(self.descr,
self.action,
action))
self.log.dbg('{}:'.format(self.descr))
self.log.dbg(' - raw \"{}\"'.format(self.action))
self.log.dbg(' - templated \"{}\"'.format(action))
cmd = action
args = []
if self.args:
args = self.args
if templater:
args = [templater.generate_string(a) for a in args]
if debug and args:
self.log.dbg('action args:')
for cnt, arg in enumerate(args):
self.log.dbg('\targs[{}]: {}'.format(cnt, arg))
try:
cmd = action.format(*args)
except IndexError:
@@ -57,7 +61,11 @@ class Cmd(DictParser):
return False
if self.silent:
self.log.sub('executing silent action \"{}\"'.format(self.key))
if debug:
self.log.dbg('action cmd silenced')
else:
if debug:
self.log.dbg('action cmd: \"{}\"'.format(cmd))
self.log.sub('executing \"{}\"'.format(cmd))
try:
ret = subprocess.call(cmd, shell=True)
@@ -124,8 +132,8 @@ class Action(Cmd):
return cls(key=key, **v)
def __str__(self):
out = '{}: \"{}\" ({})'
return out.format(self.key, self.action, self.kind)
out = '{}: [{}] \"{}\"'
return out.format(self.key, self.kind, self.action)
def __repr__(self):
return 'action({})'.format(self.__str__())

View File

@@ -50,38 +50,36 @@ class CfgAggregator:
# settings
self.settings = Settings.parse(None, self.cfgyaml.settings)
if self.debug:
self.log.dbg('settings: {}'.format(self.settings))
# dotfiles
self.dotfiles = Dotfile.parse_dict(self.cfgyaml.dotfiles)
if self.debug:
self.log.dbg('dotfiles: {}'.format(self.dotfiles))
self._debug_list('dotfiles', self.dotfiles)
# profiles
self.profiles = Profile.parse_dict(self.cfgyaml.profiles)
if self.debug:
self.log.dbg('profiles: {}'.format(self.profiles))
self._debug_list('profiles', self.profiles)
# actions
self.actions = Action.parse_dict(self.cfgyaml.actions)
if self.debug:
self.log.dbg('actions: {}'.format(self.actions))
self._debug_list('actions', self.actions)
# trans_r
self.trans_r = Transform.parse_dict(self.cfgyaml.trans_r)
if self.debug:
self.log.dbg('trans_r: {}'.format(self.trans_r))
self._debug_list('trans_r', self.trans_r)
# trans_w
self.trans_w = Transform.parse_dict(self.cfgyaml.trans_w)
if self.debug:
self.log.dbg('trans_w: {}'.format(self.trans_w))
self._debug_list('trans_w', self.trans_w)
# variables
self.variables = self.cfgyaml.get_variables()
if self.debug:
self.log.dbg('variables: {}'.format(self.variables))
self._debug_dict('variables', self.variables)
# patch dotfiles in profiles
self._patch_keys_to_objs(self.profiles,
@@ -403,3 +401,19 @@ class CfgAggregator:
path = os.path.expandvars(path)
path = os.path.abspath(path)
return path
def _debug_list(self, title, elems):
"""pretty print list"""
if not self.debug:
return
self.log.dbg('{}:'.format(title))
for e in elems:
self.log.dbg('\t- {}'.format(e))
def _debug_dict(self, title, elems):
"""pretty print dict"""
if not self.debug:
return
self.log.dbg('{}:'.format(title))
for k, v in elems.items():
self.log.dbg('\t- \"{}\": {}'.format(k, v))

View File

@@ -104,7 +104,7 @@ class CfgYaml:
# parse to self variables
self._parse_main_yaml(self.yaml_dict)
if self.debug:
self.log.dbg('before normalization: {}'.format(self.yaml_dict))
self.log.dbg('BEFORE normalization: {}'.format(self.yaml_dict))
# resolve variables
self.variables, self.prokeys = self._merge_variables()
@@ -129,7 +129,7 @@ class CfgYaml:
self._resolve_dotfile_paths()
if self.debug:
self.log.dbg('after normalization: {}'.format(self.yaml_dict))
self.log.dbg('AFTER normalization: {}'.format(self.yaml_dict))
def get_variables(self):
"""retrieve all variables"""
@@ -166,7 +166,7 @@ class CfgYaml:
]
self.settings[Settings.key_func_file] = p
if self.debug:
self.log.dbg('settings: {}'.format(self.settings))
self._debug_dict('settings', self.settings)
# dotfiles
self.ori_dotfiles = self._get_entry(dic, self.key_dotfiles)
@@ -178,14 +178,14 @@ class CfgYaml:
raise YamlException(err)
self.dotfiles = self._norm_dotfiles(self.dotfiles)
if self.debug:
self.log.dbg('dotfiles: {}'.format(self.dotfiles))
self._debug_dict('dotfiles', self.dotfiles)
# profiles
self.ori_profiles = self._get_entry(dic, self.key_profiles)
self.profiles = deepcopy(self.ori_profiles)
self.profiles = self._norm_profiles(self.profiles)
if self.debug:
self.log.dbg('profiles: {}'.format(self.profiles))
self._debug_dict('profiles', self.profiles)
# actions
self.ori_actions = self._get_entry(dic, self.key_actions,
@@ -193,7 +193,7 @@ class CfgYaml:
self.actions = deepcopy(self.ori_actions)
self.actions = self._norm_actions(self.actions)
if self.debug:
self.log.dbg('actions: {}'.format(self.actions))
self._debug_dict('actions', self.actions)
# trans_r
key = self.key_trans_r
@@ -204,28 +204,28 @@ class CfgYaml:
self.ori_trans_r = self._get_entry(dic, key, mandatory=False)
self.trans_r = deepcopy(self.ori_trans_r)
if self.debug:
self.log.dbg('trans_r: {}'.format(self.trans_r))
self._debug_dict('trans_r', self.trans_r)
# trans_w
self.ori_trans_w = self._get_entry(dic, self.key_trans_w,
mandatory=False)
self.trans_w = deepcopy(self.ori_trans_w)
if self.debug:
self.log.dbg('trans_w: {}'.format(self.trans_w))
self._debug_dict('trans_w', self.trans_w)
# variables
self.ori_variables = self._get_entry(dic,
self.key_variables,
mandatory=False)
if self.debug:
self.log.dbg('variables: {}'.format(self.ori_variables))
self._debug_dict('variables', self.ori_variables)
# dynvariables
self.ori_dvariables = self._get_entry(dic,
self.key_dvariables,
mandatory=False)
if self.debug:
self.log.dbg('dynvariables: {}'.format(self.ori_dvariables))
self._debug_dict('dynvariables', self.ori_dvariables)
def _resolve_dotfile_paths(self):
"""resolve dotfiles paths"""
@@ -305,13 +305,14 @@ class CfgYaml:
# temporarly resolve all variables for "include"
merged = self._merge_dict(dvar, var)
merged = self._rec_resolve_vars(merged)
self._debug_vars(merged)
if self.debug:
self._debug_dict('variables', merged)
# exec dynvariables
self._shell_exec_dvars(dvar.keys(), merged)
if self.debug:
self.log.dbg('local variables resolved')
self._debug_vars(merged)
self._debug_dict('variables', merged)
# resolve profile includes
t = Templategen(variables=merged,
@@ -340,7 +341,7 @@ class CfgYaml:
if self.debug:
self.log.dbg('resolve all uses of variables in config')
self._debug_vars(merged)
self._debug_dict('variables', merged)
prokeys = list(pro_var.keys()) + list(pro_dvar.keys())
return merged, prokeys
@@ -751,7 +752,7 @@ class CfgYaml:
self._clear_profile_vars(sub.variables)
if self.debug:
self.log.dbg('add import_configs var: {}'.format(sub.variables))
self._debug_dict('add import_configs var', sub.variables)
self.variables = self._merge_dict(sub.variables, self.variables)
def _import_configs(self):
@@ -997,6 +998,14 @@ class CfgYaml:
def _load_yaml(self, path):
"""load a yaml file to a dict"""
content = {}
if self.debug:
self.log.dbg('----------start:{}----------'.format(path))
cfg = '\n'
with open(path, 'r') as f:
for line in f:
cfg += line
self.log.dbg(cfg.rstrip())
self.log.dbg('----------end:{}----------'.format(path))
try:
content = self._yaml_load(path)
except Exception as e:
@@ -1074,29 +1083,22 @@ class CfgYaml:
expanded_path = os.path.expanduser(path)
return glob.glob(expanded_path, recursive=True)
def _debug_vars(self, variables):
"""pretty print variables"""
if not self.debug:
return
self.log.dbg('variables:')
for k, v in variables.items():
self.log.dbg('\t\"{}\": {}'.format(k, v))
def _norm_path(self, path):
"""Resolve a path either absolute or relative to config path"""
if self.debug:
self.log.dbg('normalizing path {}'.format(path))
if not path:
return path
path = os.path.expanduser(path)
if not os.path.isabs(path):
if self.debug:
self.log.dbg('normalizing path {} relative to config file '
'directory'.format(path))
d = os.path.dirname(self.path)
return os.path.join(d, path)
return os.path.normpath(path)
ret = os.path.join(d, path)
if self.debug:
msg = 'normalizing relative to cfg: {} -> {}'
self.log.dbg(msg.format(path, ret))
return ret
ret = os.path.normpath(path)
if self.debug and path != ret:
self.log.dbg('normalizing: {} -> {}'.format(path, ret))
return ret
def _shell_exec_dvars(self, keys, variables):
"""shell execute dynvariables"""
@@ -1135,3 +1137,13 @@ class CfgYaml:
err = 'current dotdrop version is too old for that config file.'
err += ' Please update.'
raise YamlException(err)
def _debug_dict(self, title, elems):
"""pretty print dict"""
if not self.debug:
return
self.log.dbg('{}:'.format(title))
if not elems:
return
for k, v in elems.items():
self.log.dbg('\t- \"{}\": {}'.format(k, v))

View File

@@ -47,7 +47,7 @@ def action_executor(o, actions, defactions, templater, post=False):
action))
continue
if o.debug:
LOG.dbg('executing def-{}-action {}'.format(s, action))
LOG.dbg('executing def-{}-action: {}'.format(s, action))
ret = action.execute(templater=templater, debug=o.debug)
if not ret:
err = 'def-{}-action \"{}\" failed'.format(s, action.key)
@@ -60,7 +60,7 @@ def action_executor(o, actions, defactions, templater, post=False):
LOG.dry('would execute {}-action: {}'.format(s, action))
continue
if o.debug:
LOG.dbg('executing {}-action {}'.format(s, action))
LOG.dbg('executing {}-action: {}'.format(s, action))
ret = action.execute(templater=templater, debug=o.debug)
if not ret:
err = '{}-action \"{}\" failed'.format(s, action.key)
@@ -105,7 +105,7 @@ def cmd_install(o):
# execute profile pre-action
if o.debug:
LOG.dbg('execute profile pre actions')
LOG.dbg('run {} profile pre actions'.format(len(pro_pre_actions)))
ret, err = action_executor(o, pro_pre_actions, [], t, post=False)()
if not ret:
return False
@@ -125,7 +125,8 @@ def cmd_install(o):
t, post=False)
if o.debug:
LOG.dbg('installing {}'.format(dotfile))
LOG.dbg('installing dotfile: \"{}\"'.format(dotfile.key))
LOG.dbg(dotfile.prt())
if hasattr(dotfile, 'link') and dotfile.link == LinkTypes.LINK:
r, err = inst.link(t, dotfile.src, dotfile.dst,
actionexec=pre_actions_exec)
@@ -181,11 +182,15 @@ def cmd_install(o):
# execute profile post-action
if installed > 0 or o.install_force_action:
if o.debug:
LOG.dbg('execute profile post actions')
msg = 'run {} profile post actions'
LOG.dbg(msg.format(len(pro_post_actions)))
ret, err = action_executor(o, pro_post_actions, [], t, post=False)()
if not ret:
return False
if o.debug:
LOG.dbg('install done')
if o.install_temporary:
LOG.log('\ninstalled to tmp \"{}\".'.format(tmpdir))
LOG.log('\n{} dotfile(s) installed.'.format(installed))
@@ -628,7 +633,7 @@ def apply_trans(dotpath, dotfile, templater, debug=False):
new_src = '{}.{}'.format(src, TRANS_SUFFIX)
trans = dotfile.trans_r
if debug:
LOG.dbg('executing transformation {}'.format(trans))
LOG.dbg('executing transformation: {}'.format(trans))
s = os.path.join(dotpath, src)
temp = os.path.join(dotpath, new_src)
if not trans.transform(s, temp, templater=templater, debug=debug):

View File

@@ -107,5 +107,36 @@ class Dotfile(DictParser):
msg = 'key:\"{}\", src:\"{}\", dst:\"{}\", link:\"{}\"'
return msg.format(self.key, self.src, self.dst, str(self.link))
def prt(self):
"""extended dotfile to str"""
indent = ' '
out = 'dotfile: \"{}\"'.format(self.key)
out += '\n{}src: \"{}\"'.format(indent, self.src)
out += '\n{}dst: \"{}\"'.format(indent, self.dst)
out += '\n{}link: \"{}\"'.format(indent, str(self.link))
out += '\n{}pre-action:'.format(indent)
some = self.get_pre_actions()
if some:
for a in some:
out += '\n{}- {}'.format(2 * indent, a)
out += '\n{}post-action:'.format(indent)
some = self.get_post_actions()
if some:
for a in some:
out += '\n{}- {}'.format(2 * indent, a)
out += '\n{}trans_r:'.format(indent)
some = self.get_trans_r()
if some:
out += '\n{}- {}'.format(2 * indent, some)
out += '\n{}trans_w:'.format(indent)
some = self.get_trans_w()
if some:
out += '\n{}- {}'.format(2 * indent, some)
return out
def __repr__(self):
return 'dotfile({!s})'.format(self)

View File

@@ -50,6 +50,18 @@ class Installer:
self.action_executed = False
self.log = Logger()
def _log_install(self, boolean, err):
if not self.debug:
return boolean, err
if boolean:
self.log.dbg('install: SUCCESS')
else:
if err:
self.log.dbg('install: ERROR: {}'.format(err))
else:
self.log.dbg('install: IGNORED')
return boolean, err
def install(self, templater, src, dst,
actionexec=None, noempty=False,
ignore=[]):
@@ -68,34 +80,36 @@ class Installer:
- False, None : ignored
"""
if self.debug:
self.log.dbg('install \"{}\" to \"{}\"'.format(src, dst))
self.log.dbg('installing \"{}\" to \"{}\"'.format(src, dst))
if not dst or not src:
if self.debug:
self.log.dbg('empty dst for {}'.format(src))
return True, None
return self._log_install(True, None)
self.action_executed = False
src = os.path.join(self.base, os.path.expanduser(src))
if not os.path.exists(src):
err = 'source dotfile does not exist: {}'.format(src)
return False, err
return self._log_install(False, err)
dst = os.path.expanduser(dst)
if self.totemp:
dst = self._pivot_path(dst, self.totemp)
if utils.samefile(src, dst):
# symlink loop
err = 'dotfile points to itself: {}'.format(dst)
return False, err
return self._log_install(False, err)
isdir = os.path.isdir(src)
if self.debug:
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:
return self._handle_dir(templater, src, dst,
b, e = self._handle_dir(templater, src, dst,
actionexec=actionexec,
noempty=noempty, ignore=ignore)
return self._handle_file(templater, src, dst,
return self._log_install(b, e)
b, e = self._handle_file(templater, src, dst,
actionexec=actionexec,
noempty=noempty, ignore=ignore)
return self._log_install(b, e)
def link(self, templater, src, dst, actionexec=None):
"""
@@ -115,17 +129,18 @@ class Installer:
if not dst or not src:
if self.debug:
self.log.dbg('empty dst for {}'.format(src))
return True, None
return self._log_install(True, None)
self.action_executed = False
src = os.path.normpath(os.path.join(self.base,
os.path.expanduser(src)))
if not os.path.exists(src):
err = 'source dotfile does not exist: {}'.format(src)
return False, err
return self._log_install(False, err)
dst = os.path.normpath(os.path.expanduser(dst))
if self.totemp:
# ignore actions
return self.install(templater, src, dst, actionexec=None)
b, e = self.install(templater, src, dst, actionexec=None)
return self._log_install(b, e)
if Templategen.is_template(src):
if self.debug:
@@ -134,9 +149,10 @@ class Installer:
tmp = self._pivot_path(dst, self.workdir, striphome=True)
i, err = self.install(templater, src, tmp, actionexec=actionexec)
if not i and not os.path.exists(tmp):
return i, err
return self._log_install(i, err)
src = tmp
return self._link(src, dst, actionexec=actionexec)
b, e = self._link(src, dst, actionexec=actionexec)
return self._log_install(b, e)
def link_children(self, templater, src, dst, actionexec=None):
"""
@@ -156,14 +172,14 @@ class Installer:
if not dst or not src:
if self.debug:
self.log.dbg('empty dst for {}'.format(src))
return True, None
return self._log_install(True, None)
self.action_executed = False
parent = os.path.join(self.base, os.path.expanduser(src))
# Fail if source doesn't exist
if not os.path.exists(parent):
err = 'source dotfile does not exist: {}'.format(parent)
return False, err
return self._log_install(False, err)
# Fail if source not a directory
if not os.path.isdir(parent):
@@ -171,7 +187,7 @@ class Installer:
self.log.dbg('symlink children of {} to {}'.format(src, dst))
err = 'source dotfile is not a directory: {}'.format(parent)
return False, err
return self._log_install(False, err)
dst = os.path.normpath(os.path.expanduser(dst))
if not os.path.lexists(dst):
@@ -186,7 +202,7 @@ class Installer:
if self.safe and not self.log.ask(msg):
err = 'ignoring "{}", nothing installed'.format(dst)
return False, err
return self._log_install(False, err)
os.unlink(dst)
os.mkdir(dst)
@@ -224,8 +240,9 @@ class Installer:
else:
if err:
return ret, err
return self._log_install(ret, err)
return installed > 0, None
return self._log_install(installed > 0, None)
def _link(self, src, dst, actionexec=None):
"""
@@ -429,7 +446,7 @@ class Installer:
if not r:
return -1, e
if self.debug:
self.log.dbg('write content to {}'.format(dst))
self.log.dbg('writes content to \"{}\"'.format(dst))
# re-check in case action created the file
if self.safe and not overwrite and os.path.lexists(dst):
if not self.log.ask('Overwrite \"{}\"'.format(dst)):

View File

@@ -184,9 +184,8 @@ class Options(AttrMonitor):
self.conf = Cfg(self.confpath, self.profile, debug=self.debug,
dry=self.dry)
# transform the config settings to self attribute
self._debug_dict('effective settings', self.conf.get_settings())
for k, v in self.conf.get_settings().items():
if self.debug:
self.log.dbg('new setting: {}={}'.format(k, v))
setattr(self, k, v)
def _apply_args(self):
@@ -267,15 +266,41 @@ class Options(AttrMonitor):
"""debug display all of this class attributes"""
if not self.debug:
return
self.log.dbg('CLI options:')
self.log.dbg('effective options:')
for att in dir(self):
if att.startswith('_'):
continue
val = getattr(self, att)
if callable(val):
continue
self.log.dbg('- {}: {}'.format(att, val))
if type(val) is list:
self._debug_list('-> {}'.format(att), val)
elif type(val) is dict:
self._debug_dict('-> {}'.format(att), val)
else:
self.log.dbg('-> {}: {}'.format(att, val))
def _attr_set(self, attr):
"""error when some inexistent attr is set"""
raise Exception('bad option: {}'.format(attr))
def _debug_list(self, title, elems):
"""pretty print list"""
if not self.debug:
return
self.log.dbg('{}:'.format(title))
for e in elems:
self.log.dbg('\t- {}'.format(e))
def _debug_dict(self, title, elems):
"""pretty print dict"""
if not self.debug:
return
self.log.dbg('{}:'.format(title))
for k, v in elems.items():
if type(v) is list:
self.log.dbg('\t- \"{}\":'.format(k))
for i in v:
self.log.dbg('\t\t- {}'.format(i))
else:
self.log.dbg('\t- \"{}\": {}'.format(k, v))

View File

@@ -69,7 +69,7 @@ class Templategen:
self.log.dbg('load custom filters from {}'.format(f))
self._load_path_to_dic(f, self.env.filters)
if self.debug:
self.log.dbg('template additional variables: {}'.format(variables))
self._debug_dict('template additional variables', variables)
def generate(self, src):
"""render template from path"""
@@ -126,10 +126,10 @@ class Templategen:
raw=False, debug=self.debug)
filetype = filetype.strip()
if self.debug:
self.log.dbg('\"{}\" filetype: {}'.format(src, filetype))
self.log.dbg('filetype \"{}\": {}'.format(src, filetype))
istext = self._is_text(filetype)
if self.debug:
self.log.dbg('\"{}\" is text: {}'.format(src, istext))
self.log.dbg('is text \"{}\": {}'.format(src, istext))
if not istext:
return self._handle_bin_file(src)
return self._handle_text_file(src)
@@ -223,3 +223,13 @@ class Templategen:
if marker in data:
return True
return False
def _debug_dict(self, title, elems):
"""pretty print dict"""
if not self.debug:
return
self.log.dbg('{}:'.format(title))
if not elems:
return
for k, v in elems.items():
self.log.dbg(' - \"{}\": {}'.format(k, v))