From 4d8df242b6599757b93eb6056e43fa786a830a57 Mon Sep 17 00:00:00 2001 From: Rick Nitsche Date: Fri, 20 Nov 2020 18:21:51 -0800 Subject: [PATCH] feat(config): support endpoints grouped by dirs --- coco/config.py | 85 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/coco/config.py b/coco/config.py index 2958f2b5..7a73d2c3 100644 --- a/coco/config.py +++ b/coco/config.py @@ -182,9 +182,14 @@ def load_config(path=None): if not any_exist: raise RuntimeError("No configuration files available.") + # Validate config _validate_and_resolve(config) - _load_endpoint_config(config) + # Load the endpoints + endpoint_tree = load_endpoint_tree(Path(config["endpoint_dir"])) + + # We only record the endpoint list per se, not the whole top-level group + config["endpoints"] = endpoint_tree["endpoints"] return config @@ -270,31 +275,69 @@ def _validate_and_resolve(config): raise RuntimeError("Config missing required values.") -def _load_endpoint_config(config): - """Load the endpoint config. +def load_endpoint(_file, group): + """Read an endpoint from disk. - The config is injected into the passed in config object. + Returns the parsed endpoint config entry. """ - config["endpoints"] = [] + # A file called "__meta.conf" (two underscores) can be used to set metadata + # about the containing endpoint group. + meta = _file.name == "__meta.conf" + + # Only accept files ending in .conf as endpoint configs. + # Endpoint config files starting with an underscore (_) are disabled (except + # a __meta.conf file). + if meta or (_file.suffix == ".conf" and not _file.name.startswith("_")): + logger.debug(f"Loading endpoint config {_file}.") - endpoint_dir = Path(config["endpoint_dir"]) + with _file.open("r") as fh: + try: + conf = yaml.safe_load(fh) + except yaml.YAMLError as exc: + logger.error(f"Failure reading YAML file {_file}: {exc}") - for endpoint_file in endpoint_dir.iterdir(): - # Only accept files ending in .conf as endpoint configs. - # Endpoint config files starting with an underscore (_) are disabled. - if endpoint_file.suffix == ".conf" and not endpoint_file.name.startswith("_"): - logger.debug(f"Loading endpoint config {endpoint_file}.") + # Extra endpoint metadata + conf["meta"] = meta + conf["tree"] = False - # Remove .conf from the config file name to get the name of the endpoint - name = endpoint_file.stem + # Remove .conf from the config file name to get the name of the endpoint + conf["name"] = _file.stem - with endpoint_file.open("r") as fh: - try: - conf = yaml.safe_load(fh) - except yaml.YAMLError as exc: - logger.error(f"Failure reading YAML file {endpoint_file}: {exc}") + # TODO: validate the endpoint config in here + return conf - conf["name"] = name - # TODO: validate the endpoint config in here - config["endpoints"].append(conf) +def load_endpoint_tree(path): + """Iterate over a directory `path` in the endpoint tree. + + Returns an endpoint tree config for the directory, + containing the endpoints and subtrees found within. + """ + tree = { + "name": path.name, + "tree": True, + "description": "Unremarkable endpoint tree", + "endpoints": [], + } + for dir_entry in path.iterdir(): + if dir_entry.is_dir(): + # Parse the subtree + subtree = load_endpoint_tree(dir_entry) + + # The subtree is only added if it's not empty + if subtree["endpoints"]: + tree["endpoints"].append(subtree) + else: + endpoint = load_endpoint(dir_entry) + + if endpoint["meta"]: + # If this was a _meta.conf file, merge (select) data into the + # tree config + for key in ["description"]: + if key in endpoint: + tree[key] = endpoint[key] + else: + # otherwise, append to this tree's endpoint list. + tree["endpoints"].append(load_endpoint(dir_entry)) + + return tree