Exemple #1
0
    def _parse(self):
        """parse config file"""
        # parse all actions
        if self.key_actions in self.content:
            if self.content[self.key_actions] is not None:
                for k, v in self.content[self.key_actions].items():
                    # loop through all actions
                    if k in [self.key_actions_pre, self.key_actions_post]:
                        # parse pre/post actions
                        items = self.content[self.key_actions][k].items()
                        for k2, v2 in items:
                            if k not in self.actions:
                                self.actions[k] = {}
                            self.actions[k][k2] = Action(k2, k, v2)
                    else:
                        # parse naked actions as post actions
                        if self.key_actions_post not in self.actions:
                            self.actions[self.key_actions_post] = {}
                        self.actions[self.key_actions_post][k] = Action(
                            k, '', v)

        # parse read transformations
        if self.key_trans_r in self.content:
            if self.content[self.key_trans_r] is not None:
                for k, v in self.content[self.key_trans_r].items():
                    self.trans_r[k] = Transform(k, v)

        # parse write transformations
        if self.key_trans_w in self.content:
            if self.content[self.key_trans_w] is not None:
                for k, v in self.content[self.key_trans_w].items():
                    self.trans_w[k] = Transform(k, v)

        # parse the profiles
        self.lnk_profiles = self.content[self.key_profiles]
        if self.lnk_profiles is None:
            # ensures self.lnk_profiles is a dict
            self.content[self.key_profiles] = {}
            self.lnk_profiles = self.content[self.key_profiles]
        for k, v in self.lnk_profiles.items():
            if self.key_profiles_dots in v and \
                    v[self.key_profiles_dots] is None:
                # if has the dotfiles entry but is empty
                # ensures it's an empty list
                v[self.key_profiles_dots] = []

        # parse the settings
        self.lnk_settings = self.content[self.key_settings]
        self._complete_settings()

        # parse the dotfiles
        # and construct the dict of objects per dotfile key
        if not self.content[self.key_dotfiles]:
            # ensures the dotfiles entry is a dict
            self.content[self.key_dotfiles] = {}
        for k, v in self.content[self.key_dotfiles].items():
            src = os.path.normpath(v[self.key_dotfiles_src])
            dst = os.path.normpath(v[self.key_dotfiles_dst])

            # Fail if both `link` and `link_children` present
            if self.key_dotfiles_link in v \
                    and self.key_dotfiles_link_children in v:
                msg = 'only one of `link` or `link_children` allowed per'
                msg += ' dotfile, error on dotfile "{}".'
                self.log.err(msg.format(k))

            # Otherwise, get link type
            link = LinkTypes.NOLINK
            if self.key_dotfiles_link in v and v[self.key_dotfiles_link]:
                link = LinkTypes.PARENTS
            if self.key_dotfiles_link_children in v \
                    and v[self.key_dotfiles_link_children]:
                link = LinkTypes.CHILDREN

            noempty = v[self.key_dotfiles_noempty] if \
                self.key_dotfiles_noempty \
                in v else self.lnk_settings[self.key_ignoreempty]
            itsactions = v[self.key_dotfiles_actions] if \
                self.key_dotfiles_actions in v else []
            actions = self._parse_actions(itsactions)

            # parse read transformation
            itstrans_r = v[self.key_dotfiles_trans_r] if \
                self.key_dotfiles_trans_r in v else None
            trans_r = None
            if itstrans_r:
                if type(itstrans_r) is list:
                    msg = 'One transformation allowed per dotfile'
                    msg += ', error on dotfile \"{}\"'
                    self.log.err(msg.format(k))
                    msg = 'Please modify your config file to: \"trans: {}\"'
                    self.log.err(msg.format(itstrans_r[0]))
                    msg = 'see https://github.com/deadc0de6/dotdrop/wiki/transformations#config-error-with-transformation-list'  # noqa
                    self.log.err(msg)
                    return False
                trans_r = self._parse_trans(itstrans_r, read=True)
                if not trans_r:
                    msg = 'unknown trans \"{}\" for \"{}\"'
                    self.log.err(msg.format(itstrans_r, k))
                    return False

            # parse write transformation
            itstrans_w = v[self.key_dotfiles_trans_w] if \
                self.key_dotfiles_trans_w in v else None
            trans_w = None
            if itstrans_w:
                if type(itstrans_w) is list:
                    msg = 'One write transformation allowed per dotfile'
                    msg += ', error on dotfile \"{}\"'
                    self.log.err(msg.format(k))
                    msg = 'Please modify your config file: \"trans_write: {}\"'
                    self.log.err(msg.format(itstrans_w[0]))
                    msg = 'see https://github.com/deadc0de6/dotdrop/wiki/transformations#config-error-with-transformation-list'  # noqa
                    self.log.err(msg)
                    return False
                trans_w = self._parse_trans(itstrans_w, read=False)
                if not trans_w:
                    msg = 'unknown trans_write \"{}\" for \"{}\"'
                    self.log.err(msg.format(itstrans_w, k))
                    return False

            # disable transformation when link is true
            if link != LinkTypes.NOLINK and (trans_r or trans_w):
                msg = 'transformations disabled for \"{}\"'.format(dst)
                msg += ' because link is True'
                self.log.warn(msg)
                trans_r = None
                trans_w = None

            # parse cmpignore pattern
            cmpignores = v[self.key_dotfiles_cmpignore] if \
                self.key_dotfiles_cmpignore in v else []

            # parse upignore pattern
            upignores = v[self.key_dotfiles_upignore] if \
                self.key_dotfiles_upignore in v else []

            # create new dotfile
            self.dotfiles[k] = Dotfile(k,
                                       dst,
                                       src,
                                       link=link,
                                       actions=actions,
                                       trans_r=trans_r,
                                       trans_w=trans_w,
                                       cmpignore=cmpignores,
                                       noempty=noempty,
                                       upignore=upignores)

        # assign dotfiles to each profile
        for k, v in self.lnk_profiles.items():
            self.prodots[k] = []
            if self.key_profiles_dots not in v:
                # ensures is a list
                v[self.key_profiles_dots] = []
            if not v[self.key_profiles_dots]:
                continue
            dots = v[self.key_profiles_dots]
            if self.key_all in dots:
                # add all if key ALL is used
                self.prodots[k] = list(self.dotfiles.values())
            else:
                # add the dotfiles
                for d in dots:
                    if d not in self.dotfiles:
                        msg = 'unknown dotfile \"{}\" for {}'.format(d, k)
                        self.log.err(msg)
                        continue
                    self.prodots[k].append(self.dotfiles[d])

        # handle "include" for each profile
        for k in self.lnk_profiles.keys():
            dots = self._get_included_dotfiles(k)
            self.prodots[k].extend(dots)
            # remove duplicates if any
            self.prodots[k] = list(set(self.prodots[k]))

        # make sure we have an absolute dotpath
        self.curdotpath = self.lnk_settings[self.key_dotpath]
        self.lnk_settings[self.key_dotpath] = \
            self._abs_path(self.curdotpath)

        # make sure we have an absolute workdir
        self.curworkdir = self.lnk_settings[self.key_workdir]
        self.lnk_settings[self.key_workdir] = \
            self._abs_path(self.curworkdir)

        return True
