def cmd_files(o): """list all dotfiles for a specific profile""" if o.profile not in [p.key for p in o.profiles]: LOG.warn('unknown profile \"{}\"'.format(o.profile)) return what = 'Dotfile(s)' if o.files_templateonly: what = 'Template(s)' LOG.emph('{} for profile \"{}\":\n'.format(what, o.profile)) for dotfile in o.dotfiles: if o.files_templateonly: src = os.path.join(o.dotpath, dotfile.src) if not Templategen.is_template(src): continue if o.files_grepable: fmt = '{},dst:{},src:{},link:{}' fmt = fmt.format(dotfile.key, dotfile.dst, dotfile.src, dotfile.link.name.lower()) if dotfile.chmod: fmt += ',chmod:{:o}' else: fmt += ',chmod:None' LOG.raw(fmt) else: LOG.log('{}'.format(dotfile.key), bold=True) LOG.sub('dst: {}'.format(dotfile.dst)) LOG.sub('src: {}'.format(dotfile.src)) LOG.sub('link: {}'.format(dotfile.link.name.lower())) if dotfile.chmod: LOG.sub('chmod: {:o}'.format(dotfile.chmod)) LOG.log('')
def _is_template(self, path): if not Templategen.is_template(path): if self.debug: self.log.dbg('{} is NO template'.format(path)) return False self.log.warn('{} uses template, update manually'.format(path)) return True
def link(self, templater, src, dst, actions=[]): """set src as the link target of dst""" if self.debug: self.log.dbg('link {} to {}'.format(src, dst)) self.action_executed = False src = os.path.normpath(os.path.join(self.base, os.path.expanduser(src))) if not os.path.exists(src): self.log.err('source dotfile does not exist: {}'.format(src)) return [] dst = os.path.normpath(os.path.expanduser(dst)) if self.totemp: # ignore actions return self.install(templater, src, dst, actions=[]) if Templategen.is_template(src): if self.debug: self.log.dbg('dotfile is a template') self.log.dbg('install to {} and symlink'.format(self.workdir)) tmp = self._pivot_path(dst, self.workdir, striphome=True) i = self.install(templater, src, tmp, actions=actions) if not i and not os.path.exists(tmp): return [] src = tmp return self._link(src, dst, actions=actions)
def _detail(dotpath, dotfile): """print details on all files under a dotfile entry""" LOG.log('{} (dst: \"{}\", link: {})'.format(dotfile.key, dotfile.dst, dotfile.link.name.lower())) path = os.path.join(dotpath, os.path.expanduser(dotfile.src)) if not os.path.isdir(path): template = 'no' if Templategen.is_template(path): template = 'yes' LOG.sub('{} (template:{})'.format(path, template)) else: for root, dir, files in os.walk(path): for f in files: p = os.path.join(root, f) template = 'no' if Templategen.is_template(p): template = 'yes' LOG.sub('{} (template:{})'.format(p, template))
def _detail(dotpath, dotfile): """display details on all files under a dotfile entry""" entry = '{}'.format(dotfile.key) attribs = [] attribs.append('dst: \"{}\"'.format(dotfile.dst)) attribs.append('link: \"{}\"'.format(dotfile.link.name.lower())) attribs.append('chmod: \"{}\"'.format(dotfile.chmod)) LOG.log('{} ({})'.format(entry, ', '.join(attribs))) path = os.path.join(dotpath, os.path.expanduser(dotfile.src)) if not os.path.isdir(path): template = 'no' if dotfile.template and Templategen.is_template(path): template = 'yes' LOG.sub('{} (template:{})'.format(path, template)) else: for root, _, files in os.walk(path): for f in files: p = os.path.join(root, f) template = 'no' if dotfile.template and Templategen.is_template(p): template = 'yes' LOG.sub('{} (template:{})'.format(p, template))
def link(self, templater, src, dst, actionexec=None, template=True): """ set src as the link target of dst @templater: the templater @src: dotfile source path in dotpath @dst: dotfile destination path in the FS @actionexec: action executor callback @template: template this dotfile return - True, None : success - False, error_msg : error - False, None : ignored """ if self.debug: self.log.dbg('link \"{}\" to \"{}\"'.format(src, dst)) if not dst or not src: if self.debug: self.log.dbg('empty dst for {}'.format(src)) return self._log_install(True, None) self.action_executed = False src = os.path.normpath(os.path.join(self.base, os.path.expanduser(src))) if not os.path.exists(src): err = 'source dotfile does not exist: {}'.format(src) return self._log_install(False, err) dst = os.path.normpath(os.path.expanduser(dst)) if self.totemp: # ignore actions b, e = self.install(templater, src, dst, actionexec=None, template=template) return self._log_install(b, e) if template and Templategen.is_template(src): if self.debug: self.log.dbg('dotfile is a template') self.log.dbg('install to {} and symlink'.format(self.workdir)) tmp = self._pivot_path(dst, self.workdir, striphome=True) i, err = self.install(templater, src, tmp, actionexec=actionexec, template=template) if not i and not os.path.exists(tmp): return self._log_install(i, err) src = tmp b, e = self._link(src, dst, actionexec=actionexec) return self._log_install(b, e)
def cmd_list_files(o): """list all dotfiles for a specific profile""" if o.profile not in o.profiles: LOG.warn('unknown profile \"{}\"'.format(o.profile)) return what = 'Dotfile(s)' if o.listfiles_templateonly: what = 'Template(s)' LOG.emph('{} for profile \"{}\"\n'.format(what, o.profile)) for dotfile in o.dotfiles: if o.listfiles_templateonly: src = os.path.join(o.dotpath, dotfile.src) if not Templategen.is_template(src): continue LOG.log('{} (src: \"{}\", link: {})'.format(dotfile.key, dotfile.src, dotfile.link.name.lower())) LOG.sub('{}'.format(dotfile.dst)) LOG.log('')
def cmd_list_files(opts, conf, templateonly=False): """list all dotfiles for a specific profile""" if not opts['profile'] in conf.get_profiles(): LOG.warn('unknown profile \"{}\"'.format(opts['profile'])) return what = 'Dotfile(s)' if templateonly: what = 'Template(s)' LOG.emph('{} for profile \"{}\"\n'.format(what, opts['profile'])) for dotfile in conf.get_dotfiles(opts['profile']): if templateonly: src = os.path.join(opts['dotpath'], dotfile.src) if not Templategen.is_template(src): continue LOG.log('{} (src: \"{}\", link: {})'.format(dotfile.key, dotfile.src, dotfile.link)) LOG.sub('{}'.format(dotfile.dst)) LOG.log('')
def _workdir_enum(opts): workdir_files = [] for root, _, files in os.walk(opts.workdir): for file in files: fpath = os.path.join(root, file) workdir_files.append(fpath) for dotfile in opts.dotfiles: src = os.path.join(opts.dotpath, dotfile.src) if dotfile.link == LinkTypes.NOLINK: # ignore not link files continue if not Templategen.is_template(src): # ignore not template continue newpath = pivot_path(dotfile.dst, opts.workdir, striphome=True, logger=None) if os.path.isdir(newpath): # recursive pattern = '{}/*'.format(newpath) files = workdir_files.copy() for file in files: if fnmatch.fnmatch(file, pattern): workdir_files.remove(file) # only checks children children = [f.path for f in os.scandir(newpath)] for child in children: if child in workdir_files: workdir_files.remove(child) else: if newpath in workdir_files: workdir_files.remove(newpath) for wfile in workdir_files: line = '=> \"{}\" does not exist in dotdrop' LOG.log(line.format(wfile)) return len(workdir_files)
def link_children(self, templater, src, dst, actionexec=None, template=True): """ link all files under a given directory @templater: the templater @src: dotfile source path in dotpath @dst: dotfile destination path in the FS @actionexec: action executor callback @template: template this dotfile return - True, None: success - False, error_msg: error - False, None, ignored """ if self.debug: self.log.dbg('link_children \"{}\" to \"{}\"'.format(src, dst)) if not dst or not src: if self.debug: self.log.dbg('empty dst for {}'.format(src)) return self._log_install(True, None) self.action_executed = False parent = os.path.join(self.base, os.path.expanduser(src)) # Fail if source doesn't exist if not os.path.exists(parent): err = 'source dotfile does not exist: {}'.format(parent) return self._log_install(False, err) # Fail if source not a directory if not os.path.isdir(parent): if self.debug: self.log.dbg('symlink children of {} to {}'.format(src, dst)) err = 'source dotfile is not a directory: {}'.format(parent) return self._log_install(False, err) dst = os.path.normpath(os.path.expanduser(dst)) if not os.path.lexists(dst): self.log.sub('creating directory "{}"'.format(dst)) os.makedirs(dst) if os.path.isfile(dst): msg = ''.join([ 'Remove regular file {} and ', 'replace with empty directory?', ]).format(dst) if self.safe and not self.log.ask(msg): err = 'ignoring "{}", nothing installed'.format(dst) return self._log_install(False, err) os.unlink(dst) os.mkdir(dst) children = os.listdir(parent) srcs = [os.path.normpath(os.path.join(parent, child)) for child in children] dsts = [os.path.normpath(os.path.join(dst, child)) for child in children] installed = 0 for i in range(len(children)): src = srcs[i] dst = dsts[i] if self.debug: self.log.dbg('symlink child {} to {}'.format(src, dst)) if template and Templategen.is_template(src): if self.debug: self.log.dbg('dotfile is a template') self.log.dbg('install to {} and symlink' .format(self.workdir)) tmp = self._pivot_path(dst, self.workdir, striphome=True) r, e = self.install(templater, src, tmp, actionexec=actionexec, template=template) if not r and e and not os.path.exists(tmp): continue src = tmp ret, err = self._link(src, dst, actionexec=actionexec) if ret: installed += 1 # void actionexec if dotfile installed # to prevent from running actions multiple times actionexec = None else: if err: return self._log_install(ret, err) return self._log_install(installed > 0, None)
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 _dotfile_install(o, dotfile, tmpdir=None): """ install a dotfile returns <success, dotfile key, err> """ # installer inst = _get_install_installer(o, tmpdir=tmpdir) # templater t = _get_templater(o) # add dotfile variables newvars = dotfile.get_dotfile_variables() t.add_tmp_vars(newvars=newvars) preactions = [] if not o.install_temporary: preactions.extend(dotfile.get_pre_actions()) defactions = o.install_default_actions_pre pre_actions_exec = action_executor(o, preactions, defactions, t, post=False) if o.debug: LOG.dbg('installing dotfile: \"{}\"'.format(dotfile.key)) LOG.dbg(dotfile.prt()) ignores = list(set(o.install_ignore + dotfile.instignore)) ignores = patch_ignores(ignores, dotfile.dst, debug=o.debug) is_template = dotfile.template and Templategen.is_template( dotfile.src, ignore=ignores, ) if hasattr(dotfile, 'link') and dotfile.link == LinkTypes.LINK: # link r, err = inst.install(t, dotfile.src, dotfile.dst, dotfile.link, actionexec=pre_actions_exec, is_template=is_template, ignore=ignores, chmod=dotfile.chmod) elif hasattr(dotfile, 'link') and \ dotfile.link == LinkTypes.LINK_CHILDREN: # link_children r, err = inst.install(t, dotfile.src, dotfile.dst, dotfile.link, actionexec=pre_actions_exec, is_template=is_template, chmod=dotfile.chmod, ignore=ignores) else: # nolink src = dotfile.src tmp = None if dotfile.trans_r: tmp = apply_trans(o.dotpath, dotfile, t, debug=o.debug) if not tmp: return False, dotfile.key, None src = tmp r, err = inst.install(t, src, dotfile.dst, LinkTypes.NOLINK, actionexec=pre_actions_exec, noempty=dotfile.noempty, ignore=ignores, is_template=is_template, chmod=dotfile.chmod) if tmp: tmp = os.path.join(o.dotpath, tmp) if os.path.exists(tmp): removepath(tmp, LOG) # check result of installation if r: # dotfile was installed if not o.install_temporary: defactions = o.install_default_actions_post postactions = dotfile.get_post_actions() post_actions_exec = action_executor(o, postactions, defactions, t, post=True) post_actions_exec() else: # dotfile was NOT installed if o.install_force_action: # pre-actions if o.debug: LOG.dbg('force pre action execution ...') pre_actions_exec() # post-actions if o.debug: LOG.dbg('force post action execution ...') defactions = o.install_default_actions_post postactions = dotfile.get_post_actions() post_actions_exec = action_executor(o, postactions, defactions, t, post=True) post_actions_exec() return r, dotfile.key, err
def linkall(self, templater, src, dst, actions=[]): """link all dotfiles in a given directory""" if self.debug: self.log.dbg('linkall {} to {}'.format(src, dst)) self.action_executed = False parent = os.path.join(self.base, os.path.expanduser(src)) # Fail if source doesn't exist if not os.path.exists(parent): self.log.err('source dotfile does not exist: {}'.format(parent)) return [] # Fail if source not a directory if not os.path.isdir(parent): if self.debug: self.log.dbg('symlink children of {} to {}'.format(src, dst)) self.log.err('source dotfile is not a directory: {}' .format(parent)) return [] dst = os.path.normpath(os.path.expanduser(dst)) if not os.path.lexists(dst): self.log.sub('creating directory "{}"'.format(dst)) os.makedirs(dst) if os.path.isfile(dst): msg = ''.join([ 'Remove regular file {} and ', 'replace with empty directory?', ]).format(dst) if self.safe and not self.log.ask(msg): msg = 'ignoring "{}", nothing installed' self.log.warn(msg.format(dst)) return [] os.unlink(dst) os.mkdir(dst) children = os.listdir(parent) srcs = [os.path.normpath(os.path.join(parent, child)) for child in children] dsts = [os.path.normpath(os.path.join(dst, child)) for child in children] for i in range(len(children)): src = srcs[i] dst = dsts[i] if self.debug: self.log.dbg('symlink child {} to {}'.format(src, dst)) if Templategen.is_template(src): if self.debug: self.log.dbg('dotfile is a template') self.log.dbg('install to {} and symlink' .format(self.workdir)) tmp = self._pivot_path(dst, self.workdir, striphome=True) i = self.install(templater, src, tmp, actions=actions) if not i and not os.path.exists(tmp): continue src = tmp result = self._link(src, dst, actions) # Empty actions if dotfile installed # This prevents from running actions multiple times if len(result): actions = [] return (src, dst)