def compare(self, opts, conf, tmp, nbdotfiles): dotfiles = conf.get_dotfiles(opts['profile']) self.assertTrue(len(dotfiles) == nbdotfiles) t = Templategen(base=opts['dotpath'], debug=True) inst = Installer(create=opts['create'], backup=opts['backup'], dry=opts['dry'], base=opts['dotpath'], debug=True) comp = Comparator() results = {} for dotfile in dotfiles: ret, insttmp = inst.install_to_temp(t, tmp, dotfile.src, dotfile.dst) if not ret: results[path] = False continue diff = comp.compare(insttmp, dotfile.dst, ignore=['whatever', 'whatelse']) print('XXXX diff for {} and {}:\n{}'.format( dotfile.src, dotfile.dst, diff)) path = os.path.expanduser(dotfile.dst) results[path] = diff == '' return results
def _prepare_hierarchy(self, src, dst): """prepare hierarchy for dotfile""" srcf = os.path.join(self.dotpath, src) if self._ignore(srcf): return False srcfd = os.path.dirname(srcf) if self._ignore(srcfd): return False # a dotfile in dotpath already exists at that spot if os.path.exists(srcf): if self.safe: c = Comparator(debug=self.debug, diff_cmd=self.diff_cmd) diff = c.compare(srcf, dst) if diff != '': # files are different, dunno what to do self.log.log('diff \"{}\" VS \"{}\"'.format(dst, srcf)) self.log.emph(diff) # ask user msg = 'Dotfile \"{}\" already exists, overwrite?' if not self.log.ask(msg.format(srcf)): return False if self.debug: self.log.dbg('will overwrite existing file') # create directory hierarchy if self.dry: cmd = 'mkdir -p {}'.format(srcfd) self.log.dry('would run: {}'.format(cmd)) else: try: os.makedirs(srcfd, exist_ok=True) except Exception: self.log.err('importing \"{}\" failed!'.format(dst)) return False if self.dry: self.log.dry('would copy {} to {}'.format(dst, srcf)) else: # copy the file to the dotpath try: if os.path.isdir(dst): if os.path.exists(srcf): shutil.rmtree(srcf) ig = shutil.ignore_patterns(*self.ignore) shutil.copytree(dst, srcf, copy_function=self._cp, ignore=ig) else: shutil.copy2(dst, srcf) except shutil.Error as e: src = e.args[0][0][0] why = e.args[0][0][2] self.log.err('importing \"{}\" failed: {}'.format(src, why)) return True
def _diff_before_write(self, src, dst): """diff before writing when using --showdiff - not efficient""" # create tmp to diff for templates comp = Comparator(debug=self.debug) diff = comp.compare(src, dst) # fake the output for readability if not diff: return self.log.log('diff \"{}\" VS \"{}\"'.format(src, dst)) self.log.emph(diff)
def _diff_before_write(self, src, dst, src_content): """diff before writing when using --showdiff - not efficient""" # create tmp to diff for templates tmpfile = utils.get_tmpfile() with open(tmpfile, 'wb') as f: f.write(src_content) comp = Comparator(debug=self.debug) diff = comp.compare(tmpfile, dst) # fake the output for readability self.log.log('diff \"{}\" VS \"{}\"'.format(src, dst)) self.log.emph(diff) if tmpfile: utils.remove(tmpfile)
def _prepare_hier_when_exists(self, srcf, dst): """a dotfile in dotpath already exists at that spot""" if not os.path.exists(srcf): return True if not self.safe: return True cmp = Comparator(debug=self.debug, diff_cmd=self.diff_cmd) diff = cmp.compare(srcf, dst) if diff != '': # files are different, dunno what to do self.log.log('diff \"{}\" VS \"{}\"'.format(dst, srcf)) self.log.emph(diff) # ask user msg = 'Dotfile \"{}\" already exists, overwrite?' if not self.log.ask(msg.format(srcf)): return False self.log.dbg('will overwrite existing file') return True
def compare(self, o, tmp, nbdotfiles): dotfiles = o.dotfiles self.assertTrue(len(dotfiles) == nbdotfiles) t = Templategen(base=o.dotpath, debug=True) inst = Installer(create=o.create, backup=o.backup, dry=o.dry, base=o.dotpath, debug=o.debug) comp = Comparator() results = {} for dotfile in dotfiles: path = os.path.expanduser(dotfile.dst) ret, insttmp = inst.install_to_temp(t, tmp, dotfile.src, dotfile.dst) if not ret: results[path] = False continue diff = comp.compare(insttmp, dotfile.dst, ignore=['whatever', 'whatelse']) results[path] = diff == '' return results
def cmd_compare(o, tmp): """compare dotfiles and return True if all identical""" dotfiles = o.dotfiles if dotfiles == []: msg = 'no dotfile defined for this profile (\"{}\")' LOG.warn(msg.format(o.profile)) return True # compare only specific files same = True selected = dotfiles if o.compare_focus: selected = _select(o.compare_focus, dotfiles) if len(selected) < 1: return False t = Templategen(base=o.dotpath, variables=o.variables, debug=o.debug) inst = Installer(create=o.create, backup=o.backup, dry=o.dry, base=o.dotpath, workdir=o.workdir, debug=o.debug, backup_suffix=o.install_backup_suffix) comp = Comparator(diffopts=o.compare_dopts, debug=o.debug) for dotfile in selected: if o.debug: LOG.dbg('comparing {}'.format(dotfile)) src = dotfile.src if not os.path.lexists(os.path.expanduser(dotfile.dst)): line = '=> compare {}: \"{}\" does not exist on local' LOG.log(line.format(dotfile.key, dotfile.dst)) same = False continue tmpsrc = None if dotfile.trans_r: # apply transformation tmpsrc = apply_trans(o.dotpath, dotfile, debug=o.debug) if not tmpsrc: # could not apply trans same = False continue src = tmpsrc # install dotfile to temporary dir ret, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst) if not ret: # failed to install to tmp same = False continue ignores = list(set(o.compare_ignore + dotfile.cmpignore)) diff = comp.compare(insttmp, dotfile.dst, ignore=ignores) if tmpsrc: # clean tmp transformed dotfile if any tmpsrc = os.path.join(o.dotpath, tmpsrc) if os.path.exists(tmpsrc): remove(tmpsrc) if diff == '': if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.key, dotfile.dst)) LOG.dbg('same file') else: line = '=> compare {}: diffing with \"{}\"' LOG.log(line.format(dotfile.key, dotfile.dst)) LOG.emph(diff) same = False return same
def _dotfile_compare(o, dotfile, tmp): """ compare a dotfile returns True if same """ t = _get_templater(o) inst = Installer(create=o.create, backup=o.backup, dry=o.dry, base=o.dotpath, workdir=o.workdir, debug=o.debug, backup_suffix=o.install_backup_suffix, diff_cmd=o.diff_command) comp = Comparator(diff_cmd=o.diff_command, debug=o.debug) # add dotfile variables newvars = dotfile.get_dotfile_variables() t.add_tmp_vars(newvars=newvars) # dotfiles does not exist / not installed if o.debug: LOG.dbg('comparing {}'.format(dotfile)) 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)) return False # apply transformation tmpsrc = None if dotfile.trans_r: if o.debug: LOG.dbg('applying transformation before comparing') tmpsrc = apply_trans(o.dotpath, dotfile, t, debug=o.debug) if not tmpsrc: # could not apply trans return False src = tmpsrc # is a symlink pointing to itself asrc = os.path.join(o.dotpath, os.path.expanduser(src)) adst = os.path.expanduser(dotfile.dst) if os.path.samefile(asrc, adst): if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.key, dotfile.dst)) LOG.dbg('points to itself') return True ignores = list(set(o.compare_ignore + dotfile.cmpignore)) ignores = patch_ignores(ignores, dotfile.dst, debug=o.debug) insttmp = None if dotfile.template and Templategen.is_template(src, ignore=ignores): # install dotfile to temporary dir for compare ret, err, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst, is_template=True, chmod=dotfile.chmod) if not ret: # failed to install to tmp line = '=> compare {} error: {}' LOG.log(line.format(dotfile.key, err)) LOG.err(err) return False src = insttmp # compare diff = comp.compare(src, dotfile.dst, ignore=ignores) # clean tmp transformed dotfile if any if tmpsrc: tmpsrc = os.path.join(o.dotpath, tmpsrc) if os.path.exists(tmpsrc): removepath(tmpsrc, LOG) # clean tmp template dotfile if any if insttmp: if os.path.exists(insttmp): removepath(insttmp, LOG) if diff != '': # print diff results line = '=> compare {}: diffing with \"{}\"' LOG.log(line.format(dotfile.key, dotfile.dst)) if o.compare_fileonly: LOG.raw('<files are different>') else: LOG.emph(diff) return False # no difference if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.key, dotfile.dst)) LOG.dbg('same file') return True
def cmd_compare(opts, conf, tmp, focus=[], ignore=[]): """compare dotfiles and return True if all identical""" dotfiles = conf.get_dotfiles(opts['profile']) if dotfiles == []: msg = 'no dotfile defined for this profile (\"{}\")' LOG.warn(msg.format(opts['profile'])) return True # compare only specific files same = True selected = dotfiles if focus: selected = _select(focus, dotfiles) if len(selected) < 1: return False t = Templategen(profile=opts['profile'], base=opts['dotpath'], variables=opts['variables'], debug=opts['debug']) inst = Installer(create=opts['create'], backup=opts['backup'], dry=opts['dry'], base=opts['dotpath'], workdir=opts['workdir'], debug=opts['debug']) comp = Comparator(diffopts=opts['dopts'], debug=opts['debug']) for dotfile in selected: if opts['debug']: LOG.dbg('comparing {}'.format(dotfile)) src = dotfile.src if not os.path.lexists(os.path.expanduser(dotfile.dst)): LOG.emph('\"{}\" does not exist on local\n'.format(dotfile.dst)) tmpsrc = None if dotfile.trans_r: # apply transformation tmpsrc = apply_trans(opts, dotfile) if not tmpsrc: # could not apply trans continue src = tmpsrc # install dotfile to temporary dir ret, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst) if not ret: # failed to install to tmp continue ignores = list(set(ignore + dotfile.cmpignore)) diff = comp.compare(insttmp, dotfile.dst, ignore=ignores) if tmpsrc: # clean tmp transformed dotfile if any tmpsrc = os.path.join(opts['dotpath'], tmpsrc) if os.path.exists(tmpsrc): remove(tmpsrc) if diff == '': if opts['debug']: LOG.dbg('diffing \"{}\" VS \"{}\"'.format( dotfile.key, dotfile.dst)) LOG.dbg('same file') else: LOG.log('diffing \"{}\" VS \"{}\"'.format(dotfile.key, dotfile.dst)) LOG.emph(diff) same = False return same
def cmd_importer(o): """import dotfile(s) from paths""" ret = True cnt = 0 paths = o.import_path for path in paths: if o.debug: LOG.dbg('trying to import {}'.format(path)) if not os.path.exists(path): LOG.err('\"{}\" does not exist, ignored!'.format(path)) ret = False continue dst = path.rstrip(os.sep) dst = os.path.abspath(dst) src = strip_home(dst) if o.import_as: # handle import as src = os.path.expanduser(o.import_as) src = src.rstrip(os.sep) src = os.path.abspath(src) src = strip_home(src) if o.debug: LOG.dbg('import src for {} as {}'.format(dst, src)) strip = '.' + os.sep if o.keepdot: strip = os.sep src = src.lstrip(strip) # set the link attribute linktype = o.import_link if linktype == LinkTypes.LINK_CHILDREN and \ not os.path.isdir(path): LOG.err('importing \"{}\" failed!'.format(path)) ret = False continue if o.debug: LOG.dbg('import dotfile: src:{} dst:{}'.format(src, dst)) # test no other dotfile exists with same # dst for this profile but different src dfs = o.conf.get_dotfile_by_dst(dst) if dfs: invalid = False for df in dfs: profiles = o.conf.get_profiles_by_dotfile_key(df.key) profiles = [x.key for x in profiles] if o.profile in profiles and \ not o.conf.get_dotfile_by_src_dst(src, dst): # same profile # different src LOG.err('duplicate dotfile for this profile') ret = False invalid = True break if invalid: continue # prepare hierarchy for dotfile srcf = os.path.join(o.dotpath, src) overwrite = not os.path.exists(srcf) if os.path.exists(srcf): overwrite = True if o.safe: c = Comparator(debug=o.debug, diff_cmd=o.diff_command) diff = c.compare(srcf, dst) if diff != '': # files are different, dunno what to do LOG.log('diff \"{}\" VS \"{}\"'.format(dst, srcf)) LOG.emph(diff) # ask user msg = 'Dotfile \"{}\" already exists, overwrite?' overwrite = LOG.ask(msg.format(srcf)) if o.debug: LOG.dbg('will overwrite: {}'.format(overwrite)) if overwrite: cmd = ['mkdir', '-p', '{}'.format(os.path.dirname(srcf))] if o.dry: LOG.dry('would run: {}'.format(' '.join(cmd))) else: r, _ = run(cmd, raw=False, debug=o.debug, checkerr=True) if not r: LOG.err('importing \"{}\" failed!'.format(path)) ret = False continue if o.dry: LOG.dry('would copy {} to {}'.format(dst, srcf)) else: if os.path.isdir(dst): if os.path.exists(srcf): shutil.rmtree(srcf) shutil.copytree(dst, srcf) else: shutil.copy2(dst, srcf) retconf = o.conf.new(src, dst, linktype) if retconf: LOG.sub('\"{}\" imported'.format(path)) cnt += 1 else: LOG.warn('\"{}\" ignored'.format(path)) if o.dry: LOG.dry('new config file would be:') LOG.raw(o.conf.dump()) else: o.conf.save() LOG.log('\n{} file(s) imported.'.format(cnt)) return ret
def cmd_compare(o, tmp): """compare dotfiles and return True if all identical""" dotfiles = o.dotfiles if not dotfiles: msg = 'no dotfile defined for this profile (\"{}\")' LOG.warn(msg.format(o.profile)) return True # compare only specific files same = True selected = dotfiles if o.compare_focus: selected = _select(o.compare_focus, dotfiles) if len(selected) < 1: return False t = Templategen(base=o.dotpath, variables=o.variables, func_file=o.func_file, filter_file=o.filter_file, debug=o.debug) tvars = t.add_tmp_vars() inst = Installer(create=o.create, backup=o.backup, dry=o.dry, base=o.dotpath, workdir=o.workdir, debug=o.debug, backup_suffix=o.install_backup_suffix, diff_cmd=o.diff_command) comp = Comparator(diff_cmd=o.diff_command, debug=o.debug) for dotfile in selected: # add dotfile variables t.restore_vars(tvars) newvars = dotfile.get_dotfile_variables() t.add_tmp_vars(newvars=newvars) if o.debug: LOG.dbg('comparing {}'.format(dotfile)) 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)) same = False continue tmpsrc = None if dotfile.trans_r: # apply transformation if o.debug: LOG.dbg('applying transformation before comparing') tmpsrc = apply_trans(o.dotpath, dotfile, t, debug=o.debug) if not tmpsrc: # could not apply trans same = False continue src = tmpsrc # is a symlink pointing to itself asrc = os.path.join(o.dotpath, os.path.expanduser(src)) adst = os.path.expanduser(dotfile.dst) if os.path.samefile(asrc, adst): if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.key, dotfile.dst)) LOG.dbg('points to itself') continue # install dotfile to temporary dir ret, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst) if not ret: # failed to install to tmp same = False continue ignores = list(set(o.compare_ignore + dotfile.cmpignore)) ignores = patch_ignores(ignores, dotfile.dst, debug=o.debug) diff = comp.compare(insttmp, dotfile.dst, ignore=ignores) if tmpsrc: # clean tmp transformed dotfile if any tmpsrc = os.path.join(o.dotpath, tmpsrc) if os.path.exists(tmpsrc): remove(tmpsrc) if diff == '': if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.key, dotfile.dst)) LOG.dbg('same file') else: line = '=> compare {}: diffing with \"{}\"' LOG.log(line.format(dotfile.key, dotfile.dst)) LOG.emph(diff) same = False return same
def cmd_importer(o): """import dotfile(s) from paths""" ret = True cnt = 0 paths = o.import_path for path in paths: if o.debug: LOG.dbg('trying to import {}'.format(path)) if not os.path.exists(path): LOG.err('\"{}\" does not exist, ignored!'.format(path)) ret = False continue dst = path.rstrip(os.sep) dst = os.path.abspath(dst) src = strip_home(dst) strip = '.' + os.sep if o.keepdot: strip = os.sep src = src.lstrip(strip) # set the link attribute linktype = o.import_link if linktype == LinkTypes.LINK_CHILDREN and \ not os.path.isdir(path): LOG.err('importing \"{}\" failed!'.format(path)) ret = False continue if o.debug: LOG.dbg('new dotfile: src:{} dst:{}'.format(src, dst)) # prepare hierarchy for dotfile srcf = os.path.join(o.dotpath, src) overwrite = not os.path.exists(srcf) if os.path.exists(srcf): overwrite = True if o.safe: c = Comparator(debug=o.debug) diff = c.compare(srcf, dst) if diff != '': # files are different, dunno what to do LOG.log('diff \"{}\" VS \"{}\"'.format(dst, srcf)) LOG.emph(diff) # ask user msg = 'Dotfile \"{}\" already exists, overwrite?' overwrite = LOG.ask(msg.format(srcf)) if o.debug: LOG.dbg('will overwrite: {}'.format(overwrite)) if overwrite: cmd = ['mkdir', '-p', '{}'.format(os.path.dirname(srcf))] if o.dry: LOG.dry('would run: {}'.format(' '.join(cmd))) else: r, _ = run(cmd, raw=False, debug=o.debug, checkerr=True) if not r: LOG.err('importing \"{}\" failed!'.format(path)) ret = False continue cmd = ['cp', '-R', '-L', dst, srcf] if o.dry: LOG.dry('would run: {}'.format(' '.join(cmd))) else: r, _ = run(cmd, raw=False, debug=o.debug, checkerr=True) if not r: LOG.err('importing \"{}\" failed!'.format(path)) ret = False continue retconf = o.conf.new(src, dst, linktype, o.profile) if retconf: LOG.sub('\"{}\" imported'.format(path)) cnt += 1 else: LOG.warn('\"{}\" ignored'.format(path)) if o.dry: LOG.dry('new config file would be:') LOG.raw(o.conf.dump()) else: o.conf.save() LOG.log('\n{} file(s) imported.'.format(cnt)) return ret
def cmd_compare(o, tmp): """compare dotfiles and return True if all identical""" dotfiles = o.dotfiles if not dotfiles: msg = 'no dotfile defined for this profile (\"{}\")' LOG.warn(msg.format(o.profile)) return True # compare only specific files same = True selected = dotfiles if o.compare_focus: selected = _select(o.compare_focus, dotfiles) if len(selected) < 1: return False t = Templategen(base=o.dotpath, variables=o.variables, func_file=o.func_file, filter_file=o.filter_file, debug=o.debug) tvars = t.add_tmp_vars() inst = Installer(create=o.create, backup=o.backup, dry=o.dry, base=o.dotpath, workdir=o.workdir, debug=o.debug, backup_suffix=o.install_backup_suffix, diff_cmd=o.diff_command) comp = Comparator(diff_cmd=o.diff_command, debug=o.debug) for dotfile in selected: if not dotfile.src and not dotfile.dst: # ignore fake dotfile continue # add dotfile variables t.restore_vars(tvars) newvars = dotfile.get_dotfile_variables() t.add_tmp_vars(newvars=newvars) # dotfiles does not exist / not installed if o.debug: LOG.dbg('comparing {}'.format(dotfile)) 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)) same = False continue # apply transformation tmpsrc = None if dotfile.trans_r: if o.debug: LOG.dbg('applying transformation before comparing') tmpsrc = apply_trans(o.dotpath, dotfile, t, debug=o.debug) if not tmpsrc: # could not apply trans same = False continue src = tmpsrc # is a symlink pointing to itself asrc = os.path.join(o.dotpath, os.path.expanduser(src)) adst = os.path.expanduser(dotfile.dst) if os.path.samefile(asrc, adst): if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.key, dotfile.dst)) LOG.dbg('points to itself') continue log_dst = dotfile.dst if log_dst.startswith(os.path.expanduser('~')): log_dst = log_dst.replace(os.path.expanduser('~'), '~', 1) # install dotfile to temporary dir and compare ret, err, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst, template=dotfile.template) if not ret: # failed to install to tmp line = '=> compare {}: error' LOG.log(line.format(dotfile.key, err)) LOG.err(err) same = False continue ignores = list(set(o.compare_ignore + dotfile.cmpignore)) ignores = patch_ignores(ignores, dotfile.dst, debug=o.debug) src_newer = os.path.getmtime(asrc) > os.path.getmtime(adst) if o.debug: LOG.dbg('src newer: {}'.format(src_newer)) diff = '' if o.compare_target == 'local' \ or (o.compare_target == 'smart' and not src_newer): diff = comp.compare(dotfile.dst, insttmp, ignore=ignores) diff_target = dotfile.dst else: diff = comp.compare(insttmp, dotfile.dst, ignore=ignores) diff_target = insttmp # clean tmp transformed dotfile if any if tmpsrc: tmpsrc = os.path.join(o.dotpath, tmpsrc) if os.path.exists(tmpsrc): remove(tmpsrc, LOG) if diff == '': # no difference if o.debug: line = '=> compare {}: diffing with \"{}\"' LOG.dbg(line.format(dotfile.src_key, log_dst)) LOG.dbg('same file') else: # print diff results line = '=> compare {}: diffing with \"{}\"' if diff_target == dotfile.dst: line = line.format(log_dst, dotfile.src_key) else: line = line.format(dotfile.src_key, log_dst) LOG.log(line) if o.compare_target == 'smart': if src_newer: LOG.sub('{} is newer'.format(dotfile.src_key)) else: LOG.sub('{} is newer'.format(log_dst)) if not o.compare_fileonly: LOG.emph(diff) same = False return same