Exemple #2
0
    def _parse(self):
        """parse config file"""
        # parse all actions
        if self.key_actions in self.content:
            if self.content[self.key_actions] is not None:
                for k, v in self.content[self.key_actions].items():
                    # loop through all actions
                    if k in [self.key_actions_pre, self.key_actions_post]:
                        # parse pre/post actions
                        items = self.content[self.key_actions][k].items()
                        for k2, v2 in items:
                            if k not in self.actions:
                                self.actions[k] = {}
                            self.actions[k][k2] = Action(k2, v2)
                    else:
                        # parse naked actions as post actions
                        if self.key_actions_post not in self.actions:
                            self.actions[self.key_actions_post] = {}
                        self.actions[self.key_actions_post][k] = Action(k, v)

        # parse all transformations
        if self.key_trans in self.content:
            if self.content[self.key_trans] is not None:
                for k, v in self.content[self.key_trans].items():
                    self.trans[k] = Transform(k, v)

        # parse the profiles
        self.lnk_profiles = self.content[self.key_profiles]
        if self.lnk_profiles is None:
            # ensures self.lnk_profiles is a dict
            self.content[self.key_profiles] = {}
            self.lnk_profiles = self.content[self.key_profiles]
        for k, v in self.lnk_profiles.items():
            if self.key_profiles_dots in v and \
                    v[self.key_profiles_dots] is None:
                # if has the dotfiles entry but is empty
                # ensures it's an empty list
                v[self.key_profiles_dots] = []

        # parse the settings
        self.lnk_settings = self.content[self.key_settings]
        self._complete_settings()

        # parse the dotfiles
        # and construct the dict of objects per dotfile key
        if not self.content[self.key_dotfiles]:
            # ensures the dotfiles entry is a dict
            self.content[self.key_dotfiles] = {}
        for k, v in self.content[self.key_dotfiles].items():
            src = v[self.key_dotfiles_src]
            dst = v[self.key_dotfiles_dst]
            link = v[self.key_dotfiles_link] if self.key_dotfiles_link \
                in v else self.default_link
            itsactions = v[self.key_dotfiles_actions] if \
                self.key_dotfiles_actions in v else []
            actions = self._parse_actions(itsactions)
            itstrans = v[self.key_dotfiles_trans] if \
                self.key_dotfiles_trans in v else []
            trans = self._parse_trans(itstrans)
            if len(trans) > 0 and link:
                msg = 'transformations disabled for \"{}\"'.format(dst)
                msg += ' because link is True'
                self.log.warn(msg)
                trans = []
            self.dotfiles[k] = Dotfile(k,
                                       dst,
                                       src,
                                       link=link,
                                       actions=actions,
                                       trans=trans)

        # assign dotfiles to each profile
        for k, v in self.lnk_profiles.items():
            self.prodots[k] = []
            if self.key_profiles_dots not in v:
                # ensures is a list
                v[self.key_profiles_dots] = []
            if not v[self.key_profiles_dots]:
                continue
            dots = v[self.key_profiles_dots]
            if self.key_all in dots:
                # add all if key ALL is used
                self.prodots[k] = list(self.dotfiles.values())
            else:
                # add the dotfiles
                self.prodots[k].extend([self.dotfiles[d] for d in dots])

        # handle "include" for each profile
        for k in self.lnk_profiles.keys():
            dots = self._get_included_dotfiles(k)
            self.prodots[k].extend(dots)
            # remove duplicates if any
            self.prodots[k] = list(set(self.prodots[k]))

        # make sure we have an absolute dotpath
        self.curdotpath = self.lnk_settings[self.key_dotpath]
        self.lnk_settings[self.key_dotpath] = self.abs_dotpath(self.curdotpath)
        return True
    def _load(self):
        """load lower level config"""
        self.cfgyaml = CfgYaml(self.path,
                               self.profile_key,
                               debug=self.debug)

        # settings
        self.settings = Settings.parse(None, self.cfgyaml.settings)

        # dotfiles
        self.dotfiles = Dotfile.parse_dict(self.cfgyaml.dotfiles)
        if self.debug:
            self._debug_list('dotfiles', self.dotfiles)

        # profiles
        self.profiles = Profile.parse_dict(self.cfgyaml.profiles)
        if self.debug:
            self._debug_list('profiles', self.profiles)

        # actions
        self.actions = Action.parse_dict(self.cfgyaml.actions)
        if self.debug:
            self._debug_list('actions', self.actions)

        # trans_r
        self.trans_r = Transform.parse_dict(self.cfgyaml.trans_r)
        if self.debug:
            self._debug_list('trans_r', self.trans_r)

        # trans_w
        self.trans_w = Transform.parse_dict(self.cfgyaml.trans_w)
        if self.debug:
            self._debug_list('trans_w', self.trans_w)

        # variables
        self.variables = self.cfgyaml.variables
        if self.debug:
            self._debug_dict('variables', self.variables)

        # patch dotfiles in profiles
        self._patch_keys_to_objs(self.profiles,
                                 "dotfiles", self.get_dotfile)

        # patch action in dotfiles actions
        self._patch_keys_to_objs(self.dotfiles,
                                 "actions", self._get_action_w_args)
        # patch action in profiles actions
        self._patch_keys_to_objs(self.profiles,
                                 "actions", self._get_action_w_args)

        # patch actions in settings default_actions
        self._patch_keys_to_objs([self.settings],
                                 "default_actions", self._get_action_w_args)
        if self.debug:
            msg = 'default actions: {}'.format(self.settings.default_actions)
            self.log.dbg(msg)

        # patch trans_w/trans_r in dotfiles
        self._patch_keys_to_objs(self.dotfiles,
                                 "trans_r",
                                 self._get_trans_w_args(self._get_trans_r),
                                 islist=False)
        self._patch_keys_to_objs(self.dotfiles,
                                 "trans_w",
                                 self._get_trans_w_args(self._get_trans_w),
                                 islist=False)
