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

f-string refactoring

This commit is contained in:
deadc0de6
2022-08-28 22:10:20 +02:00
parent 66880c0d31
commit df65f3a126
11 changed files with 206 additions and 212 deletions

View File

@@ -54,8 +54,8 @@ class Cmd(DictParser):
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))
err = f'undefined arguments for {self.descr}: {exc}'
self.log.warn(err)
return False
return args
@@ -73,14 +73,14 @@ class Cmd(DictParser):
try:
cmd = action.format(*args)
except IndexError as exc:
err = 'findex error for {self.descr}: \"{action}\"'
err = f'index error for {self.descr}: \"{action}\"'
err += f' with \"{args}\"'
err += f': {exc}'
self.log.warn(err)
return False
except KeyError as exc:
err = f'key error for {self.descr}: \"{action}\": {exc}'
err += ' with \"{args}\"'
err += f' with \"{args}\"'
self.log.warn(err)
return False
if self.silent:
@@ -94,7 +94,7 @@ class Cmd(DictParser):
try:
ret = subprocess.call(cmd, shell=True)
except KeyboardInterrupt:
self.log.warn('f{self.descr} interrupted')
self.log.warn(f'{self.descr} interrupted')
if ret != 0:
self.log.warn(f'{self.descr} returned code {ret}')
return ret == 0
@@ -104,7 +104,7 @@ class Cmd(DictParser):
return {'action': value}
def __str__(self):
return 'key:{self.key} -> \"{self.action}\"'
return f'key:{self.key} -> \"{self.action}\"'
class Action(Cmd):
@@ -138,8 +138,8 @@ class Action(Cmd):
return cls(key=key, **val)
def __str__(self):
out = '{}: [{}] \"{}\"'
return out.format(self.key, self.kind, self.action)
out = f'{self.key}: [{self.kind}] \"{self.action}\"'
return out
def __repr__(self):
return f'action({self.__str__()})'
@@ -171,8 +171,8 @@ class Transform(Cmd):
and {1} is the result file
"""
if os.path.exists(arg1):
msg = 'transformation \"{}\": destination exists: {}'
self.log.warn(msg.format(self.key, arg1))
msg = f'transformation \"{self.key}\": destination exists: {arg1}'
self.log.warn(msg)
return False
if not self.args:

View File

@@ -85,8 +85,8 @@ class CfgAggregator:
key = dotfile.key
ret = self.cfgyaml.add_dotfile_to_profile(key, self.profile_key)
if ret:
msg = 'new dotfile {} to profile {}'
self.log.dbg(msg.format(key, self.profile_key))
msg = f'new dotfile {key} to profile {self.profile_key}'
self.log.dbg(msg)
# save the config and reload it
if ret:
@@ -136,8 +136,8 @@ class CfgAggregator:
try:
src = self.cfgyaml.resolve_dotfile_src(src)
except UndefinedException as exc:
err = 'unable to resolve {}: {}'
self.log.err(err.format(src, exc))
err = f'unable to resolve {src}: {exc}'
self.log.err(err)
return None
dotfiles = self.get_dotfile_by_dst(dst)
for dotfile in dotfiles:
@@ -453,8 +453,8 @@ class CfgAggregator:
if len(fields) > 1:
# we have args
key, *args = fields
msg = 'action with parm: {} and {}'
self.log.dbg(msg.format(key, args))
msg = f'action with parm: {key} and {args}'
self.log.dbg(msg)
action = self._get_action(key).copy(args)
else:
action = self._get_action(key)
@@ -467,8 +467,8 @@ class CfgAggregator:
if len(fields) > 1:
# we have args
key, *args = fields
msg = 'trans with parm: {} and {}'
self.log.dbg(msg.format(key, args))
msg = f'trans with parm: {key} and {args}'
self.log.dbg(msg)
trans = getter(key).copy(args)
else:
trans = getter(key)

View File

@@ -363,7 +363,6 @@ class CfgYaml:
pro[self.key_profile_dotfiles].append(dotfile_key)
if self._debug:
msg = f'add \"{dotfile_key}\" to profile \"{profile_key}\"'
msg.format(dotfile_key, profile_key)
self._dbg(msg)
self._dirty = True
return self._dirty
@@ -861,8 +860,8 @@ class CfgYaml:
new = self.__get_profile_included_item(inherited_profile,
keyitem, seen)
if self._debug:
msg = 'included {} from {}: {}'
self._dbg(msg.format(keyitem, inherited_profile, new))
msg = f'included {keyitem} from {inherited_profile}: {new}'
self._dbg(msg)
items.update(new)
cur = pentry.get(keyitem, {})
@@ -938,7 +937,7 @@ class CfgYaml:
# merge actions keys
if self._debug:
msg = f'Merging actions {profile} '
msg += '<- {i}: {actions} <- {o_actions}'
msg += f'<- {i}: {actions} <- {o_actions}'
self._dbg(msg)
actions.extend(o_actions)
this_profile[self.key_profile_actions] = uniq_list(actions)
@@ -1231,7 +1230,7 @@ class CfgYaml:
# check top entries
for entry in self.top_entries:
if entry not in yamldict:
err = f'no {entry} entry found'.format(entry)
err = f'no {entry} entry found'
self._log.err(err)
raise YamlException(f'config format error: {err}')
@@ -1654,8 +1653,8 @@ class CfgYaml:
dirn = os.path.dirname(self._path)
ret = os.path.join(dirn, path)
if self._debug:
msg = 'normalizing relative to cfg: {} -> {}'
self._dbg(msg.format(path, ret))
msg = f'normalizing relative to cfg: {path} -> {ret}'
self._dbg(msg)
path = ret
ret = os.path.normpath(path)
if self._debug and path != ret:

View File

@@ -52,15 +52,15 @@ def action_executor(opts, actions, defactions, templater, post=False):
LOG.dbg(f'executing def-{actiontype}-action: {action}')
ret = action.execute(templater=templater, debug=opts.debug)
if not ret:
err = 'def-{}-action \"{}\" failed'
LOG.err(err.format(actiontype, action.key))
err = f'def-{actiontype}-action \"{action.key}\" failed'
LOG.err(err)
return False, err
# execute actions
for action in actions:
if opts.dry:
err = 'would execute {}-action: {}'
LOG.dry(err.format(actiontype, action))
err = f'would execute {actiontype}-action: {action}'
LOG.dry(err)
continue
LOG.dbg(f'executing {actiontype}-action: {action}')
ret = action.execute(templater=templater, debug=opts.debug)
@@ -112,8 +112,9 @@ def _dotfile_compare(opts, dotfile, tmp):
src = dotfile.src
if not os.path.lexists(os.path.expanduser(dotfile.dst)):
line = '=> compare {}: \"{}\" does not exist on destination'
LOG.log(line.format(dotfile.key, dotfile.dst))
line = f'=> compare {dotfile.key}: \"{dotfile.dst}\" '
line += 'does not exist on destination'
LOG.log(line)
return False
# apply transformation
@@ -130,8 +131,8 @@ def _dotfile_compare(opts, dotfile, tmp):
asrc = os.path.join(opts.dotpath, os.path.expanduser(src))
adst = os.path.expanduser(dotfile.dst)
if os.path.samefile(asrc, adst):
line = '=> compare {}: diffing with \"{}\"'
LOG.dbg(line.format(dotfile.key, dotfile.dst))
line = f'=> compare {dotfile.key}: diffing with \"{dotfile.dst}\"'
LOG.dbg(line)
LOG.dbg('points to itself')
return True
@@ -149,8 +150,8 @@ def _dotfile_compare(opts, dotfile, tmp):
set_create=True)
if not ret:
# failed to install to tmp
line = '=> compare {} error: {}'
LOG.log(line.format(dotfile.key, err))
line = f'=> compare {dotfile.key} error: {err}'
LOG.log(line)
LOG.err(err)
return False
src = insttmp
@@ -172,17 +173,17 @@ def _dotfile_compare(opts, dotfile, tmp):
if diff != '':
# print diff results
if opts.compare_fileonly:
line = f'=> differ: \"{dotfile.src}\" \"{dotfile.dst}\"'
LOG.log(line.format(dotfile.key, dotfile.dst))
line = f'=> differ: \"{dotfile.key}\" \"{dotfile.dst}\"'
LOG.log(line)
else:
line = '=> compare {}: diffing with \"{}\"'
LOG.log(line.format(dotfile.key, dotfile.dst))
line = f'=> compare {dotfile.key}: diffing with \"{dotfile.dst}\"'
LOG.log(line)
LOG.emph(diff)
return False
# no difference
line = '=> compare {}: diffing with \"{}\"'
LOG.dbg(line.format(dotfile.key, dotfile.dst))
line = f'=> compare {dotfile.key}: diffing with \"{dotfile.dst}\"'
LOG.dbg(line)
LOG.dbg('same file')
return True
@@ -300,8 +301,8 @@ def cmd_install(opts):
dotfiles = [d for d in dotfiles if d.key in uniq]
if not dotfiles:
msg = 'no dotfile to install for this profile (\"{}\")'
LOG.warn(msg.format(opts.profile))
msg = f'no dotfile to install for this profile (\"{opts.profile}\")'
LOG.warn(msg)
return False
lfs = [k.key for k in dotfiles]
@@ -359,8 +360,8 @@ def cmd_install(opts):
# execute profile post-action
if len(installed) > 0 or opts.install_force_action:
msg = 'run {} profile post actions'
LOG.dbg(msg.format(len(pro_post_actions)))
msg = f'run {len(pro_post_actions)} profile post actions'
LOG.dbg(msg)
ret, _ = action_executor(opts, pro_post_actions,
[], templ, post=False)()
if not ret:
@@ -417,7 +418,7 @@ def cmd_compare(opts, tmp):
"""compare dotfiles and return True if all identical"""
dotfiles = opts.dotfiles
if not dotfiles:
msg = 'no dotfile defined for this profile (\"{opts.profile}\")'
msg = f'no dotfile defined for this profile (\"{opts.profile}\")'
LOG.warn(msg)
return True
@@ -582,11 +583,12 @@ def cmd_files(opts):
if not Templategen.is_template(src):
continue
if opts.files_grepable:
fmt = '{},dst:{},src:{},link:{}'
fmt = fmt.format(dotfile.key, dotfile.dst,
dotfile.src, dotfile.link.name.lower())
fmt = f'{dotfile.key},'
fmt += f'dst:{dotfile.dst},'
fmt += f'src:{dotfile.src},'
fmt += f'link:{dotfile.link.name.lower()}'
if dotfile.chmod:
fmt += ',chmod:{:o}'
fmt += f',chmod:{dotfile.chmod:o}'
else:
fmt += ',chmod:None'
LOG.raw(fmt)

View File

@@ -67,7 +67,7 @@ class Importer:
-1: error
"""
path = os.path.abspath(path)
self.log.dbg(f'import {path}'.format(path))
self.log.dbg(f'import {path}')
if not os.path.exists(path):
self.log.err(f'\"{path}\" does not exist, ignored!')
return -1
@@ -167,8 +167,8 @@ class Importer:
dflperm = get_default_file_perms(dst, self.umask)
self.log.dbg(f'import chmod: {import_mode}')
if import_mode or perm != dflperm:
msg = 'adopt mode {:o} (umask {:o})'
self.log.dbg(msg.format(perm, dflperm))
msg = f'adopt mode {perm:o} (umask {dflperm:o})'
self.log.dbg(msg)
chmod = perm
# add file to config file
@@ -199,8 +199,8 @@ class Importer:
self.log.log(f'diff \"{dst}\" VS \"{src}\"')
self.log.emph(diff)
# ask user
msg = 'Dotfile \"{}\" already exists, overwrite?'
if not self.log.ask(msg.format(src)):
msg = f'Dotfile \"{src}\" already exists, overwrite?'
if not self.log.ask(msg):
return False
self.log.dbg('will overwrite existing file')
return True
@@ -283,8 +283,8 @@ class Importer:
not self.conf.get_dotfile_by_src_dst(src, dst):
# same profile
# different src
msg = 'duplicate dotfile: {}'
self.log.err(msg.format(dotfile.key))
msg = f'duplicate dotfile: {dotfile.key}'
self.log.err(msg)
return True
return False

