def test_install(self): '''Test the install function''' tmp = get_tempfolder() self.assertTrue(os.path.exists(tmp)) self.addCleanup(clean, tmp) dst = get_tempfolder() self.assertTrue(os.path.exists(dst)) self.addCleanup(clean, dst) # create the dotfile in dotdrop f1, c1 = create_random_file(tmp) dst1 = os.path.join(dst, get_string(6)) d1 = Dotfile(get_string(5), dst1, os.path.basename(f1)) f2, c2 = create_random_file(tmp) dst2 = os.path.join(dst, get_string(6)) d2 = Dotfile(get_string(5), dst2, os.path.basename(f2)) with open(f2, 'w') as f: f.write(self.TEMPLATE) f3, _ = create_random_file(tmp, binary=True) dst3 = os.path.join(dst, get_string(6)) d3 = Dotfile(get_string(5), dst3, os.path.basename(f3)) # to test backup f4, c4 = create_random_file(tmp) dst4 = os.path.join(dst, get_string(6)) d4 = Dotfile(get_string(6), dst4, os.path.basename(f4)) with open(dst4, 'w') as f: f.write(get_string(16)) # generate the config and stuff profile = get_string(5) confpath = os.path.join(tmp, self.CONFIG_NAME) self.fake_config(confpath, [d1, d2, d3, d4], profile, tmp) conf = Cfg(confpath, tmp) self.assertTrue(conf is not None) # install them conf, opts = load_config(confpath, tmp, profile) opts['safe'] = False install(opts, conf) # now compare the generated files self.assertTrue(os.path.exists(dst1)) self.assertTrue(os.path.exists(dst2)) self.assertTrue(os.path.exists(dst3)) # make sure backup is there b = dst4 + Installer.BACKUP_SUFFIX self.assertTrue(os.path.exists(b)) self.assertTrue(filecmp.cmp(f1, dst1, shallow=True)) f2content = open(dst2, 'r').read() self.assertTrue(f2content == self.RESULT) self.assertTrue(filecmp.cmp(f3, dst3, shallow=True))
def new(self, src, dst, link, profile_key): """ import a new dotfile @src: path in dotpath @dst: path in FS @link: LinkType @profile_key: to which profile """ dst = self.path_to_dotfile_dst(dst) dotfile = self.get_dotfile_by_dst(dst) if not dotfile: # get a new dotfile with a unique key key = self._get_new_dotfile_key(dst) if self.debug: self.log.dbg('new dotfile key: {}'.format(key)) # add the dotfile self.cfgyaml.add_dotfile(key, src, dst, link) dotfile = Dotfile(key, dst, src) key = dotfile.key ret = self.cfgyaml.add_dotfile_to_profile(key, profile_key) if self.debug: self.log.dbg('new dotfile {} to profile {}'.format( key, profile_key)) # reload self.cfgyaml.save() if self.debug: self.log.dbg('RELOADING') self._load() return ret
def _create_new_dotfile(self, src, dst, link): """create a new dotfile""" # get a new dotfile with a unique key key = self._get_new_dotfile_key(dst) if self.debug: self.log.dbg('new dotfile key: {}'.format(key)) # add the dotfile self.cfgyaml.add_dotfile(key, src, dst, link) return Dotfile(key, dst, src)
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(): self.actions[k] = Action(k, v) # parse the profiles self.profiles = self.content[self.key_profiles] if self.profiles is None: self.content[self.key_profiles] = {} self.profiles = self.content[self.key_profiles] for k, v in self.profiles.items(): if v[self.key_profiles_dots] is None: v[self.key_profiles_dots] = [] # parse the configs self.configs = self.content[self.key_config] # parse the dotfiles if not self.content[self.key_dotfiles]: 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 False entries = v[self.key_dotfiles_actions] if \ self.key_dotfiles_actions in v else [] actions = self._parse_actions(self.actions, entries) self.dotfiles[k] = Dotfile(k, dst, src, link=link, actions=actions) # assign dotfiles to each profile for k, v in self.profiles.items(): self.prodots[k] = [] if self.key_profiles_dots not in v: 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: self.prodots[k] = list(self.dotfiles.values()) else: self.prodots[k].extend([self.dotfiles[d] for d in dots]) # handle "include" for each profile for k in self.profiles.keys(): dots = self._get_included_dotfiles(k) self.prodots[k].extend(dots) # no duplicates self.prodots[k] = list(set(self.prodots[k])) # make sure we have an absolute dotpath self.curdotpath = self.configs[self.key_dotpath] self.configs[self.key_dotpath] = self.get_abs_dotpath(self.curdotpath) return True
def _create_new_dotfile(self, src, dst, link, chmod=None): """create a new dotfile""" # get a new dotfile with a unique key key = self._get_new_dotfile_key(dst) self.log.dbg('new dotfile key: {}'.format(key)) # add the dotfile if not self.cfgyaml.add_dotfile(key, src, dst, link, chmod=chmod): return None return Dotfile(key, dst, src)
def importer(opts, conf, paths): """import dotfile(s) from paths""" home = os.path.expanduser(TILD) cnt = 0 for path in paths: if not os.path.lexists(path): LOG.err('\"{}\" does not exist, ignored !'.format(path)) continue dst = path.rstrip(os.sep) src = dst if dst.startswith(home): src = dst[len(home):] strip = '.' + os.sep if opts['keepdot']: strip = os.sep src = src.lstrip(strip) # create a new dotfile dotfile = Dotfile('', dst, src) linkit = opts['link'] or opts['link_by_default'] retconf, new_dotfile = conf.new(dotfile, opts['profile'], linkit) dotfile = new_dotfile # prepare hierarchy for dotfile srcf = os.path.join(CUR, opts['dotpath'], src) if not os.path.exists(srcf): cmd = ['mkdir', '-p', '{}'.format(os.path.dirname(srcf))] if opts['dry']: LOG.dry('would run: {}'.format(' '.join(cmd))) else: run(cmd, raw=False, debug=opts['debug']) cmd = ['cp', '-R', '-L', dst, srcf] if opts['dry']: LOG.dry('would run: {}'.format(' '.join(cmd))) if linkit: LOG.dry('would symlink {} to {}'.format(srcf, dst)) else: run(cmd, raw=False, debug=opts['debug']) if linkit: remove(dst) os.symlink(srcf, dst) if retconf: LOG.sub('\"{}\" imported'.format(path)) cnt += 1 else: LOG.warn('\"{}\" ignored'.format(path)) if opts['dry']: LOG.dry('new config file would be:') LOG.raw(conf.dump()) else: conf.save() LOG.log('\n{} file(s) imported.'.format(cnt))
def test_jhelpers(self): """Test the install function""" # dotpath location tmp = get_tempdir() self.assertTrue(os.path.exists(tmp)) self.addCleanup(clean, tmp) # where dotfiles will be installed dst = get_tempdir() self.assertTrue(os.path.exists(dst)) self.addCleanup(clean, dst) # create the dotfile in dotdrop f1, c1 = create_random_file(tmp) with open(f1, 'w') as f: f.write(self.TEMPLATE) dst1 = os.path.join(dst, get_string(6)) d1 = Dotfile(get_string(5), dst1, os.path.basename(f1)) # generate the config and stuff profile = get_string(5) confpath = os.path.join(tmp, self.CONFIG_NAME) self.fake_config(confpath, d1, profile, tmp) conf = Cfg(confpath, profile, debug=True) self.assertTrue(conf is not None) # install them o = load_options(confpath, profile) o.safe = False o.install_showdiff = True o.variables = {} o.debug = True cmd_install(o) # now compare the generated files self.assertTrue(os.path.exists(dst1)) f1content = open(dst1, 'r').read() self.assertTrue(f1content == self.RESULT)
def test_install(self): """Test the install function""" # dotpath location tmp = get_tempdir() self.assertTrue(os.path.exists(tmp)) self.addCleanup(clean, tmp) # where dotfiles will be installed dst = get_tempdir() self.assertTrue(os.path.exists(dst)) self.addCleanup(clean, dst) # create the dotfile in dotdrop f1, c1 = create_random_file(tmp) dst1 = os.path.join(dst, get_string(6)) d1 = Dotfile(get_string(5), dst1, os.path.basename(f1)) # fake a print self.assertTrue(str(d1) != '') f2, c2 = create_random_file(tmp) dst2 = os.path.join(dst, get_string(6)) d2 = Dotfile(get_string(5), dst2, os.path.basename(f2)) with open(f2, 'w') as f: f.write(self.TEMPLATE) f3, _ = create_random_file(tmp, binary=True) dst3 = os.path.join(dst, get_string(6)) d3 = Dotfile(get_string(5), dst3, os.path.basename(f3)) # create a directory dotfile dir1 = os.path.join(tmp, 'somedir') create_dir(dir1) fd, _ = create_random_file(dir1) dstd = os.path.join(dst, get_string(6)) ddot = Dotfile(get_string(5), dstd, os.path.basename(dir1)) # to test backup f4, c4 = create_random_file(tmp) dst4 = os.path.join(dst, get_string(6)) d4 = Dotfile(key=get_string(6), dst=dst4, src=os.path.basename(f4)) with open(dst4, 'w') as f: f.write(get_string(16)) # to test link f5, c5 = create_random_file(tmp) dst5 = os.path.join(dst, get_string(6)) self.addCleanup(clean, dst5) d5 = Dotfile(get_string(6), dst5, os.path.basename(f5), link=True) # create the dotfile directories in dotdrop dir1 = create_dir(os.path.join(tmp, get_string(6))) self.assertTrue(os.path.exists(dir1)) self.addCleanup(clean, dir1) dst6 = os.path.join(dst, get_string(6)) # fill with files sub1, _ = create_random_file(dir1, template=True) self.assertTrue(os.path.exists(sub1)) sub2, _ = create_random_file(dir1) self.assertTrue(os.path.exists(sub2)) # make up the dotfile d6 = Dotfile(get_string(6), dst6, os.path.basename(dir1)) # to test symlink directories dir2 = create_dir(os.path.join(tmp, get_string(6))) self.assertTrue(os.path.exists(dir2)) self.addCleanup(clean, dir2) dst7 = os.path.join(dst, get_string(6)) # fill with files sub3, _ = create_random_file(dir2) self.assertTrue(os.path.exists(sub3)) sub4, _ = create_random_file(dir2) self.assertTrue(os.path.exists(sub4)) # make up the dotfile d7 = Dotfile(get_string(6), dst7, os.path.basename(dir2), link=True) # to test actions value = get_string(12) fact = '/tmp/action' self.addCleanup(clean, fact) act1 = Action('testaction', 'post', 'echo "{}" > {}'.format(value, fact)) f8, c8 = create_random_file(tmp) dst8 = os.path.join(dst, get_string(6)) d8 = Dotfile(get_string(6), dst8, os.path.basename(f8), actions=[act1]) # to test transformations trans1 = 'trans1' trans2 = 'trans2' cmd = 'cat {0} | sed \'s/%s/%s/g\' > {1}' % (trans1, trans2) tr = Action('testtrans', 'post', cmd) f9, c9 = create_random_file(tmp, content=trans1) dst9 = os.path.join(dst, get_string(6)) d9 = Dotfile(get_string(6), dst9, os.path.basename(f9), trans_r=tr) # to test template f10, _ = create_random_file(tmp, content='{{@@ header() @@}}') dst10 = os.path.join(dst, get_string(6)) d10 = Dotfile(get_string(6), dst10, os.path.basename(f10)) # generate the config and stuff profile = get_string(5) confpath = os.path.join(tmp, self.CONFIG_NAME) dotfiles = [d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, ddot] self.fake_config(confpath, dotfiles, profile, tmp, [act1], [tr]) conf = Cfg(confpath) self.assertTrue(conf is not None) # install them conf, opts = load_config(confpath, profile) opts['safe'] = False opts['debug'] = True opts['showdiff'] = True opts['variables'] = {} cmd_install(opts, conf) # now compare the generated files self.assertTrue(os.path.exists(dst1)) self.assertTrue(os.path.exists(dst2)) self.assertTrue(os.path.exists(dst3)) self.assertTrue(os.path.exists(dst5)) self.assertTrue(os.path.exists(dst6)) self.assertTrue(os.path.exists(dst7)) self.assertTrue(os.path.exists(dst8)) self.assertTrue(os.path.exists(dst10)) self.assertTrue(os.path.exists(fd)) # check if 'dst5' is a link whose target is 'f5' self.assertTrue(os.path.islink(dst5)) self.assertTrue(os.path.realpath(dst5) == os.path.realpath(f5)) # check if 'dst7' is a link whose target is 'dir2' self.assertTrue(os.path.islink(dst7)) self.assertTrue(os.path.realpath(dst7) == os.path.realpath(dir2)) # make sure backup is there b = dst4 + Installer.BACKUP_SUFFIX self.assertTrue(os.path.exists(b)) self.assertTrue(filecmp.cmp(f1, dst1, shallow=True)) f2content = open(dst2, 'r').read() self.assertTrue(f2content == self.RESULT) self.assertTrue(filecmp.cmp(f3, dst3, shallow=True)) # test action has been executed self.assertTrue(os.path.exists(fact)) self.assertTrue(str(act1) != '') actcontent = open(fact, 'r').read().rstrip() self.assertTrue(actcontent == value) # test transformation has been done self.assertTrue(os.path.exists(dst9)) transcontent = open(dst9, 'r').read().rstrip() self.assertTrue(transcontent == trans2) # test template has been remplaced self.assertTrue(os.path.exists(dst10)) tempcontent = open(dst10, 'r').read().rstrip() self.assertTrue(tempcontent == header())
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) # create a new dotfile dotfile = Dotfile('', dst, src) linktype = LinkTypes(o.link) if o.debug: LOG.dbg('new dotfile: {}'.format(dotfile)) # prepare hierarchy for dotfile srcf = os.path.join(o.dotpath, src) if not os.path.exists(srcf): 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))) if linktype == LinkTypes.PARENTS: LOG.dry('would symlink {} to {}'.format(srcf, dst)) else: r, _ = run(cmd, raw=False, debug=o.debug, checkerr=True) if not r: LOG.err('importing \"{}\" failed!'.format(path)) ret = False continue if linktype == LinkTypes.PARENTS: remove(dst) os.symlink(srcf, dst) retconf, dotfile = o.conf.new(dotfile, o.profile, link=linktype, debug=o.debug) 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 _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
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)
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 test_install(self): '''Test the install function''' # dotpath location tmp = get_tempfolder() self.assertTrue(os.path.exists(tmp)) self.addCleanup(clean, tmp) # where dotfiles will be installed dst = get_tempfolder() self.assertTrue(os.path.exists(dst)) self.addCleanup(clean, dst) # create the dotfile in dotdrop f1, c1 = create_random_file(tmp) dst1 = os.path.join(dst, get_string(6)) d1 = Dotfile(get_string(5), dst1, os.path.basename(f1)) # fake a print self.assertTrue(str(d1) != '') f2, c2 = create_random_file(tmp) dst2 = os.path.join(dst, get_string(6)) d2 = Dotfile(get_string(5), dst2, os.path.basename(f2)) with open(f2, 'w') as f: f.write(self.TEMPLATE) f3, _ = create_random_file(tmp, binary=True) dst3 = os.path.join(dst, get_string(6)) d3 = Dotfile(get_string(5), dst3, os.path.basename(f3)) # to test backup f4, c4 = create_random_file(tmp) dst4 = os.path.join(dst, get_string(6)) d4 = Dotfile(get_string(6), dst4, os.path.basename(f4)) with open(dst4, 'w') as f: f.write(get_string(16)) # to test link f5, c5 = create_random_file(tmp) dst5 = os.path.join(dst, get_string(6)) self.addCleanup(clean, dst5) d5 = Dotfile(get_string(6), dst5, os.path.basename(f5), link=True) # create the dotfile folders in dotdrop dir1 = create_dir(os.path.join(tmp, get_string(6))) self.assertTrue(os.path.exists(dir1)) self.addCleanup(clean, dir1) dst6 = os.path.join(dst, get_string(6)) # fill with files sub1, _ = create_random_file(dir1) self.assertTrue(os.path.exists(sub1)) sub2, _ = create_random_file(dir1) self.assertTrue(os.path.exists(sub2)) # make up the dotfile d6 = Dotfile(get_string(6), dst6, os.path.basename(dir1)) # to test symlink folders dir2 = create_dir(os.path.join(tmp, get_string(6))) self.assertTrue(os.path.exists(dir2)) self.addCleanup(clean, dir2) dst7 = os.path.join(dst, get_string(6)) # fill with files sub3, _ = create_random_file(dir2) self.assertTrue(os.path.exists(sub3)) sub4, _ = create_random_file(dir2) self.assertTrue(os.path.exists(sub4)) # make up the dotfile d7 = Dotfile(get_string(6), dst7, os.path.basename(dir2), link=True) # to test actions value = get_string(12) fact = '/tmp/action' act1 = Action('testaction', 'echo "%s" > %s' % (value, fact)) f8, c8 = create_random_file(tmp) dst8 = os.path.join(dst, get_string(6)) d8 = Dotfile(get_string(6), dst8, os.path.basename(f8), actions=[act1]) # generate the config and stuff profile = get_string(5) confpath = os.path.join(tmp, self.CONFIG_NAME) self.fake_config(confpath, [d1, d2, d3, d4, d5, d6, d7, d8], profile, tmp, [act1]) conf = Cfg(confpath) self.assertTrue(conf is not None) # install them conf, opts = load_config(confpath, profile) opts['safe'] = False opts['quiet'] = True install(opts, conf) # now compare the generated files self.assertTrue(os.path.exists(dst1)) self.assertTrue(os.path.exists(dst2)) self.assertTrue(os.path.exists(dst3)) self.assertTrue(os.path.exists(dst5)) self.assertTrue(os.path.exists(dst6)) self.assertTrue(os.path.exists(dst7)) self.assertTrue(os.path.exists(dst8)) # check if 'dst5' is a link whose target is 'f5' self.assertTrue(os.path.islink(dst5)) self.assertTrue(os.path.realpath(dst5) == os.path.realpath(f5)) # check if 'dst7' is a link whose target is 'dir2' self.assertTrue(os.path.islink(dst7)) self.assertTrue(os.path.realpath(dst7) == os.path.realpath(dir2)) # make sure backup is there b = dst4 + Installer.BACKUP_SUFFIX self.assertTrue(os.path.exists(b)) self.assertTrue(filecmp.cmp(f1, dst1, shallow=True)) f2content = open(dst2, 'r').read() self.assertTrue(f2content == self.RESULT) self.assertTrue(filecmp.cmp(f3, dst3, shallow=True)) # test action has been executed self.assertTrue(os.path.exists(fact)) self.assertTrue(str(act1) != '') actcontent = open(fact, 'r').read().rstrip() self.assertTrue(actcontent == value)