def _load_yaml(self, path): """load a yaml file to a dict""" content = {} if not os.path.exists(path): raise YamlException('config path not found: {}'.format(path)) try: content = self._yaml_load(path) except Exception as e: self.log.err(e) raise YamlException('invalid config: {}'.format(path)) return content
def _check_minversion(self, minversion): if not minversion: return try: cur = tuple([int(x) for x in VERSION.split('.')]) cfg = tuple([int(x) for x in minversion.split('.')]) except Exception: err = 'bad version: \"{}\" VS \"{}\"'.format(VERSION, minversion) raise YamlException(err) if cur < cfg: err = 'current dotdrop version is too old for that config file.' err += ' Please update.' raise YamlException(err)
def _import_sub(self, path, key, mandatory=False, patch_func=None, fatal_not_found=True): """ import the block "key" from "path" patch_func is applied to each element if defined """ if self.debug: self.log.dbg('import \"{}\" from \"{}\"'.format(key, path)) self.log.dbg('ignore non existing: \"{}\"'.format(fatal_not_found)) extdict = self._load_yaml(path, fatal_not_found=fatal_not_found) if extdict is None and not fatal_not_found: return {} new = self._get_entry(extdict, key, mandatory=mandatory) if patch_func: if self.debug: self.log.dbg('calling patch: {}'.format(patch_func)) new = patch_func(new) if not new and mandatory: err = 'no \"{}\" imported from \"{}\"'.format(key, path) self.log.warn(err) raise YamlException(err) if self.debug: self.log.dbg('imported \"{}\": {}'.format(key, new)) return new
def save(self): """save this instance and return True if saved""" if not self._dirty: return False content = self._prepare_to_save(self._yaml_dict) if self._dirty_deprecated: # add minversion settings = content[self.key_settings] settings[self.key_settings_minversion] = VERSION # save to file if self._debug: self._dbg('saving to {}'.format(self._path)) try: with open(self._path, 'w') as f: self._yaml_dump(content, f) except Exception as e: self._log.err(e) raise YamlException('error saving config: {}'.format(self._path)) if self._dirty_deprecated: warn = 'your config contained deprecated entries' warn += ' and was updated' self._log.warn(warn) self._dirty = False self.cfg_updated = False return True
def __init__(self, args=None): """constructor @args: argument dictionary (if None use sys) """ self.args = {} if not args: self.args = docopt(USAGE, version=VERSION) if args: self.args = args.copy() self.log = Logger() self.debug = self.args['--verbose'] or ENV_DEBUG in os.environ self.dry = self.args['--dry'] if ENV_NODEBUG in os.environ: # force disabling debugs self.debug = False self.profile = self.args['--profile'] self.confpath = self._get_config_path() if not self.confpath: raise YamlException('no config file found') if self.debug: self.log.dbg('version: {}'.format(VERSION)) self.log.dbg('command: {}'.format(' '.join(sys.argv))) self.log.dbg('config file: {}'.format(self.confpath)) self._read_config() self._apply_args() self._fill_attr() if ENV_NOBANNER not in os.environ \ and self.banner \ and not self.args['--no-banner']: self._header() self._debug_attr() # start monitoring for bad attribute self._set_attr_err = True
def save(self): """save this instance and return True if saved""" if not self.dirty: return False content = self._clear_none(self.dump()) # make sure we have the base entries if self.key_settings not in content: content[self.key_settings] = None if self.key_dotfiles not in content: content[self.key_dotfiles] = None if self.key_profiles not in content: content[self.key_profiles] = None # save to file if self.debug: self.log.dbg('saving to {}'.format(self.path)) try: self._yaml_dump(content, self.path) except Exception as e: self.log.err(e) raise YamlException('error saving config: {}'.format(self.path)) self.dirty = False return True
def _load_yaml(self, path, fatal_not_found=True): """load a yaml file to a dict""" content = {} if not os.path.exists(path): err = 'config path not found: {}'.format(path) if fatal_not_found: raise YamlException(err) else: self.log.warn(err) return None try: content = self._yaml_load(path) except Exception as e: self.log.err(e) raise YamlException('invalid config: {}'.format(path)) return content
def _load_yaml(self, path): """load a yaml file to a dict""" content = {} try: content = self._yaml_load(path) except Exception as e: self.log.err(e) raise YamlException('invalid config: {}'.format(path)) return content
def _get_entry(self, dic, key, mandatory=True): """return entry from yaml dictionary""" if key not in dic: if mandatory: raise YamlException('invalid config: no {} found'.format(key)) dic[key] = {} return dic[key] if mandatory and not dic[key]: # ensure is not none dic[key] = {} return dic[key]
def _rec_resolve_profile_include(self, profile): """ recursively resolve include of other profiles's: * dotfiles * actions """ this_profile = self.profiles[profile] # include dotfiles = this_profile.get(self.key_profile_dotfiles, []) actions = this_profile.get(self.key_profile_actions, []) includes = this_profile.get(self.key_profile_include, None) if not includes: # nothing to include return dotfiles, actions if self.debug: self.log.dbg('{} includes: {}'.format(profile, ','.join(includes))) self.log.dbg('{} dotfiles before include: {}'.format( profile, dotfiles)) self.log.dbg('{} actions before include: {}'.format( profile, actions)) seen = [] for i in uniq_list(includes): # ensure no include loop occurs if i in seen: raise YamlException('\"include loop\"') seen.append(i) # included profile even exists if i not in self.profiles.keys(): self.log.warn('include unknown profile: {}'.format(i)) continue # recursive resolve o_dfs, o_actions = self._rec_resolve_profile_include(i) # merge dotfile keys dotfiles.extend(o_dfs) this_profile[self.key_profile_dotfiles] = uniq_list(dotfiles) # merge actions keys actions.extend(o_actions) this_profile[self.key_profile_actions] = uniq_list(actions) dotfiles = this_profile.get(self.key_profile_dotfiles, []) actions = this_profile.get(self.key_profile_actions, []) if self.debug: self.log.dbg('{} dotfiles after include: {}'.format( profile, dotfiles)) self.log.dbg('{} actions after include: {}'.format( profile, actions)) # since dotfiles and actions are resolved here # and variables have been already done at the beginning # of the parsing, we can clear these include self.profiles[profile][self.key_profile_include] = None return dotfiles, actions
def __init__(self, path, profile=None, debug=False): """ config parser @path: config file path @profile: the selected profile @debug: debug flag """ self.path = os.path.abspath(path) self.profile = profile self.debug = debug self.log = Logger() # config needs to be written self.dirty = False # indicates the config has been updated self.dirty_deprecated = False if not os.path.exists(path): err = 'invalid config path: \"{}\"'.format(path) if self.debug: self.log.dbg(err) raise YamlException(err) self.yaml_dict = self._load_yaml(self.path) # live patch deprecated entries self._fix_deprecated(self.yaml_dict) # parse to self variables self._parse_main_yaml(self.yaml_dict) if self.debug: self.log.dbg('before normalization: {}'.format(self.yaml_dict)) # resolve variables self.variables, self.prokeys = self._merge_variables() # apply variables self._apply_variables() # process imported variables (import_variables) self._import_variables() # process imported actions (import_actions) self._import_actions() # process imported profile dotfiles (import) self._import_profiles_dotfiles() # process imported configs (import_configs) self._import_configs() # process profile include self._resolve_profile_includes() # process profile ALL self._resolve_profile_all() # patch dotfiles paths self._resolve_dotfile_paths() if self.debug: self.log.dbg('after normalization: {}'.format(self.yaml_dict))
def _shell_exec_dvars(self, keys, variables): """shell execute dynvariables""" for k in list(keys): ret, out = shell(variables[k], debug=self.debug) if not ret: err = 'var \"{}: {}\" failed: {}'.format(k, variables[k], out) self.log.err(err) raise YamlException(err) if self.debug: self.log.dbg('\"{}\": {} -> {}'.format(k, variables[k], out)) variables[k] = out
def __init__(self, args=None): """constructor @args: argument dictionary (if None use sys) """ # attributes gotten from self.conf.get_settings() self.banner = None self.showdiff = None self.default_actions = [] self.instignore = None self.force_chmod = None self.cmpignore = None self.impignore = None self.upignore = None self.link_on_import = None self.chmod_on_import = None self.check_version = None self.clear_workdir = None self.key_prefix = None self.key_separator = None # args parsing self.args = {} if not args: self.args = docopt(USAGE, version=VERSION) if args: self.args = args.copy() self.debug = self.args['--verbose'] or ENV_DEBUG in os.environ self.log = Logger(debug=self.debug) self.dry = self.args['--dry'] if ENV_NODEBUG in os.environ: # force disabling debugs self.debug = False self.profile = self.args['--profile'] self.confpath = self._get_config_path() if not self.confpath: raise YamlException('no config file found') self.log.dbg('#################################################') self.log.dbg('#################### DOTDROP ####################') self.log.dbg('#################################################') self.log.dbg('version: {}'.format(VERSION)) self.log.dbg('command: {}'.format(' '.join(sys.argv))) self.log.dbg('config file: {}'.format(self.confpath)) self._read_config() self._apply_args() self._fill_attr() if ENV_NOBANNER not in os.environ \ and self.banner \ and not self.args['--no-banner']: self._header() self._debug_attr() # start monitoring for bad attribute self._set_attr_err = True
def _parse_blk_dotfiles(self, dic): """parse the "dotfiles" block""" dotfiles = self._get_entry(dic, self.key_dotfiles).copy() keys = dotfiles.keys() if len(keys) != len(list(set(keys))): dups = [x for x in keys if x not in list(set(keys))] err = 'duplicate dotfile keys found: {}'.format(dups) raise YamlException(err) dotfiles = self._norm_dotfiles(dotfiles) if self._debug: self._debug_dict('dotfiles block', dotfiles) return dotfiles
def _shell_exec_dvars(self, dic, keys=[]): """shell execute dynvariables in-place""" if not keys: keys = dic.keys() for k in keys: v = dic[k] ret, out = shell(v, debug=self._debug) if not ret: err = 'var \"{}: {}\" failed: {}'.format(k, v, out) self._log.err(err) raise YamlException(err) if self._debug: self._dbg('{}: `{}` -> {}'.format(k, v, out)) dic[k] = out
def _glob_paths(self, paths): """glob a list of paths""" if not isinstance(paths, list): paths = [paths] res = [] for p in paths: if not self._is_glob(p): res.append(p) continue p = os.path.expanduser(p) new = glob.glob(p) if not new: raise YamlException('bad path: {}'.format(p)) res.extend(glob.glob(p)) return res
def _load_yaml(self, path): """load a yaml file to a dict""" content = {} if self._debug: self._dbg('----------start:{}----------'.format(path)) cfg = '\n' with open(path, 'r') as f: for line in f: cfg += line self._dbg(cfg.rstrip()) self._dbg('----------end:{}----------'.format(path)) try: content = self._yaml_load(path) except Exception as e: self._log.err(e) raise YamlException('invalid config: {}'.format(path)) return content
def _import_sub(self, path, key, mandatory=False, patch_func=None): """ import the block "key" from "path" patch_func is applied to each element if defined """ if self.debug: self.log.dbg('import \"{}\" from \"{}\"'.format(key, path)) extdict = self._load_yaml(path) new = self._get_entry(extdict, key, mandatory=mandatory) if patch_func: new = patch_func(new) if not new and mandatory: err = 'no \"{}\" imported from \"{}\"'.format(key, path) self.log.warn(err) raise YamlException(err) if self.debug: self.log.dbg('new \"{}\": {}'.format(key, new)) return new
def _get_included_variables(self, profile, seen): """return included variables""" variables = {} if not profile or profile not in self.profiles.keys(): return variables # profile entry pentry = self.profiles.get(profile) # inherite profile variables for inherited_profile in pentry.get(self.key_profile_include, []): if inherited_profile == profile or inherited_profile in seen: raise YamlException('\"include\" loop') seen.append(inherited_profile) new = self._get_included_variables(inherited_profile, seen) if self.debug: msg = 'included vars from {}: {}' self.log.dbg(msg.format(inherited_profile, new)) variables.update(new) cur = pentry.get(self.key_profile_variables, {}) return self._merge_dict(cur, variables)
def __get_profile_included_item(self, profile, keyitem, seen): """recursively get included <keyitem> from profile""" items = {} if not profile or profile not in self.profiles.keys(): return items # considered profile entry pentry = self.profiles.get(profile) # recursively get <keyitem> from inherited profile for inherited_profile in pentry.get(self.key_profile_include, []): if inherited_profile == profile or inherited_profile in seen: raise YamlException('\"include\" loop') seen.append(inherited_profile) new = self.__get_profile_included_item(inherited_profile, keyitem, seen) if self._debug: msg = 'included {} from {}: {}' self._dbg(msg.format(keyitem, inherited_profile, new)) items.update(new) cur = pentry.get(keyitem, {}) return self._merge_dict(cur, items)
def save(self): """save this instance and return True if saved""" if not self.dirty: return False content = self._clear_none(self.dump()) # make sure we have the base entries if self.key_settings not in content: content[self.key_settings] = None if self.key_dotfiles not in content: content[self.key_dotfiles] = None if self.key_profiles not in content: content[self.key_profiles] = None if self.dirty_deprecated: # add minversion settings = content[self.key_settings] settings[self.key_settings_minversion] = VERSION # save to file if self.debug: self.log.dbg('saving to {}'.format(self.path)) try: self._yaml_dump(content, self.path) except Exception as e: self.log.err(e) raise YamlException('error saving config: {}'.format(self.path)) if self.dirty_deprecated: warn = 'your config contained deprecated entries' warn += ' and was updated' self.log.warn(warn) self.dirty = False self.cfg_updated = False return True
def _import_config(self, path): """import config from path""" path, fatal_not_found = self._norm_extended_import_path(path) if self.debug: self.log.dbg('import config from {}'.format(path)) if not os.path.exists(path): err = 'config path not found: {}'.format(path) if fatal_not_found: raise YamlException(err) else: self.log.warn(err) return sub = CfgYaml(path, profile=self.profile, debug=self.debug) # settings are ignored from external file # except for filter_file and func_file self.settings[Settings.key_func_file] += [ self._norm_path(func_file) for func_file in sub.settings[Settings.key_func_file] ] self.settings[Settings.key_filter_file] += [ self._norm_path(func_file) for func_file in sub.settings[Settings.key_filter_file] ] # merge top entries self.dotfiles = self._merge_dict(self.dotfiles, sub.dotfiles) self.profiles = self._merge_dict(self.profiles, sub.profiles) self.actions = self._merge_dict(self.actions, sub.actions) self.trans_r = self._merge_dict(self.trans_r, sub.trans_r) self.trans_w = self._merge_dict(self.trans_w, sub.trans_w) self._clear_profile_vars(sub.variables) if self.debug: self.log.dbg('add import_configs var: {}'.format(sub.variables)) self.variables = self._merge_dict(sub.variables, self.variables)
def _rec_resolve_profile_include(self, profile): """ recursively resolve include of other profiles's: * dotfiles * actions * variables * dynvariables variables/dynvariables are directly merged with the global variables (self.variables) if these are included in the selected profile returns dotfiles, actions, variables, dynvariables """ this_profile = self.profiles[profile] # considered profile content dotfiles = this_profile.get(self.key_profile_dotfiles, []) or [] actions = this_profile.get(self.key_profile_actions, []) or [] includes = this_profile.get(self.key_profile_include, []) or [] pvars = this_profile.get(self.key_profile_variables, {}) or {} pdvars = this_profile.get(self.key_profile_dvariables, {}) or {} if not includes: # nothing to include return dotfiles, actions, pvars, pdvars if self.debug: self.log.dbg('{} includes {}'.format(profile, ','.join(includes))) self.log.dbg('{} dotfiles before include: {}'.format( profile, dotfiles)) self.log.dbg('{} actions before include: {}'.format( profile, actions)) self.log.dbg('{} variables before include: {}'.format( profile, pvars)) self.log.dbg('{} dynvariables before include: {}'.format( profile, pdvars)) seen = [] for i in uniq_list(includes): if self.debug: self.log.dbg('resolving includes "{}" <- "{}"'.format( profile, i)) # ensure no include loop occurs if i in seen: raise YamlException('\"include loop\"') seen.append(i) # included profile even exists if i not in self.profiles.keys(): self.log.warn('include unknown profile: {}'.format(i)) continue # recursive resolve if self.debug: self.log.dbg( 'recursively resolving includes for profile "{}"'.format( i)) o_dfs, o_actions, o_v, o_dv = self._rec_resolve_profile_include(i) # merge dotfile keys if self.debug: self.log.dbg('Merging dotfiles {} <- {}: {} <- {}'.format( profile, i, dotfiles, o_dfs)) dotfiles.extend(o_dfs) this_profile[self.key_profile_dotfiles] = uniq_list(dotfiles) # merge actions keys if self.debug: self.log.dbg('Merging actions {} <- {}: {} <- {}'.format( profile, i, actions, o_actions)) actions.extend(o_actions) this_profile[self.key_profile_actions] = uniq_list(actions) # merge variables if self.debug: self.log.dbg('Merging variables {} <- {}: {} <- {}'.format( profile, i, dict(pvars), dict(o_v))) pvars = self._merge_dict(o_v, pvars) this_profile[self.key_profile_variables] = pvars # merge dynvariables if self.debug: self.log.dbg( 'Merging dynamic variables {} <- {}: {} <- {}'.format( profile, i, dict(pdvars), dict(o_dv))) pdvars = self._merge_dict(o_dv, pdvars) this_profile[self.key_profile_dvariables] = pdvars dotfiles = this_profile.get(self.key_profile_dotfiles, []) actions = this_profile.get(self.key_profile_actions, []) pvars = this_profile.get(self.key_profile_variables, {}) or {} pdvars = this_profile.get(self.key_profile_dvariables, {}) or {} if self.debug: self.log.dbg('{} dotfiles after include: {}'.format( profile, dotfiles)) self.log.dbg('{} actions after include: {}'.format( profile, actions)) self.log.dbg('{} variables after include: {}'.format( profile, pvars)) self.log.dbg('{} dynvariables after include: {}'.format( profile, pdvars)) if profile == self.profile: # Only for the selected profile, we execute dynamic variables and # we merge variables/dynvariables into the global variables self._shell_exec_dvars(pdvars.keys(), pdvars) self.variables = self._merge_dict(pvars, self.variables) self.variables = self._merge_dict(pdvars, self.variables) # since included items are resolved here # we can clear these include self.profiles[profile][self.key_profile_include] = None return dotfiles, actions, pvars, pdvars
def _handle_non_existing_path(self, path, fatal_not_found=True): """Raise an exception or log a warning to handle non-existing paths.""" error = 'bad path {}'.format(path) if fatal_not_found: raise YamlException(error) self._log.warn(error)
def _rec_resolve_profile_include(self, profile): """ recursively resolve include of other profiles's: * dotfiles * actions returns dotfiles, actions """ this_profile = self.profiles[profile] # considered profile content dotfiles = this_profile.get(self.key_profile_dotfiles, []) or [] actions = this_profile.get(self.key_profile_actions, []) or [] includes = this_profile.get(self.key_profile_include, []) or [] if not includes: # nothing to include return dotfiles, actions if self._debug: self._dbg('{} includes {}'.format(profile, ','.join(includes))) self._dbg('{} dotfiles before include: {}'.format( profile, dotfiles)) self._dbg('{} actions before include: {}'.format(profile, actions)) seen = [] for i in uniq_list(includes): if self._debug: self._dbg('resolving includes "{}" <- "{}"'.format(profile, i)) # ensure no include loop occurs if i in seen: raise YamlException('\"include loop\"') seen.append(i) # included profile even exists if i not in self.profiles.keys(): self._log.warn('include unknown profile: {}'.format(i)) continue # recursive resolve if self._debug: self._dbg( 'recursively resolving includes for profile "{}"'.format( i)) o_dfs, o_actions = self._rec_resolve_profile_include(i) # merge dotfile keys if self._debug: self._dbg('Merging dotfiles {} <- {}: {} <- {}'.format( profile, i, dotfiles, o_dfs)) dotfiles.extend(o_dfs) this_profile[self.key_profile_dotfiles] = uniq_list(dotfiles) # merge actions keys if self._debug: self._dbg('Merging actions {} <- {}: {} <- {}'.format( profile, i, actions, o_actions)) actions.extend(o_actions) this_profile[self.key_profile_actions] = uniq_list(actions) dotfiles = this_profile.get(self.key_profile_dotfiles, []) actions = this_profile.get(self.key_profile_actions, []) if self._debug: self._dbg('{} dotfiles after include: {}'.format( profile, dotfiles)) self._dbg('{} actions after include: {}'.format(profile, actions)) # since included items are resolved here # we can clear these include self.profiles[profile][self.key_profile_include] = [] return dotfiles, actions
def __init__(self, path, profile=None, addprofiles=[], debug=False): """ config parser @path: config file path @profile: the selected profile @addprofiles: included profiles @debug: debug flag """ self._path = os.path.abspath(path) self._profile = profile self._debug = debug self._log = Logger() # config needs to be written self._dirty = False # indicates the config has been updated self._dirty_deprecated = False # profile variables self._profilevarskeys = [] # included profiles self._inc_profiles = addprofiles # init the dictionaries self.settings = {} self.dotfiles = {} self.profiles = {} self.actions = {} self.trans_r = {} self.trans_w = {} self.variables = {} if not os.path.exists(self._path): err = 'invalid config path: \"{}\"'.format(path) if self._debug: self._dbg(err) raise YamlException(err) self._yaml_dict = self._load_yaml(self._path) # live patch deprecated entries self._fix_deprecated(self._yaml_dict) ################################################## # parse the config and variables ################################################## # parse the "config" block self.settings = self._parse_blk_settings(self._yaml_dict) # base templater (when no vars/dvars exist) self.variables = self._enrich_vars(self.variables, self._profile) self._redefine_templater() # variables and dynvariables need to be first merged # before being templated in order to allow cyclic # references between them # parse the "variables" block var = self._parse_blk_variables(self._yaml_dict) self._add_variables(var, template=False) # parse the "dynvariables" block dvariables = self._parse_blk_dynvariables(self._yaml_dict) self._add_variables(dvariables, template=False) # now template variables and dynvariables from the same pool self._rec_resolve_variables(self.variables) # and execute dvariables # since this is done after recursively resolving variables # and dynvariables this means that variables referencing # dynvariables will result with the not executed value if dvariables.keys(): self._shell_exec_dvars(self.variables, keys=dvariables.keys()) # finally redefine the template self._redefine_templater() if self._debug: self._debug_dict('current variables defined', self.variables) # parse the "profiles" block self.profiles = self._parse_blk_profiles(self._yaml_dict) # include the profile's variables/dynvariables last # as it overwrites existing ones self._inc_profiles, pv, pvd = self._get_profile_included_vars() self._add_variables(pv, prio=True) self._add_variables(pvd, shell=True, prio=True) self._profilevarskeys.extend(pv.keys()) self._profilevarskeys.extend(pvd.keys()) # template variables self.variables = self._template_dict(self.variables) if self._debug: self._debug_dict('current variables defined', self.variables) ################################################## # template the "include" entries ################################################## self._template_include_entry() if self._debug: self._debug_dict('current variables defined', self.variables) ################################################## # parse the other blocks ################################################## # parse the "dotfiles" block self.dotfiles = self._parse_blk_dotfiles(self._yaml_dict) # parse the "actions" block self.actions = self._parse_blk_actions(self._yaml_dict) # parse the "trans_r" block self.trans_r = self._parse_blk_trans_r(self._yaml_dict) # parse the "trans_w" block self.trans_w = self._parse_blk_trans_w(self._yaml_dict) ################################################## # import elements ################################################## # process imported variables (import_variables) newvars = self._import_variables() self._clear_profile_vars(newvars) self._add_variables(newvars) # process imported actions (import_actions) self._import_actions() # process imported profile dotfiles (import) self._import_profiles_dotfiles() # process imported configs (import_configs) self._import_configs() # process profile include self._resolve_profile_includes() # add the current profile variables _, pv, pvd = self._get_profile_included_vars() self._add_variables(pv, prio=True) self._add_variables(pvd, shell=True, prio=True) self._profilevarskeys.extend(pv.keys()) self._profilevarskeys.extend(pvd.keys()) # resolve variables self._clear_profile_vars(newvars) self._add_variables(newvars) # process profile ALL self._resolve_profile_all() # patch dotfiles paths self._template_dotfiles_paths() if self._debug: self._dbg('########### {} ###########'.format('final config')) self._debug_entries()
def _parse_main_yaml(self, dic): """parse the different blocks""" self.ori_settings = self._get_entry(dic, self.key_settings) self.settings = Settings(None).serialize().get(self.key_settings) self.settings.update(self.ori_settings) # resolve minimum version if self.key_settings_minversion in self.settings: minversion = self.settings[self.key_settings_minversion] self._check_minversion(minversion) # resolve settings paths p = self._norm_path(self.settings[self.key_settings_dotpath]) self.settings[self.key_settings_dotpath] = p p = self._norm_path(self.settings[self.key_settings_workdir]) self.settings[self.key_settings_workdir] = p if self.debug: self.log.dbg('settings: {}'.format(self.settings)) # dotfiles self.ori_dotfiles = self._get_entry(dic, self.key_dotfiles) self.dotfiles = deepcopy(self.ori_dotfiles) keys = self.dotfiles.keys() if len(keys) != len(list(set(keys))): dups = [x for x in keys if x not in list(set(keys))] err = 'duplicate dotfile keys found: {}'.format(dups) raise YamlException(err) self.dotfiles = self._norm_dotfiles(self.dotfiles) if self.debug: self.log.dbg('dotfiles: {}'.format(self.dotfiles)) # profiles self.ori_profiles = self._get_entry(dic, self.key_profiles) self.profiles = deepcopy(self.ori_profiles) self.profiles = self._norm_profiles(self.profiles) if self.debug: self.log.dbg('profiles: {}'.format(self.profiles)) # actions self.ori_actions = self._get_entry(dic, self.key_actions, mandatory=False) self.actions = deepcopy(self.ori_actions) self.actions = self._norm_actions(self.actions) if self.debug: self.log.dbg('actions: {}'.format(self.actions)) # trans_r key = self.key_trans_r if self.old_key_trans_r in dic: self.log.warn('\"trans\" is deprecated, please use \"trans_read\"') dic[self.key_trans_r] = dic[self.old_key_trans_r] del dic[self.old_key_trans_r] self.ori_trans_r = self._get_entry(dic, key, mandatory=False) self.trans_r = deepcopy(self.ori_trans_r) if self.debug: self.log.dbg('trans_r: {}'.format(self.trans_r)) # trans_w self.ori_trans_w = self._get_entry(dic, self.key_trans_w, mandatory=False) self.trans_w = deepcopy(self.ori_trans_w) if self.debug: self.log.dbg('trans_w: {}'.format(self.trans_w)) # variables self.ori_variables = self._get_entry(dic, self.key_variables, mandatory=False) if self.debug: self.log.dbg('variables: {}'.format(self.ori_variables)) # dynvariables self.ori_dvariables = self._get_entry(dic, self.key_dvariables, mandatory=False) if self.debug: self.log.dbg('dynvariables: {}'.format(self.ori_dvariables))