def transform(self, config, meta_config=None): """Return a config and a list of changes, if any.""" checker = CompulsoryChecker() problem_list = checker.validate(config, meta_config) missing_sect_opts = [] for report in problem_list: if report.info != checker.WARNING_COMPULSORY_USER_IGNORED: missing_sect_opts.append((report.section, report.option)) missing_sect_opts.sort() missing_sect_opts.sort(key=lambda x: str(x[1])) for sect, opt in missing_sect_opts: if opt is None: config.set([sect]) self.add_report(sect, opt, None, self.ADD_COMPULSORY_SECT) problem_list = checker.validate(config, meta_config) missing_sect_opts = [] for report in problem_list: if report.info != checker.WARNING_COMPULSORY_USER_IGNORED: missing_sect_opts.append((report.section, report.option)) missing_sect_opts.sort() missing_sect_opts.sort(key=lambda x: x[1]) for sect, opt in missing_sect_opts: if opt is None: continue var_id = self._get_id_from_section_option(sect, opt) metadata = metomi.rose.macro.get_metadata_for_config_id( var_id, meta_config) value = metomi.rose.variable.get_value_from_metadata(metadata) config.set([sect, opt], value) self.add_report(sect, opt, value, self.ADD_COMPULSORY_OPT) return config, self.reports
def store_password(self): """Store the authentication information for self.prefix.""" if self.username and self.username_orig != self.username: user_rose_conf_path = os.path.join(ResourceLocator.USER_CONF_PATH, ResourceLocator.ROSE_CONF) if os.access(user_rose_conf_path, os.F_OK | os.R_OK | os.W_OK): config = metomi.rose.config.load(user_rose_conf_path) else: config = metomi.rose.config.ConfigNode() config.set(["rosie-id", "prefix-username." + self.prefix], self.username) metomi.rose.config.dump(config, user_rose_conf_path) if (self.password_store is not None and self.password and self.password_orig != self.password): self.password_store.store_password(self.scheme, self.host, self.username, self.password)
def write_config(self, filename, tasks): """Write an analysis config file based on a list of tasks provided""" config = metomi.rose.config.ConfigNode() for task in tasks: sectionname = task.name if task.resultfileconfig: config.set([sectionname, "resultfile"], task.resultfileconfig) for i in range(1, task.numkgofiles + 1): origvar = "kgo" + str(i) + "fileconfig" valvar = "kgo" + str(i) + "file" if hasattr(task, origvar): config.set([sectionname, valvar], getattr(task, origvar)) if task.extract: config.set([sectionname, "extract"], task.extract) if task.subextract: config.set( [sectionname, "extract"], task.extract + ":" + task.subextract, ) if task.comparison: config.set([sectionname, "comparison"], task.comparison) if task.tolerance: config.set([sectionname, "tolerance"], task.tolerance) if task.warnonfail: config.set([sectionname, "warnonfail"], "true") metomi.rose.config.dump(config, filename)
def add_setting(self, config, keys, value=None, forced=False, state=None, comments=None, info=None): """Add a setting to the configuration. Args: config (metomi.rose.config.ConfigNode): The application configuration. keys (list): A list defining a hierarchy of node.value 'keys'. A section will be a list of one keys, an option will have two. value (string - optional): String denoting the new setting value. Required for options but not for settings. forced (bool - optional) If True override value if the setting already exists. state (str - optional): The state of the new setting - should be one of the ``rose.config.ConfigNode`` states e.g. ``rose.config.ConfigNode.STATE_USER_IGNORED``. Defaults to ``rose.config.ConfigNode.STATE_NORMAL``. comments (list - optional): List of comment lines (strings) for the new setting or ``None``. info (string - optional): A short string containing no new lines, describing the addition of the setting. Returns: None """ section, option = self._get_section_option_from_keys(keys) id_ = self._get_id_from_section_option(section, option) if option is not None and value is None: value = "" if info is None: if option is None: info = self.INFO_ADDED_SECT else: info = self.INFO_ADDED_VAR.format(repr(value)) # Search for existing conflicting settings. conflict_id = None found_setting = False if config.get([section, option]) is None: for key in config.get_value(): existing_section = key if not existing_section.startswith(section): continue existing_base_section = ( metomi.rose.macro.REC_ID_STRIP.sub("", existing_section)) if option is None: # For section 'foo', look for 'foo', 'foo{bar}', 'foo(1)'. found_setting = (existing_section == section or existing_base_section == section) else: # For 'foo=bar', don't allow sections 'foo(1)', 'foo{bar}'. found_setting = (existing_section != section and existing_base_section == section) if found_setting: conflict_id = existing_section break if option is not None: for keys, _ in config.walk([existing_section]): existing_option = keys[1] existing_base_option = ( metomi.rose.macro.REC_ID_STRIP_DUPL.sub( "", existing_option) ) # For option 'foo', look for 'foo', 'foo(1)'. if (existing_section == section and (existing_option == option or existing_base_option == option)): found_setting = True conflict_id = self._get_id_from_section_option( existing_section, existing_option) break if found_setting: break else: found_setting = True conflict_id = None # If already added, quit, unless "forced". if found_setting: if forced and (conflict_id is None or id_ == conflict_id): # If forced, override settings for an identical id. return self.change_setting_value( config, keys, value, state, comments, info) if conflict_id: self.add_report( section, option, value, self.WARNING_ADD_CLASH.format(id_, conflict_id), is_warning=True ) return False # Add parent section if missing. if option is not None and config.get([section]) is None: self.add_setting(config, [section]) if value is not None and not isinstance(value, str): text = "New value {0} for {1} is not a string" raise ValueError(text.format(repr(value), id_)) # Set (add) the section/option. config.set([section, option], value=value, state=state, comments=comments) self.add_report(section, option, value, info)
def namelist_dump(args=None, output_file=None, case_mode=None): """Convert Fortran namelist file to a Rose configuration.""" # Input and output options if not args: args = [STD_FILE_ARG] if output_file is None or output_file == STD_FILE_ARG: output_file = sys.stdout else: output_file = open(output_file, "w") # Config: file: sections config = metomi.rose.config.ConfigNode() files = [] for arg in args: if arg == STD_FILE_ARG: files.append(sys.stdin) config.set(["file:STDIN"], {}) else: files.append(open(arg, "r")) config.set(["file:" + arg], {}) # Parse files into a list of NamelistGroup objects groups = metomi.rose.formats.namelist.parse(files) # Count group in files and group groups_in_file = {} groups_by_name = {} index_of_group = {} for group in groups: name = group.name.lower() if name not in groups_by_name: groups_by_name[name] = [] groups_by_name[name].append(group) index_of_group[group] = len(groups_by_name[name]) if group.file_ not in groups_in_file: groups_in_file[group.file_] = [] groups_in_file[group.file_].append(group) # Add contents to relevant file: sections for file_, groups in groups_in_file.items(): section = "file:" + file_ if file_ == sys.stdin.name: section = "file:STDIN" group_sections = [] for group in groups: group_section = "namelist:" + tr_case(group.name, case_mode) if len(groups_by_name[group.name.lower()]) > 1: group_section += "(" + str(index_of_group[group]) + ")" group_sections.append(group_section) config.set([section, "source"], " ".join(group_sections)) # Add namelist: sections for name, groups in groups_by_name.items(): for group in groups: section = "namelist:" + tr_case(group.name, case_mode) if len(groups) > 1: section += "(" + str(index_of_group[group]) + ")" config.set([section], {}) for obj in group.objects: lhs = tr_case(obj.lhs, case_mode) config.set([section, lhs], obj.get_rhs_as_string()) # Config: write results metomi.rose.config.dump(config, output_file, sort_sections=_sort_config_key, sort_option_items=_sort_config_key, env_escape_ok=True) output_file.close()