1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-04 18:34:48 +00:00
This commit is contained in:
deadc0de6
2021-04-29 14:31:28 +02:00
parent 9ae90d5109
commit d7dc7da33b
3 changed files with 80 additions and 60 deletions

View File

@@ -4,10 +4,11 @@ Copyright (c) 2017, deadc0de6
"""
import sys
import dotdrop.dotdrop
def main():
import dotdrop.dotdrop
"""entry point"""
if dotdrop.dotdrop.main():
sys.exit(0)
sys.exit(1)

View File

@@ -15,6 +15,9 @@ from dotdrop.exceptions import UndefinedException
class Cmd(DictParser):
"""A command to execute"""
args = []
eq_ignore = ('log',)
descr = 'command'
@@ -28,46 +31,58 @@ class Cmd(DictParser):
self.action = action
self.silent = key.startswith('_')
def _get_action(self, templater, debug):
action = None
try:
action = templater.generate_string(self.action)
except UndefinedException as exc:
err = 'undefined variable for {}: \"{}\"'.format(self.descr, exc)
self.log.warn(err)
return False
if debug:
self.log.dbg('{}:'.format(self.descr))
self.log.dbg(' - raw \"{}\"'.format(self.action))
self.log.dbg(' - templated \"{}\"'.format(action))
return action
def _get_args(self, templater):
args = []
if not self.args:
return args
args = self.args
if templater:
try:
args = [templater.generate_string(a) for a in args]
except UndefinedException as exc:
err = 'undefined arguments for {}: {}'
self.log.warn(err.format(self.descr, exc))
return False
return args
def execute(self, templater=None, debug=False):
"""execute the command in the shell"""
ret = 1
action = self.action
if templater:
try:
action = templater.generate_string(self.action)
except UndefinedException as e:
err = 'undefined variable for {}: \"{}\"'.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))
self.log.dbg(' - templated \"{}\"'.format(action))
action = self._get_action(templater, debug)
cmd = action
args = []
if self.args:
args = self.args
if templater:
try:
args = [templater.generate_string(a) for a in args]
except UndefinedException as e:
err = 'undefined arguments for {}: {}'
self.log.warn(err.format(self.descr, e))
return False
args = self._get_args(templater)
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 as e:
except IndexError as exc:
err = 'index error for {}: \"{}\"'.format(self.descr, action)
err += ' with \"{}\"'.format(args)
err += ': {}'.format(e)
err += ': {}'.format(exc)
self.log.warn(err)
return False
except KeyError as e:
err = 'key error for {}: \"{}\": {}'.format(self.descr, action, e)
except KeyError as exc:
err = 'key error for {}: \"{}\": {}'.format(self.descr,
action,
exc)
err += ' with \"{}\"'.format(args)
self.log.warn(err)
return False
@@ -96,6 +111,7 @@ class Cmd(DictParser):
class Action(Cmd):
"""An action to execute"""
pre = 'pre'
post = 'post'
@@ -107,7 +123,7 @@ class Action(Cmd):
@kind: type of action (pre or post)
@action: action string
"""
super(Action, self).__init__(key, action)
super().__init__(key, action)
self.kind = kind
self.args = []
@@ -120,9 +136,9 @@ class Action(Cmd):
@classmethod
def parse(cls, key, value):
"""parse key value into object"""
v = {}
v['kind'], v['action'] = value
return cls(key=key, **v)
val = {}
val['kind'], val['action'] = value
return cls(key=key, **val)
def __str__(self):
out = '{}: [{}] \"{}\"'
@@ -133,6 +149,8 @@ class Action(Cmd):
class Transform(Cmd):
"""A transformation on a dotfile"""
descr = 'transformation'
def __init__(self, key, action):
@@ -140,7 +158,7 @@ class Transform(Cmd):
@key: action key
@trans: action string
"""
super(Transform, self).__init__(key, action)
super().__init__(key, action)
self.args = []
def copy(self, args):

View File

@@ -24,6 +24,7 @@ TILD = '~'
class CfgAggregator:
"""The config aggregator class"""
file_prefix = 'f'
dir_prefix = 'd'
@@ -106,10 +107,10 @@ class CfgAggregator:
"""
dotfiles = []
dst = self._norm_path(dst)
for d in self.dotfiles:
left = self._norm_path(d.dst)
for dotfile in self.dotfiles:
left = self._norm_path(dotfile.dst)
if left == dst:
dotfiles.append(d)
dotfiles.append(dotfile)
return dotfiles
def get_dotfile_by_src_dst(self, src, dst):
@@ -120,14 +121,14 @@ class CfgAggregator:
"""
try:
src = self.cfgyaml.resolve_dotfile_src(src)
except UndefinedException as e:
except UndefinedException as exc:
err = 'unable to resolve {}: {}'
self.log.err(err.format(src, e))
self.log.err(err.format(src, exc))
return None
dotfiles = self.get_dotfile_by_dst(dst)
for d in dotfiles:
if d.src == src:
return d
for dotfile in dotfiles:
if dotfile.src == src:
return dotfile
return None
def save(self):
@@ -162,10 +163,10 @@ class CfgAggregator:
def get_profiles_by_dotfile_key(self, key):
"""return all profiles having this dotfile"""
res = []
for p in self.profiles:
keys = [d.key for d in p.dotfiles]
for profile in self.profiles:
keys = [dotfile.key for dotfile in profile.dotfiles]
if key in keys:
res.append(p)
res.append(profile)
return res
def get_dotfiles(self):
@@ -282,27 +283,27 @@ class CfgAggregator:
return
if self.debug:
self.log.dbg('patching {} ...'.format(keys))
for c in containers:
for container in containers:
objects = []
okeys = getattr(c, keys)
okeys = getattr(container, keys)
if not okeys:
continue
if not islist:
okeys = [okeys]
for k in okeys:
o = get_by_key(k)
if not o:
err = '{} does not contain'.format(c)
err += ' a {} entry named {}'.format(keys, k)
for key in okeys:
obj = get_by_key(key)
if not obj:
err = '{} does not contain'.format(container)
err += ' a {} entry named {}'.format(keys, key)
self.log.err(err)
raise Exception(err)
objects.append(o)
objects.append(obj)
if not islist:
objects = objects[0]
# if self.debug:
# er = 'patching {}.{} with {}'
# self.log.dbg(er.format(c, keys, objects))
setattr(c, keys, objects)
setattr(container, keys, objects)
########################################################
# dotfile key
@@ -341,8 +342,8 @@ class CfgAggregator:
dirs.reverse()
prefix = self.dir_prefix if os.path.isdir(path) else self.file_prefix
entries = []
for d in dirs:
entries.insert(0, d)
for dri in dirs:
entries.insert(0, dri)
key = self.key_sep.join([prefix] + entries)
if key not in keys:
return key
@@ -384,12 +385,12 @@ class CfgAggregator:
def _split_path_for_key(self, path):
"""return a list of path elements, excluded home path"""
p = strip_home(path)
path = strip_home(path)
dirs = []
while True:
p, f = os.path.split(p)
dirs.append(f)
if not p or not f:
path, file = os.path.split(path)
dirs.append(file)
if not path or not file:
break
dirs.reverse()
# remove empty entries
@@ -453,13 +454,13 @@ class CfgAggregator:
if not self.debug:
return
self.log.dbg('{}:'.format(title))
for e in elems:
self.log.dbg('\t- {}'.format(e))
for elem in elems:
self.log.dbg('\t- {}'.format(elem))
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))
for k, val in elems.items():
self.log.dbg('\t- \"{}\": {}'.format(k, val))