Beispiel #1
0
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('')
Beispiel #2
0
 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
Beispiel #3
0
    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)
Beispiel #4
0
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))
Beispiel #5
0
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))
Beispiel #6
0
    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)
Beispiel #7
0
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('')
Beispiel #8
0
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('')
Beispiel #9
0
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)
Beispiel #10
0
    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)
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
    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)