View File

@@ -92,8 +92,8 @@ class Installer:
self.log.dbg('fake dotfile installed')
self._exec_pre_actions(actionexec)
return True, None
msg = 'installing \"{}\" to \"{}\" (link: {})'
self.log.dbg(msg.format(src, dst, str(linktype)))
msg = f'installing \"{src}\" to \"{dst}\" (link: {linktype})'
self.log.dbg(msg)
src, dst, cont, err = self._check_paths(src, dst)
if not cont:
return self._log_install(cont, err)
@@ -101,7 +101,7 @@ class Installer:
# check source file exists
src = os.path.join(self.base, src)
if not os.path.exists(src):
err = 'source dotfile does not exist: {}'.format(src)
err = f'source dotfile does not exist: {src}'
return self._log_install(False, err)
self.action_executed = False
@@ -118,8 +118,8 @@ class Installer:
return self._log_install(ret, err)
isdir = os.path.isdir(src)
self.log.dbg('install {} to {}'.format(src, dst))
self.log.dbg('\"{}\" is a directory: {}'.format(src, isdir))
self.log.dbg(f'install {src} to {dst}')
self.log.dbg(f'\"{src}\" is a directory: {isdir}')
if linktype == LinkTypes.NOLINK:
# normal file
@@ -148,9 +148,9 @@ class Installer:
elif linktype == LinkTypes.LINK_CHILDREN:
# symlink direct children
if not isdir:
msg = 'symlink children of {} to {}'
self.log.dbg(msg.format(src, dst))
err = 'source dotfile is not a directory: {}'.format(src)
msg = f'symlink children of {src} to {dst}'
self.log.dbg(msg)
err = f'source dotfile is not a directory: {src}'
ret = False
else:
ret, err = self._link_children(templater, src, dst,
@@ -158,7 +158,7 @@ class Installer:
is_template=is_template,
ignore=ignore)
self.log.dbg('before chmod: {} err:{}'.format(ret, err))
self.log.dbg(f'before chmod: {ret} err:{err}')
if self.dry:
return self._log_install(ret, err)
@@ -175,13 +175,13 @@ class Installer:
dstperms = utils.get_file_perm(dst)
if dstperms != chmod:
# apply mode
msg = 'chmod {} to {:o}'.format(dst, chmod)
msg = f'chmod {dst} to {chmod:o}'
if not force_chmod and self.safe and not self.log.ask(msg):
ret = False
err = 'aborted'
else:
if not self.comparing:
self.log.sub('chmod {} to {:o}'.format(dst, chmod))
self.log.sub(f'chmod {dst} to {chmod:o}')
if utils.chmod(dst, chmod, debug=self.debug):
ret = True
else:
@@ -208,7 +208,7 @@ class Installer:
return
- success, error-if-any, dotfile-installed-path
"""
self.log.dbg('tmp install {} (defined dst: {})'.format(src, dst))
self.log.dbg(f'tmp install {src} (defined dst: {dst})')
src, dst, cont, err = self._check_paths(src, dst)
if not cont:
self._log_install(cont, err)
@@ -236,7 +236,7 @@ class Installer:
is_template=is_template,
chmod=chmod, ignore=ignore)
if ret:
self.log.dbg('tmp installed in {}'.format(tmpdst))
self.log.dbg(f'tmp installed in {tmpdst}')
# restore flags
self.dry = drysaved
@@ -303,7 +303,7 @@ class Installer:
"""
if is_template:
self.log.dbg('is a template')
self.log.dbg('install to {}'.format(self.workdir))
self.log.dbg(f'install to {self.workdir}')
tmp = utils.pivot_path(dst, self.workdir,
striphome=True, logger=self.log)
ret, err = self.install(templater, src, tmp,
@@ -332,17 +332,17 @@ class Installer:
parent = os.path.join(self.base, src)
if not os.path.lexists(dst):
if self.dry:
self.log.dry('would create directory "{}"'.format(dst))
self.log.dry(f'would create directory "{dst}"')
else:
if not self.comparing:
self.log.sub('creating directory "{}"'.format(dst))
self.log.sub(f'creating directory "{dst}"')
self._create_dirs(dst)
if os.path.isfile(dst):
msg = ''.join([
'Remove regular file {} and ',
f'Remove regular file {dst} and ',
'replace with empty directory?',
]).format(dst)
])
if self.safe and not self.log.ask(msg):
return False, 'aborted'
@@ -362,16 +362,15 @@ class Installer:
if utils.must_ignore([subsrc, subdst], ignore, debug=self.debug):
self.log.dbg(
'ignoring install of {} to {}'.format(src, dst),
f'ignoring install of {src} to {dst}',
)
continue
self.log.dbg('symlink child {} to {}'.format(subsrc, subdst))
self.log.dbg(f'symlink child {subsrc} to {subdst}')
if is_template:
self.log.dbg('child is a template')
self.log.dbg('install to {} and symlink'
.format(self.workdir))
self.log.dbg(f'install to {self.workdir} and symlink')
tmp = utils.pivot_path(subdst, self.workdir,
striphome=True, logger=self.log)
ret2, err2 = self.install(templater, subsrc, tmp,
@@ -414,15 +413,15 @@ class Installer:
if os.path.lexists(dst):
# symlink exists
if os.path.realpath(dst) == os.path.realpath(src):
msg = 'ignoring "{}", link already exists'.format(dst)
msg = f'ignoring "{dst}", link already exists'
self.log.dbg(msg)
return False, None
if self.dry:
self.log.dry('would remove {} and link to {}'.format(dst, src))
self.log.dry(f'would remove {dst} and link to {src}')
return True, None
if self.showdiff:
self._show_diff_before_write(src, dst)
msg = 'Remove "{}" for link creation?'.format(dst)
msg = f'Remove "{dst}" for link creation?'
if self.safe and not self.log.ask(msg):
return False, 'aborted'
@@ -431,16 +430,16 @@ class Installer:
try:
utils.removepath(dst)
except OSError as exc:
err = 'something went wrong with {}: {}'.format(src, exc)
err = f'something went wrong with {src}: {exc}'
return False, err
if self.dry:
self.log.dry('would link {} to {}'.format(dst, src))
self.log.dry(f'would link {dst} to {src}')
return True, None
base = os.path.dirname(dst)
if not self._create_dirs(base):
err = 'error creating directory for {}'.format(dst)
err = f'error creating directory for {dst}'
return False, err
# execute pre-actions
@@ -450,13 +449,13 @@ class Installer:
# re-check in case action created the file
if os.path.lexists(dst):
msg = 'Remove "{}" for link creation?'.format(dst)
msg = f'Remove "{dst}" for link creation?'
if self.safe and not overwrite and not self.log.ask(msg):
return False, 'aborted'
try:
utils.removepath(dst)
except OSError as exc:
err = 'something went wrong with {}: {}'.format(src, exc)
err = f'something went wrong with {src}: {exc}'
return False, err
# create symlink
@@ -469,7 +468,7 @@ class Installer:
lnk_src = os.path.relpath(src, dstrel)
os.symlink(lnk_src, dst)
if not self.comparing:
self.log.sub('linked {} to {}'.format(dst, lnk_src))
self.log.sub(f'linked {dst} to {lnk_src}')
return True, None
def _copy_file(self, templater, src, dst,
@@ -484,25 +483,25 @@ class Installer:
- False, None : ignored
- False, 'aborted' : user aborted
"""
self.log.dbg('deploy file: {}'.format(src))
self.log.dbg('ignore empty: {}'.format(noempty))
self.log.dbg('ignore pattern: {}'.format(ignore))
self.log.dbg('is_template: {}'.format(is_template))
self.log.dbg('no empty: {}'.format(noempty))
self.log.dbg(f'deploy file: {src}')
self.log.dbg(f'ignore empty: {noempty}')
self.log.dbg(f'ignore pattern: {ignore}')
self.log.dbg(f'is_template: {is_template}')
self.log.dbg(f'no empty: {noempty}')
# ignore file
if utils.must_ignore([src, dst], ignore, debug=self.debug):
self.log.dbg('ignoring install of {} to {}'.format(src, dst))
self.log.dbg(f'ignoring install of {src} to {dst}')
return False, None
# check no loop
if utils.samefile(src, dst):
err = 'dotfile points to itself: {}'.format(dst)
err = f'dotfile points to itself: {dst}'
return False, err
# check source file exists
if not os.path.exists(src):
err = 'source dotfile does not exist: {}'.format(src)
err = f'source dotfile does not exist: {src}'
return False, err
# handle the file
@@ -518,10 +517,10 @@ class Installer:
templater.restore_vars(saved)
# test is empty
if noempty and utils.content_empty(content):
self.log.dbg('ignoring empty template: {}'.format(src))
self.log.dbg(f'ignoring empty template: {src}')
return False, None
if content is None:
err = 'empty template {}'.format(src)
err = f'empty template {src}'
return False, err
# write the file
@@ -530,7 +529,7 @@ class Installer:
actionexec=actionexec)
if ret and not err:
if not self.dry and not self.comparing:
self.log.sub('install {} to {}'.format(src, dst))
self.log.sub(f'install {src} to {dst}')
return ret, err
def _copy_dir(self, templater, src, dst,
@@ -545,14 +544,14 @@ class Installer:
- False, None : ignored
- False, 'aborted' : user aborted
"""
self.log.dbg('deploy dir {}'.format(src))
self.log.dbg(f'deploy dir {src}')
# default to nothing installed and no error
ret = False, None
# handle all files in dir
for entry in os.listdir(src):
fpath = os.path.join(src, entry)
self.log.dbg('deploy sub from {}: {}'.format(dst, entry))
self.log.dbg(f'deploy sub from {dst}: {entry}')
if not os.path.isdir(fpath):
# is file
res, err = self._copy_file(templater, fpath,
@@ -596,7 +595,7 @@ class Installer:
file.write(content)
shutil.copymode(src, dst)
except NotADirectoryError as exc:
err = 'opening dest file: {}'.format(exc)
err = f'opening dest file: {exc}'
return False, err
except OSError as exc:
return False, str(exc)
@@ -624,7 +623,7 @@ class Installer:
"""
overwrite = not self.safe
if self.dry:
self.log.dry('would install {}'.format(dst))
self.log.dry(f'would install {dst}')
return True, None
if os.path.lexists(dst):
@@ -634,21 +633,21 @@ class Installer:
except OSError as exc:
if exc.errno == errno.ENOENT:
# broken symlink
err = 'broken symlink {}'.format(dst)
err = f'broken symlink {dst}'
return False, err
if self.diff:
if not self._is_different(src, dst, content=content):
self.log.dbg('{} is the same'.format(dst))
self.log.dbg(f'{dst} is the same')
return False, None
if self.safe:
self.log.dbg('change detected for {}'.format(dst))
self.log.dbg(f'change detected for {dst}')
if self.showdiff:
# get diff
self._show_diff_before_write(src, dst,
content=content)
if not self.log.ask('Overwrite \"{}\"'.format(dst)):
if not self.log.ask(f'Overwrite \"{dst}\"'):
return False, 'aborted'
overwrite = True
@@ -658,7 +657,7 @@ class Installer:
# create hierarchy
base = os.path.dirname(dst)
if not self._create_dirs(base):
err = 'creating directory for {}'.format(dst)
err = f'creating directory for {dst}'
return False, err
# execute pre actions
@@ -666,12 +665,12 @@ class Installer:
if not ret:
return False, err
self.log.dbg('install file to \"{}\"'.format(dst))
self.log.dbg(f'install file to \"{dst}\"')
# re-check in case action created the file
if self.safe and not overwrite and \
os.path.lexists(dst) and \
not self.log.ask('Overwrite \"{}\"'.format(dst)):
self.log.warn('ignoring {}'.format(dst))
not self.log.ask(f'Overwrite \"{dst}\"'):
self.log.warn(f'ignoring {dst}')
return False, 'aborted'
# writing to file
@@ -726,7 +725,7 @@ class Installer:
def _print_diff(self, src, dst, diff):
"""show diff to user"""
self.log.log('diff \"{}\" VS \"{}\"'.format(dst, src))
self.log.log(f'diff \"{dst}\" VS \"{src}\"')
self.log.emph(diff)
def _create_dirs(self, directory):
@@ -737,9 +736,9 @@ class Installer:
if os.path.exists(directory):
return True
if self.dry:
self.log.dry('would mkdir -p {}'.format(directory))
self.log.dry(f'would mkdir -p {directory}')
return True
self.log.dbg('mkdir -p {}'.format(directory))
self.log.dbg(f'mkdir -p {directory}')
os.makedirs(directory, exist_ok=True)
return os.path.exists(directory)
@@ -749,7 +748,7 @@ class Installer:
if self.dry:
return
dst = path.rstrip(os.sep) + self.backup_suffix
self.log.log('backup {} to {}'.format(path, dst))
self.log.log(f'backup {path} to {dst}')
os.rename(path, dst)
def _exec_pre_actions(self, actionexec):
@@ -773,7 +772,7 @@ class Installer:
self.log.dbg('install: SUCCESS')
else:
if err:
self.log.dbg('install: ERROR: {}'.format(err))
self.log.dbg(f'install: ERROR: {err}')
else:
self.log.dbg('install: IGNORED')
return boolean, err
@@ -785,7 +784,7 @@ class Installer:
"""
# check both path are valid
if not dst or not src:
err = 'empty dst or src for {}'.format(src)
err = f'empty dst or src for {src}'
self.log.dbg(err)
return None, None, False, err

View File

@@ -57,7 +57,7 @@ class Logger:
"""error log"""
cstart = self._color(self.RED)
cend = self._color(self.RESET)
msg = f'{string} {end}'.format(string, end)
msg = f'{string} {end}'
sys.stderr.write(f'{cstart}[ERR] {msg}{cend}')
def warn(self, string, end='\n'):

View File

@@ -59,7 +59,7 @@ class Settings(DictParser):
key_import_variables = 'import_variables'
# defaults
default_diff_command = 'diff -r -u {0} {1}'
default_diff_cmd = 'diff -r -u {0} {1}'
def __init__(self, backup=True, banner=True,
create=True, default_actions=None, dotpath='dotfiles',
@@ -71,7 +71,7 @@ class Settings(DictParser):
impignore=None, workdir='~/.config/dotdrop',
showdiff=False, minversion=None,
func_file=None, filter_file=None,
diff_command=default_diff_command,
diff_command=default_diff_cmd,
template_dotfile_default=True,
ignore_missing_in_dotdrop=False,
force_chmod=False, chmod_on_import=False,

View File

@@ -107,7 +107,7 @@ class Templategen:
try:
return self.env.from_string(string).render(self.variables)
except UndefinedError as exc:
err = 'undefined variable: {exc.message}'
err = f'undefined variable: {exc.message}'
raise UndefinedException(err) from exc
def add_tmp_vars(self, newvars=None):

View File

@@ -61,7 +61,7 @@ class Updater:
"""update the dotfile installed on path"""
path = os.path.expanduser(path)
if not os.path.lexists(path):
self.log.err('\"{}\" does not exist!'.format(path))
self.log.err(f'\"{path}\" does not exist!')
return False
dotfiles = self.conf.get_dotfile_by_dst(path,
profile_key=self.profile_key)
@@ -69,12 +69,12 @@ class Updater:
return False
for dotfile in dotfiles:
if not dotfile:
msg = 'invalid dotfile for update: {}'
self.log.err(msg.format(dotfile.key))
err = f'invalid dotfile for update: {dotfile.key}'
self.log.err(err)
return False
msg = 'updating {} from path \"{}\"'
self.log.dbg(msg.format(dotfile, path))
msg = f'updating {dotfile} from path \"{path}\"'
self.log.dbg(msg)
if not self._update(path, dotfile):
return False
return True
@@ -83,11 +83,11 @@ class Updater:
"""update the dotfile referenced by key"""
dotfile = self.conf.get_dotfile(key, profile_key=self.profile_key)
if not dotfile:
self.log.dbg('no such dotfile: \"{}\"'.format(key))
msg = 'invalid dotfile for update: {}'
self.log.err(msg.format(key))
self.log.dbg(f'no such dotfile: \"{key}\"')
msg = f'invalid dotfile for update: {key}'
self.log.err(msg)
return False
self.log.dbg('updating {} from key \"{}\"'.format(dotfile, key))
self.log.dbg(f'updating {dotfile} from key \"{key}\"')
path = self.conf.path_to_dotfile_dst(dotfile.dst)
return self._update(path, dotfile)
@@ -97,27 +97,27 @@ class Updater:
new_path = None
ignores = list(set(self.ignore + dotfile.upignore))
self.ignores = patch_ignores(ignores, dotfile.dst, debug=self.debug)
self.log.dbg('ignore pattern(s): {}'.format(self.ignores))
self.log.dbg(f'ignore pattern(s): {self.ignores}')
deployed_path = os.path.expanduser(path)
local_path = os.path.join(self.dotpath, dotfile.src)
local_path = os.path.expanduser(local_path)
if not os.path.exists(deployed_path):
msg = '\"{}\" does not exist'
self.log.err(msg.format(deployed_path))
msg = f'\"{deployed_path}\" does not exist'
self.log.err(msg)
return False
if not os.path.exists(local_path):
msg = '\"{}\" does not exist, import it first'
self.log.err(msg.format(local_path))
msg = f'\"{local_path}\" does not exist, import it first'
self.log.err(msg)
return False
ignore_missing_in_dotdrop = self.ignore_missing_in_dotdrop or \
dotfile.ignore_missing_in_dotdrop
if (ignore_missing_in_dotdrop and not os.path.exists(local_path)) or \
self._ignore([deployed_path, local_path]):
self.log.sub('\"{}\" ignored'.format(dotfile.key))
self.log.sub(f'\"{dotfile.key}\" ignored')
return True
# apply write transformation if any
new_path = self._apply_trans_w(deployed_path, dotfile)
@@ -136,8 +136,8 @@ class Updater:
if deployed_mode != local_mode:
# mirror rights
msg = 'adopt mode {:o} for {}'
self.log.dbg(msg.format(deployed_mode, dotfile.key))
msg = f'adopt mode {deployed_mode:o} for {dotfile.key}'
self.log.dbg(msg)
if self.conf.update_dotfile(dotfile.key, deployed_mode):
ret = True
@@ -151,26 +151,26 @@ class Updater:
trans = dotfile.get_trans_w()
if not trans:
return path
self.log.dbg('executing write transformation {}'.format(trans))
self.log.dbg(f'executing write transformation {trans}')
tmp = get_unique_tmp_name()
self.templater.restore_vars(self.tvars)
newvars = dotfile.get_dotfile_variables()
self.templater.add_tmp_vars(newvars=newvars)
if not trans.transform(path, tmp, templater=self.templater,
debug=self.debug):
msg = 'transformation \"{}\" failed for {}'
self.log.err(msg.format(trans.key, dotfile.key))
if os.path.exists(tmp):
removepath(tmp, logger=self.log)
err = f'transformation \"{trans.key}\" failed for {dotfile.key}'
self.log.err(err)
return None
return tmp
def _is_template(self, path):
if not Templategen.is_template(path, ignore=self.ignores,
debug=self.debug):
self.log.dbg('{} is NO template'.format(path))
self.log.dbg(f'{path} is NO template')
return False
self.log.warn('{} uses template, update manually'.format(path))
self.log.warn(f'{path} uses template, update manually')
return True
def _show_patch(self, fpath, tpath):
@@ -179,7 +179,8 @@ class Updater:
tmp = write_to_tmpfile(content)
mirror_file_rights(tpath, tmp)
cmds = ['diff', '-u', tmp, fpath, '|', 'patch', tpath]
self.log.warn('try patching with: \"{}\"'.format(' '.join(cmds)))
cmdss = ' '.join(cmds)
self.log.warn(f'try patching with: \"{cmdss}\"')
return False
def _resolve_template(self, tpath):
@@ -202,8 +203,8 @@ class Updater:
dstr = get_file_perm(dst)
if srcr == dstr:
return
msg = 'copy rights from {} ({:o}) to {} ({:o})'
self.log.dbg(msg.format(src, srcr, dst, dstr))
msg = f'copy rights from {src} ({srcr:o}) to {dst} ({dstr:o})'
self.log.dbg(msg)
try:
mirror_file_rights(src, dst)
except OSError as exc:
@@ -212,67 +213,49 @@ class Updater:
def _handle_file(self, deployed_path, local_path, compare=True):
"""sync path (deployed file) and local_path (dotdrop dotfile path)"""
if self._ignore([deployed_path, local_path]):
self.log.sub('\"{}\" ignored'.format(local_path))
self.log.sub(f'\"{local_path}\" ignored')
return True
self.log.dbg('update for file {} and {}'.format(
deployed_path,
local_path,
))
self.log.dbg(f'update for file {deployed_path} and {local_path}')
if self._is_template(local_path):
# dotfile is a template
self.log.dbg('{} is a template'.format(local_path))
self.log.dbg(f'{local_path} is a template')
if self.showpatch:
try:
self._show_patch(deployed_path, local_path)
except UndefinedException as exc:
msg = 'unable to show patch for {}: {}'.format(
deployed_path,
exc,
)
msg = f'unable to show patch for {deployed_path}: {exc}'
self.log.warn(msg)
return False
if compare and \
filecmp.cmp(deployed_path, local_path, shallow=False) and \
self._same_rights(deployed_path, local_path):
# no difference
self.log.dbg('identical files: {} and {}'.format(
deployed_path,
local_path,
))
self.log.dbg(f'identical files: {deployed_path} and {local_path}')
return True
if not self._overwrite(deployed_path, local_path):
return False
try:
if self.dry:
self.log.dry('would cp {} {}'.format(
deployed_path,
local_path,
))
self.log.dry(f'would cp {deployed_path} {local_path}')
else:
self.log.dbg('cp {} {}'.format(deployed_path, local_path))
self.log.dbg(f'cp {deployed_path} {local_path}')
shutil.copyfile(deployed_path, local_path)
self._mirror_rights(deployed_path, local_path)
self.log.sub('\"{}\" updated'.format(local_path))
self.log.sub(f'\"{local_path}\" updated')
except IOError as exc:
self.log.warn('{} update failed, do manually: {}'.format(
deployed_path,
exc
))
self.log.warn(f'{deployed_path} update failed, do manually: {exc}')
return False
return True
def _handle_dir(self, deployed_path, local_path, dotfile):
"""sync path (local dir) and local_path (dotdrop dir path)"""
self.log.dbg('handle update for dir {} to {}'.format(
deployed_path,
local_path,
))
self.log.dbg(f'handle update for dir {deployed_path} to {local_path}')
# paths must be absolute (no tildes)
deployed_path = os.path.expanduser(deployed_path)
local_path = os.path.expanduser(local_path)
if self._ignore([deployed_path, local_path]):
self.log.sub('\"{}\" ignored'.format(local_path))
self.log.sub(f'\"{local_path}\" ignored')
return True
# find the differences
diff = filecmp.dircmp(deployed_path, local_path, ignore=None)
@@ -293,12 +276,12 @@ class Updater:
new = os.path.join(right, toadd)
if (ignore_missing_in_dotdrop and not os.path.exists(new)) or \
self._ignore([exist, new]):
self.log.sub('\"{}\" ignored'.format(exist))
self.log.sub(f'\"{exist}\" ignored')
continue
if self.dry:
self.log.dry('would cp -r {} {}'.format(exist, new))
self.log.dry(f'would cp -r {exist} {new}')
continue
self.log.dbg('cp -r {} {}'.format(exist, new))
self.log.dbg(f'cp -r {exist} {new}')
# Newly created directory should be copied as is (for efficiency).
def ign(src, names):
@@ -318,10 +301,10 @@ class Updater:
try:
shutil.copytree(exist, new, ignore=ign)
except OSError as exc:
msg = 'error copying dir {}'.format(exist)
self.log.err('{}: {}'.format(msg, exc))
msg = f'error copying dir {exist}'
self.log.err(f'{msg}: {exc}')
continue
self.log.sub('\"{}\" dir added'.format(new))
self.log.sub(f'\"{new}\" dir added')
def _merge_dirs_remove_right_only(self, diff, left, right,
ignore_missing_in_dotdrop):
@@ -334,13 +317,13 @@ class Updater:
if self._ignore([old]):
continue
if self.dry:
self.log.dry('would rm -r {}'.format(old))
self.log.dry(f'would rm -r {old}')
continue
self.log.dbg('rm -r {}'.format(old))
self.log.dbg(f'rm -r {old}')
if not self._confirm_rm_r(old):
continue
removepath(old, logger=self.log)
self.log.sub('\"{}\" dir removed'.format(old))
self.log.sub(f'\"{old}\" dir removed')
# handle files diff
# sync files that exist in both but are different
@@ -354,9 +337,9 @@ class Updater:
self._ignore([fleft, fright]):
continue
if self.dry:
self.log.dry('would cp {} {}'.format(fleft, fright))
self.log.dry(f'would cp {fleft} {fright}')
continue
self.log.dbg('cp {} {}'.format(fleft, fright))
self.log.dbg(f'cp {fleft} {fright}')
self._handle_file(fleft, fright, compare=False)
def _merge_dirs_copy_left_only(self, diff, left, right,
@@ -372,18 +355,18 @@ class Updater:
self._ignore([exist, new]):
continue
if self.dry:
self.log.dry('would cp {} {}'.format(exist, new))
self.log.dry(f'would cp {exist} {new}')
continue
self.log.dbg('cp {} {}'.format(exist, new))
self.log.dbg(f'cp {exist} {new}')
try:
shutil.copyfile(exist, new)
except OSError as exc:
msg = 'error copying file {}'.format(exist)
self.log.err('{}: {}'.format(msg, exc))
msg = f'error copying file {exist}'
self.log.err(f'{msg}: {exc}')
continue
self._mirror_rights(exist, new)
self.log.sub('\"{}\" added'.format(new))
self.log.sub(f'\"{new}\" added')
def _merge_dirs_remove_right_only_2(self, diff, right):
"""remove files that don't exist in deployed version"""
@@ -397,16 +380,16 @@ class Updater:
if self._ignore([new]):
continue
if self.dry:
self.log.dry('would rm {}'.format(new))
self.log.dry(f'would rm {new}')
continue
self.log.dbg('rm {}'.format(new))
self.log.dbg(f'rm {new}')
removepath(new, logger=self.log)
self.log.sub('\"{}\" removed'.format(new))
self.log.sub(f'\"{new}\" removed')
def _merge_dirs(self, diff, dotfile):
"""Synchronize directories recursively."""
left, right = diff.left, diff.right
self.log.dbg('sync dir {} to {}'.format(left, right))
self.log.dbg(f'sync dir {left} to {right}')
if self._ignore([left, right]):
return True
@@ -437,20 +420,20 @@ class Updater:
def _overwrite(self, src, dst):
"""ask for overwritting"""
msg = 'Overwrite \"{}\" with \"{}\"?'.format(dst, src)
msg = f'Overwrite \"{dst}\" with \"{src}\"?'
if self.safe and not self.log.ask(msg):
return False
return True
def _confirm_rm_r(self, directory):
"""ask for rm -r directory"""
msg = 'Recursively remove \"{}\"?'.format(directory)
msg = f'Recursively remove \"{directory}\"?'
if self.safe and not self.log.ask(msg):
return False
return True
def _ignore(self, paths):
if must_ignore(paths, self.ignores, debug=self.debug):
self.log.dbg('ignoring update for {}'.format(paths))
self.log.dbg(f'ignoring update for {paths}')
return True
return False

View File

@@ -247,8 +247,9 @@ def must_ignore(paths, ignores, debug=False):
# Each of these will start with an '!' so we need to remove that
nign = nign[1:]
if debug:
msg = 'trying to match :\"{}\" with non-ignore-pattern:\"{}\"'
LOG.dbg(msg.format(path, nign), force=True)
msg = f'trying to match :\"{path}\" '
msg += f'with non-ignore-pattern:\"{nign}\"'
LOG.dbg(msg, force=True)
if fnmatch.fnmatch(path, nign):
if debug:
msg = f'negative ignore \"{nign}\" match: {path}'
@@ -347,50 +348,60 @@ def dependencies_met():
# check unix tools deps
# diff command is checked in settings.py
deps = ['file']
err = 'The tool \"{}\" was not found in the PATH!'
for dep in deps:
if not shutil.which(dep):
raise UnmetDependency(err.format(dep))
# check python deps
err = 'missing python module \"{}\"'
err = f'The tool \"{dep}\" was not found in the PATH!'
raise UnmetDependency(err)
# check python deps
# pylint: disable=C0415
# python-magic
name = 'python-magic'
err = f'missing python module \"{name}\"'
try:
import magic
assert magic
if not hasattr(magic, 'from_file'):
LOG.warn(err.format('python-magic'))
LOG.warn(err)
except ImportError:
LOG.warn(err.format('python-magic'))
LOG.warn(err)
# docopt
name = 'docopt'
err = f'missing python module \"{name}\"'
try:
from docopt import docopt
assert docopt
except ImportError as exc:
raise Exception(err.format('docopt')) from exc
raise Exception(err) from exc
# jinja2
name = 'jinja2'
err = f'missing python module \"{name}\"'
try:
import jinja2
assert jinja2
except ImportError as exc:
raise Exception(err.format('jinja2')) from exc
raise Exception(err) from exc
# ruamel.yaml
name = 'ruamel.yaml'
err = f'missing python module \"{name}\"'
try:
from ruamel.yaml import YAML
assert YAML
except ImportError as exc:
raise Exception(err.format('ruamel.yaml')) from exc
raise Exception(err) from exc
# toml
name = 'toml'
err = f'missing python module \"{name}\"'
try:
import toml
assert toml
except ImportError as exc:
raise Exception(err.format('toml')) from exc
raise Exception(err) from exc
# pylint: enable=C0415
@@ -488,8 +499,8 @@ def check_version():
if latest.startswith('v'):
latest = latest[1:]
if version.parse(VERSION) < version.parse(latest):
msg = 'A new version of dotdrop is available ({})'
LOG.warn(msg.format(latest))
msg = f'A new version of dotdrop is available ({latest})'
LOG.warn(msg)
def pivot_path(path, newdir, striphome=False, logger=None):