def get_conf(self): """Return the site/user configuration root node.""" if self.conf is None: # base system conf path paths = [self.SYST_CONF_PATH] # add $ROSE_SITE_CONF_PATH if defined if "ROSE_SITE_CONF_PATH" in os.environ: path_str = os.environ["ROSE_SITE_CONF_PATH"].strip() if path_str: paths.append(Path(path_str)) # add user conf path paths.append(self.USER_CONF_PATH) # use $ROSE_CONF_PATH (and ignore all others) if defined if "ROSE_CONF_PATH" in os.environ: paths_str = os.getenv("ROSE_CONF_PATH").strip() if paths_str: paths = [ Path(path) for path in paths_str.split(os.pathsep) ] else: paths = [] # load and cache config self.conf = ConfigNode() config_loader = ConfigLoader() for path in paths: conffile = path / self.ROSE_CONF if conffile.is_file() and os.access(conffile, os.R_OK): config_loader.load_with_opts(str(conffile), self.conf) return self.conf
def get_conf(self): """Return the site/user configuration root node.""" if self.conf is None: paths = [self.SITE_CONF_PATH, self.USER_CONF_PATH] if "ROSE_CONF_PATH" in os.environ: paths_str = os.getenv("ROSE_CONF_PATH").strip() if paths_str: paths = paths_str.split(os.pathsep) else: paths = [] self.conf = ConfigNode() config_loader = ConfigLoader() for path in paths: name = os.path.join(path, self.ROSE_CONF) if os.path.isfile(name) and os.access(name, os.R_OK): config_loader.load_with_opts(name, self.conf) return self.conf
class ConfigTreeLoader: """Load a Rose configuration with inheritance.""" def __init__(self, *args, **kwargs): self.node_loader = ConfigLoader(*args, **kwargs) def load( self, conf_dir, conf_name, conf_dir_paths=None, opt_keys=None, conf_node=None, no_ignore=False, defines=None, ): """Load a (runtime) configuration directory with inheritance. Return a ConfigTree object that represents the result. conf_dir -- The path to the configuration directory to load. conf_name -- The (base) name of the configuration file. E.g. "rose-suite.conf". conf_dir_paths -- A list of directories to locate relative paths to configurations. opt_keys -- Optional configuration keys. conf_node -- A metomi.rose.config.ConfigNode to extend, or None to use a fresh one. no_ignore -- If True, skip loading ignored config settings. defines -- A list of [SECTION]KEY=VALUE overrides. """ if not conf_dir_paths: conf_dir_paths = [] conf_dir = self._search(conf_dir, [os.getcwd()] + conf_dir_paths) nodes = {} # {conf_dir: node, ...} conf_file_name = os.path.join(conf_dir, conf_name) used_keys = [] nodes[conf_dir] = self.node_loader.load_with_opts( conf_file_name, more_keys=opt_keys, used_keys=used_keys, defines=defines, ) conf_tree = ConfigTree() conf_tree.conf_dirs = mro( conf_dir, self._get_base_names, conf_name, conf_dir_paths, opt_keys, used_keys, nodes, ) if opt_keys: bad_keys = [] for opt_key in opt_keys: if ( opt_key not in used_keys and not self.node_loader.can_miss_opt_conf_key(opt_key) ): bad_keys.append(opt_key) if bad_keys: raise BadOptionalConfigurationKeysError(bad_keys) if conf_node is None: conf_tree.node = ConfigNode() else: conf_tree.node = conf_node for t_conf_dir in conf_tree.conf_dirs: node = nodes[t_conf_dir] for keys, sub_node in node.walk(no_ignore=no_ignore): if keys == ["", "import"]: continue if conf_tree.node.get(keys) is None: conf_tree.node.set( keys, sub_node.value, sub_node.state, sub_node.comments ) for dir_path, dir_names, file_names in os.walk(t_conf_dir): names = [dir_ for dir_ in dir_names if dir_.startswith(".")] for name in names: dir_names.remove(name) for file_name in file_names: if file_name == conf_name or file_name.startswith("."): continue path = os.path.join(dir_path, file_name) rel_path = os.path.relpath(path, t_conf_dir) if rel_path not in conf_tree.files: conf_tree.files[rel_path] = t_conf_dir if rel_path not in conf_tree.file_locs: conf_tree.file_locs[rel_path] = [] conf_tree.file_locs[rel_path].append(t_conf_dir) return conf_tree __call__ = load def _get_base_names( self, my_conf_dir, conf_name, conf_dir_paths, opt_keys, used_keys, nodes, ): """Return a list of configuration directories to import.""" values = shlex.split(nodes[my_conf_dir].get_value(["import"], "")) i_conf_dirs = [] for value in values: i_conf_dir = self._search( value, [os.path.dirname(my_conf_dir)] + conf_dir_paths ) i_conf_file_name = os.path.join(i_conf_dir, conf_name) if nodes.get(i_conf_dir) is None: nodes[i_conf_dir] = self.node_loader.load_with_opts( i_conf_file_name, more_keys=opt_keys, used_keys=used_keys ) i_conf_dirs.append(i_conf_dir) return i_conf_dirs @classmethod def _search(cls, conf_dir, conf_dir_paths): """Search for named a configuration directory from a list of paths.""" if os.path.isabs(conf_dir): return os.path.abspath(conf_dir) for conf_dir_path in conf_dir_paths: dir_ = os.path.join(conf_dir_path, conf_dir) if os.path.isdir(dir_): return os.path.abspath(dir_) return os.path.abspath(os.path.join(conf_dir_paths[0], conf_dir))
def main(): """Implement the "rose config" command.""" opt_parser = RoseOptionParser() opt_parser.add_my_options("default", "env_var_process_mode", "files", "keys", "meta", "meta_key", "no_ignore", "no_opts", "print_conf_mode") opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) metomi.rose.macro.add_meta_paths() if opts.meta_key: opts.meta = True if opts.files and opts.meta_key: report(Exception("Cannot specify both a file and meta key.")) sys.exit(1) config_loader = ConfigLoader() sources = [] if opts.files: root_node = ConfigNode() for fname in opts.files: if fname == "-": sources.append(sys.stdin) else: if opts.meta: try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) rel_path = os.sep.join(fname.split(os.sep)[:-1]) fpath = get_meta_path(root_node, rel_path) if fpath is None: report(MetadataNotFoundEvent(fname)) else: sources.append(fpath) else: sources.append(fname) elif opts.meta: root_node = ConfigNode() if opts.meta_key: root_node.set(["meta"], opts.meta_key) else: fname = os.path.join(os.getcwd(), metomi.rose.SUB_CONFIG_NAME) try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) fpath = get_meta_path(root_node, meta_key=opts.meta_key) root_node.unset(["meta"]) if fpath is None: report(Exception("Metadata not found")) sys.exit(1) else: sources.append(fpath) else: root_node = ResourceLocator.default().get_conf() for source in sources: try: if opts.meta or opts.no_opts: config_loader.load(source, root_node) else: config_loader.load_with_opts(source, root_node) except (ConfigSyntaxError, IOError) as exc: report(exc) sys.exit(1) if source is sys.stdin: source.close() if opts.quietness: sys.exit(root_node.get(args, opts.no_ignore) is None) if opts.keys_mode: try: keys = list(root_node.get(args, opts.no_ignore).value) except AttributeError: sys.exit(1) keys.sort() for key in keys: print(key) sys.exit() conf_dump = ConfigDumper() if len(args) == 0: conf_dump(root_node, concat_mode=opts.print_conf_mode) sys.exit() node = root_node.get(args, opts.no_ignore) if node is not None and isinstance(node.value, dict): if opts.print_conf_mode: conf_dump(ConfigNode().set(args, node.value), concat_mode=True) sys.exit() keys = list(node.value) keys.sort() for key in keys: node_of_key = node.get([key], opts.no_ignore) if node_of_key: value = node_of_key.value state = node_of_key.state string = "%s%s=%s" % (state, key, value) lines = string.splitlines() print(lines[0]) i_equal = len(state + key) + 1 for line in lines[1:]: print(" " * i_equal + line) sys.exit() if node is None: if opts.default is None: sys.exit(1) value = opts.default elif opts.env_var_process_mode: value = env_var_process(node.value) else: value = node.value if opts.print_conf_mode: conf_dump(ConfigNode().set(args, value), concat_mode=True) else: print(value) sys.exit()
def main(): """Implement the "rose config" command.""" opt_parser = RoseOptionParser(description=''' Parse and print rose configuration files. With no option and no argument, print the rose site + user configuration. EXAMPLES # Print the value of OPTION in SECTION. rose config SECTION OPTION # Print the value of OPTION in SECTION in FILE. rose config --file=FILE SECTION OPTION # Print the value of OPTION in SECTION if exists, or VALUE otherwise. rose config --default=VALUE SECTION OPTION # Print the OPTION=VALUE pairs in SECTION. rose config SECTION # Print the value of a top level OPTION. rose config OPTION # Print the OPTION keys in SECTION. rose config --keys SECTION # Print the SECTION keys. rose config --keys # Exit with 0 if OPTION exists in SECTION, or 1 otherwise. rose config -q SECTION OPTION # Exit with 0 if SECTION exists, or 1 otherwise. rose config -q SECTION # Combine the configurations in FILE1 and FILE2, and dump the result. rose config --file=FILE1 --file=FILE2 # Print the value of OPTION in SECTION of the metadata associated with # the specified config FILE rose config --file=FILE --meta SECTION OPTION # Print the value of a specified metadata KEY rose config --meta-key=KEY ''', epilog=''' ENVIRONMENT VARIABLES optional ROSE_META_PATH Prepend `$ROSE_META_PATH` to the metadata search path. ''') opt_parser.add_my_options( "default", "env_var_process_mode", "files", "keys", "meta", "meta_key", "no_ignore", "no_opts", "print_conf_mode", ) # the quietness argument is non-standard for this command opt_parser.modify_option( 'quietness', help=("Exit with 0 if the specified `SECTION` and/or `OPTION` exist in" " the configuration, or 1 otherwise."), ) opts, args = opt_parser.parse_args() report = Reporter(opts.verbosity - opts.quietness) metomi.rose.macro.add_meta_paths() if opts.meta_key: opts.meta = True if opts.files and opts.meta_key: report(Exception("Cannot specify both a file and meta key.")) sys.exit(1) config_loader = ConfigLoader() sources = [] if opts.files: root_node = ConfigNode() for fname in opts.files: if fname == "-": sources.append(sys.stdin) else: if opts.meta: try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) rel_path = os.sep.join(fname.split(os.sep)[:-1]) fpath = get_meta_path(root_node, rel_path) if fpath is None: report(MetadataNotFoundEvent(fname)) else: sources.append(fpath) else: sources.append(fname) elif opts.meta: root_node = ConfigNode() if opts.meta_key: root_node.set(["meta"], opts.meta_key) else: fname = os.path.join(os.getcwd(), metomi.rose.SUB_CONFIG_NAME) try: root_node = config_loader.load(fname) except ConfigSyntaxError as exc: report(exc) sys.exit(1) fpath = get_meta_path(root_node, meta_key=opts.meta_key) root_node.unset(["meta"]) if fpath is None: report(Exception("Metadata not found")) sys.exit(1) else: sources.append(fpath) else: root_node = ResourceLocator.default().get_conf() for source in sources: try: if opts.meta or opts.no_opts: config_loader.load(source, root_node) else: config_loader.load_with_opts(source, root_node) except (ConfigSyntaxError, IOError) as exc: report(exc) sys.exit(1) if source is sys.stdin: source.close() if opts.quietness: sys.exit(root_node.get(args, opts.no_ignore) is None) if opts.keys_mode: try: keys = list(root_node.get(args, opts.no_ignore).value) except AttributeError: sys.exit(1) keys.sort() for key in keys: print(key) sys.exit() conf_dump = ConfigDumper() if len(args) == 0: conf_dump(root_node, concat_mode=opts.print_conf_mode) sys.exit() node = root_node.get(args, opts.no_ignore) if node is not None and isinstance(node.value, dict): if opts.print_conf_mode: conf_dump(ConfigNode().set(args, node.value), concat_mode=True) sys.exit() keys = list(node.value) keys.sort() for key in keys: node_of_key = node.get([key], opts.no_ignore) if node_of_key: value = node_of_key.value state = node_of_key.state string = "%s%s=%s" % (state, key, value) lines = string.splitlines() print(lines[0]) i_equal = len(state + key) + 1 for line in lines[1:]: print(" " * i_equal + line) sys.exit() if node is None: if opts.default is None: sys.exit(1) value = opts.default elif opts.env_var_process_mode: value = env_var_process(node.value) else: value = node.value if opts.print_conf_mode: conf_dump(ConfigNode().set(args, value), concat_mode=True) else: print(value) sys.exit()