From df65f3a126d07d6224956a7f5a20118c10542aa3 Mon Sep 17 00:00:00 2001 From: deadc0de6 Date: Sun, 28 Aug 2022 22:10:20 +0200 Subject: [PATCH] f-string refactoring --- dotdrop/action.py | 20 +++--- dotdrop/cfg_aggregator.py | 16 ++--- dotdrop/cfg_yaml.py | 13 ++-- dotdrop/dotdrop.py | 52 ++++++++------- dotdrop/importer.py | 14 ++-- dotdrop/installer.py | 119 ++++++++++++++++----------------- dotdrop/logger.py | 2 +- dotdrop/settings.py | 4 +- dotdrop/templategen.py | 2 +- dotdrop/updater.py | 137 +++++++++++++++++--------------------- dotdrop/utils.py | 39 +++++++---- 11 files changed, 206 insertions(+), 212 deletions(-) diff --git a/dotdrop/action.py b/dotdrop/action.py index d0b7628..6d032aa 100644 --- a/dotdrop/action.py +++ b/dotdrop/action.py @@ -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: diff --git a/dotdrop/cfg_aggregator.py b/dotdrop/cfg_aggregator.py index c75513f..7572f29 100644 --- a/dotdrop/cfg_aggregator.py +++ b/dotdrop/cfg_aggregator.py @@ -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) diff --git a/dotdrop/cfg_yaml.py b/dotdrop/cfg_yaml.py index 18fab17..c901a1c 100644 --- a/dotdrop/cfg_yaml.py +++ b/dotdrop/cfg_yaml.py @@ -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: diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 59181cc..6d85345 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -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) diff --git a/dotdrop/importer.py b/dotdrop/importer.py index d9f1760..99e0c5e 100644 --- a/dotdrop/importer.py +++ b/dotdrop/importer.py @@ -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 diff --git a/dotdrop/installer.py b/dotdrop/installer.py index 17d66aa..0fb7e6a 100644 --- a/dotdrop/installer.py +++ b/dotdrop/installer.py @@ -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 diff --git a/dotdrop/logger.py b/dotdrop/logger.py index 1a78b2b..03f9b91 100644 --- a/dotdrop/logger.py +++ b/dotdrop/logger.py @@ -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'): diff --git a/dotdrop/settings.py b/dotdrop/settings.py index 30ce88f..ef043c8 100644 --- a/dotdrop/settings.py +++ b/dotdrop/settings.py @@ -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, diff --git a/dotdrop/templategen.py b/dotdrop/templategen.py index b7f5f73..a3e9865 100644 --- a/dotdrop/templategen.py +++ b/dotdrop/templategen.py @@ -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): diff --git a/dotdrop/updater.py b/dotdrop/updater.py index 7340e33..97e5a77 100644 --- a/dotdrop/updater.py +++ b/dotdrop/updater.py @@ -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 diff --git a/dotdrop/utils.py b/dotdrop/utils.py index d4b109a..54c0bd9 100644 --- a/dotdrop/utils.py +++ b/dotdrop/utils.py @@ -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):