Exemple #4
0
    def test_update(self):
        """Test the update function"""
        # setup some directories
        fold_config = os.path.join(os.path.expanduser('~'), '.config')
        create_dir(fold_config)
        fold_subcfg = os.path.join(os.path.expanduser('~'), '.config',
                                   get_string(5))
        create_dir(fold_subcfg)
        self.addCleanup(clean, fold_subcfg)
        fold_tmp = get_tempdir()
        create_dir(fold_tmp)
        self.addCleanup(clean, fold_tmp)

        # create the directories
        tmp = get_tempdir()
        self.assertTrue(os.path.exists(tmp))
        self.addCleanup(clean, tmp)

        dotfilespath = get_tempdir()
        self.assertTrue(os.path.exists(dotfilespath))
        self.addCleanup(clean, dotfilespath)

        # create the dotfiles to test
        d1, c1 = create_random_file(fold_config)
        self.assertTrue(os.path.exists(d1))
        self.addCleanup(clean, d1)

        d2, c2 = create_random_file(fold_config)
        self.assertTrue(os.path.exists(d2))
        self.addCleanup(clean, d2)

        # template
        d3t, c3t = create_random_file(fold_config)
        self.assertTrue(os.path.exists(d3t))
        self.addCleanup(clean, d3t)

        # sub dirs
        dsubstmp = get_tempdir()
        self.assertTrue(os.path.exists(dsubstmp))
        self.addCleanup(clean, dsubstmp)
        dirsubs = os.path.basename(dsubstmp)

        dir1string = 'somedir'
        dir1 = os.path.join(dsubstmp, dir1string)
        create_dir(dir1)
        dir1sub1str = 'sub1'
        sub1 = os.path.join(dir1, dir1sub1str)
        create_dir(sub1)
        dir1sub2str = 'sub2'
        sub2 = os.path.join(dir1, dir1sub2str)
        create_dir(sub2)
        f1s1, f1s1c1 = create_random_file(sub1)
        self.assertTrue(os.path.exists(f1s1))
        f1s2, f1s2c1 = create_random_file(sub2)
        self.assertTrue(os.path.exists(f1s2))

        # create the directory to test
        dpath = os.path.join(fold_config, get_string(5))
        dir1 = create_dir(dpath)
        dirf1, _ = create_random_file(dpath)
        self.addCleanup(clean, dir1)

        # create the config file
        profile = get_string(5)
        confpath = create_fake_config(dotfilespath,
                                      configname=self.CONFIG_NAME,
                                      dotpath=self.CONFIG_DOTPATH,
                                      backup=self.CONFIG_BACKUP,
                                      create=self.CONFIG_CREATE)
        self.assertTrue(os.path.exists(confpath))
        o = load_options(confpath, profile)
        o.debug = True
        o.update_showpatch = True
        dfiles = [d1, dir1, d2, d3t, dsubstmp]

        # import the files
        o.import_path = dfiles
        cmd_importer(o)

        # get new config
        o = load_options(confpath, profile)
        o.safe = False
        o.debug = True
        o.update_showpatch = True
        trans = Transform('trans', 'cp -r {0} {1}')
        d3tb = os.path.basename(d3t)
        for dotfile in o.dotfiles:
            if os.path.basename(dotfile.dst) == d3tb:
                # patch the template
                src = os.path.join(o.dotpath, dotfile.src)
                src = os.path.expanduser(src)
                edit_content(src, '{{@@ profile @@}}')
            if os.path.basename(dotfile.dst) == dirsubs:
                # retrieve the path of the sub in the dotpath
                d1indotpath = os.path.join(o.dotpath, dotfile.src)
                d1indotpath = os.path.expanduser(d1indotpath)
            dotfile.trans_w = trans

        # update template
        o.update_path = [d3t]
        self.assertFalse(cmd_update(o))

        # update sub dirs
        gone = os.path.join(d1indotpath, dir1string)
        gone = os.path.join(gone, dir1sub1str)
        self.assertTrue(os.path.exists(gone))
        clean(sub1)  # dir1sub1str
        self.assertTrue(os.path.exists(gone))
        o.update_path = [dsubstmp]
        cmd_update(o)
        self.assertFalse(os.path.exists(gone))

        # edit the files
        edit_content(d1, 'newcontent')
        edit_content(dirf1, 'newcontent')

        # add more file
        dirf2, _ = create_random_file(dpath)

        # add more dirs
        dpath = os.path.join(dpath, get_string(5))
        create_dir(dpath)
        create_random_file(dpath)

        # update it
        o.update_path = [d1, dir1]
        cmd_update(o)

        # test content
        newcontent = open(d1, 'r').read()
        self.assertTrue(newcontent == 'newcontent')
        newcontent = open(dirf1, 'r').read()
        self.assertTrue(newcontent == 'newcontent')

        edit_content(d2, 'newcontentbykey')

        # update it by key
        dfiles = o.dotfiles
        d2key = ''
        for ds in dfiles:
            t = os.path.expanduser(ds.dst)
            if t == d2:
                d2key = ds.key
                break
        self.assertTrue(d2key != '')
        o.update_path = [d2key]
        o.update_iskey = True
        cmd_update(o)

        # test content
        newcontent = open(d2, 'r').read()
        self.assertTrue(newcontent == 'newcontentbykey')