1
0
mirror of https://github.com/deadc0de6/dotdrop.git synced 2026-02-10 03:59:17 +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 sys
import dotdrop.dotdrop
def main(): def main():
import dotdrop.dotdrop """entry point"""
if dotdrop.dotdrop.main(): if dotdrop.dotdrop.main():
sys.exit(0) sys.exit(0)
sys.exit(1) sys.exit(1)

View File

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

View File

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