Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
 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
Ejemplo n.º 3
0
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))
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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()