From a0e0b09302c4521148a924981e5c06cba653432d Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Wed, 17 May 2023 11:28:30 -0700 Subject: [PATCH 01/14] WIP merged configs --- devcluster/__init__.py | 2 ++ devcluster/__main__.py | 32 +++++++++++++++--------- devcluster/config.py | 51 ++++++++++++++++++++++++++++++++++++++- devcluster/test_config.py | 48 ++++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 devcluster/test_config.py diff --git a/devcluster/__init__.py b/devcluster/__init__.py index 06e5df2..fc38cd9 100644 --- a/devcluster/__init__.py +++ b/devcluster/__init__.py @@ -18,6 +18,8 @@ CustomConfig, CustomDockerConfig, AtomicConfig, + read_path, + deep_merge_configs, ) from devcluster.recovery import ProcessTracker from devcluster.logger import Logger, Log, LogCB diff --git a/devcluster/__main__.py b/devcluster/__main__.py index 8f6cb2b..e350c1a 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -2,6 +2,7 @@ import argparse import contextlib +import pathlib import fcntl import os import subprocess @@ -184,18 +185,25 @@ def main() -> None: sys.exit(1) env["DOCKER_LOCALHOST"] = docker_localhost - with open(config_path) as f: - config_body = yaml.safe_load(f.read()) - if config_body is None: - print(f"config file '{config_path}' is an empty file!", file=sys.stderr) - sys.exit(1) - if not isinstance(config_body, dict): - print( - f"config file '{config_path}' does not represent a dict!", - file=sys.stderr, - ) - sys.exit(1) - config = dc.Config(dc.expand_env(config_body, env)) + def load_config_body(config_path: str) -> dict: + with open(config_path) as f: + config_body = yaml.safe_load(f.read()) + if config_body is None: + print(f"config file '{config_path}' is an empty file!", file=sys.stderr) + sys.exit(1) + if not isinstance(config_body, dict): + print( + f"config file '{config_path}' does not represent a dict!", + file=sys.stderr, + ) + sys.exit(1) + return config_body + + BASE_CONFIG_PATH = os.path.expanduser("~/.config/devcluster/base.yaml") + config_body = load_config_body(config_path) + base_config_body = load_config_body(BASE_CONFIG_PATH) + config = dc.Config(dc.expand_env(config_body, env), dc.expand_env(base_config_body, env)) + # Process cwd. cwd_path = None diff --git a/devcluster/config.py b/devcluster/config.py index 8165178..4dab01d 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -554,9 +554,57 @@ def read(config: typing.Any) -> "CommandConfig": check_list_of_strings(config, msg) return CommandConfig(config) +def deep_merge(obj1, obj2, predicate): + if isinstance(obj1, dict) and isinstance(obj2, dict): + return deep_merge_dict(obj1, obj2, predicate) + elif isinstance(obj1, list) and isinstance(obj2, list): + return deep_merge_list(obj1, obj2, predicate) + else: + return obj2 + +def deep_merge_dict(dict1, dict2, predicate): + result = dict1.copy() + for key, value in dict2.items(): + if key in dict1: + result[key] = deep_merge(dict1[key], value, predicate) + else: + result[key] = value + return result + +def deep_merge_list(list1, list2, predicate): + result = list1.copy() + for item2 in list2: + if not any(predicate(item1, item2) for item1 in list1): + result.append(item2) + else: + for index, item1 in enumerate(list1): + if predicate(item1, item2): + result[index] = deep_merge(item1, item2, predicate) + return result + + +def deep_merge_configs(o1: typing.Any, o2: typing.Any) -> typing.Dict: + def should_merge(d1: dict, d2: dict) -> bool: + # is a stage + if d1.keys() == d2.keys() and len(d1.keys()) == 1: + print(f"found stage {d1.keys()}") + print( d1, d2) + return True + + # is a rp + if d1.get("pool_name") is not None and d1.get("pool_name") == d2.get("pool_name"): + return True + + return False + + merged = deep_merge(o1, o2, should_merge) + return merged + class Config: - def __init__(self, config: typing.Any) -> None: + def __init__(self, config: typing.Any, base_config: typing.Optional[typing.Any] = None) -> None: + if base_config: + config = deep_merge_configs(base_config, config) allowed = {"stages", "commands", "startup_input", "temp_dir", "cwd"} required = {"stages"} check_keys(allowed, required, config, type(self).__name__) @@ -576,3 +624,4 @@ def __init__(self, config: typing.Any) -> None: self.cwd = read_path(config.get("cwd")) if self.cwd is not None: assert isinstance(self.cwd, str), "cwd must be a string" + diff --git a/devcluster/test_config.py b/devcluster/test_config.py new file mode 100644 index 0000000..745f115 --- /dev/null +++ b/devcluster/test_config.py @@ -0,0 +1,48 @@ +import devcluster as dc + +# test deep_merge_configs +def test_deep_merge_configs(): + # Test merge dicts + configs = [ + { + "stages": [ + {"stage1": {"param1": 1, "param2": 2}}, + {"stage5": {"param2": 3, "param3": 4}}, + {"stage4": {"param2": 3, "param3": 4}} + ] + }, + { + "stages": [ + {"stage1": {"param2": 3, "param3": 4}}, + {"stage3": {"param2": 3, "param3": 4}} + ] + }, + ] + merged = deep_merge_configs(configs[0], configs[1]) + assert merged.get("stages")[0] == {"stage1": {"param1": 1, "param2": 3, "param3": 4}} + + # Test merge lists of dicts with the same pool_name + configs = [ + {"pools": [{"pool_name": "pool1", "param1": 1}, {"pool_name": "pool2", "param1": 1}]}, + {"pools": [{"pool_name": "pool1", "param2": 2}, {"pool_name": "pool2", "param2": 2}]} + ] + merged = deep_merge_configs(configs[0], configs[1]) + assert merged == {"pools": [ + {"pool_name": "pool1", "param1": 1, "param2": 2}, + {"pool_name": "pool2", "param1": 1, "param2": 2} + ]} + + # Test merge lists of dicts with different pool_names + configs = [ + {"pools": [{"pool_name": "pool1", "param1": 1}, {"pool_name": "pool2", "param1": 1}]}, + {"pools": [{"pool_name": "pool3", "param1": 1}, {"pool_name": "pool4", "param1": 1}]} + ] + merged = deep_merge_configs(configs[0], configs[1]) + assert merged == {"pools": [ + {"pool_name": "pool1", "param1": 1}, + {"pool_name": "pool2", "param1": 1}, + {"pool_name": "pool3", "param1": 1}, + {"pool_name": "pool4", "param1": 1} + ]} + +test_deep_merge_configs() From 9e0b9d080e6b8bb95d5014e2e29feaef96864997 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Wed, 17 May 2023 11:38:14 -0700 Subject: [PATCH 02/14] load configs by name --- devcluster/__main__.py | 30 ++++++++++++++++++++++-------- devcluster/config.py | 2 -- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index e350c1a..71669bf 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -15,6 +15,8 @@ import devcluster as dc +CONFIG_DIR = pathlib.Path(os.path.expanduser("~/.config/devcluster")) +BASE_CONFIG_PATH = CONFIG_DIR / "_base.yaml" # prefer stdlib importlib.resources over pkg_resources, when available @typing.no_type_check @@ -146,9 +148,22 @@ def main() -> None: if not ok: sys.exit(1) + def expand_path(path: str) -> pathlib.Path: + """ + if the path doesn't exist try to match it with a known config name. + """ + p = pathlib.Path(path) + if not p.exists(): + p = CONFIG_DIR / (path + ".yaml") + if not p.exists(): + print(f"Path {path} does not exist", file=sys.stderr) + sys.exit(1) + return p + + # Read config before the cwd. if args.config is not None: - config_path = args.config + config_path = expand_path(args.config) else: check_paths = [] # Always support ~/.devcluster.yaml @@ -185,23 +200,22 @@ def main() -> None: sys.exit(1) env["DOCKER_LOCALHOST"] = docker_localhost - def load_config_body(config_path: str) -> dict: - with open(config_path) as f: + def load_config_body(path: str) -> dict: + with open(path) as f: config_body = yaml.safe_load(f.read()) if config_body is None: - print(f"config file '{config_path}' is an empty file!", file=sys.stderr) + print(f"config file '{path}' is an empty file!", file=sys.stderr) sys.exit(1) if not isinstance(config_body, dict): print( - f"config file '{config_path}' does not represent a dict!", + f"config file '{path}' does not represent a dict!", file=sys.stderr, ) sys.exit(1) return config_body - BASE_CONFIG_PATH = os.path.expanduser("~/.config/devcluster/base.yaml") - config_body = load_config_body(config_path) - base_config_body = load_config_body(BASE_CONFIG_PATH) + config_body = load_config_body(str(config_path)) + base_config_body = load_config_body(str(BASE_CONFIG_PATH)) config = dc.Config(dc.expand_env(config_body, env), dc.expand_env(base_config_body, env)) diff --git a/devcluster/config.py b/devcluster/config.py index 4dab01d..d5ef870 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -587,8 +587,6 @@ def deep_merge_configs(o1: typing.Any, o2: typing.Any) -> typing.Dict: def should_merge(d1: dict, d2: dict) -> bool: # is a stage if d1.keys() == d2.keys() and len(d1.keys()) == 1: - print(f"found stage {d1.keys()}") - print( d1, d2) return True # is a rp From 8c743d88fe3537a468d40630508298baed879813 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Wed, 17 May 2023 12:27:37 -0700 Subject: [PATCH 03/14] merge n configs. update testing --- Makefile | 1 + devcluster/config.py | 11 ++++++----- {devcluster => tests}/test_config.py | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) rename {devcluster => tests}/test_config.py (90%) diff --git a/Makefile b/Makefile index bb417b3..75a20bf 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ check: .PHONY: test test: python tests/test_e2e.py + python tests/test_config.py .PHONY: fmt fmt: diff --git a/devcluster/config.py b/devcluster/config.py index d5ef870..94389c8 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -4,6 +4,7 @@ import os import string import typing +import functools import devcluster as dc @@ -554,7 +555,8 @@ def read(config: typing.Any) -> "CommandConfig": check_list_of_strings(config, msg) return CommandConfig(config) -def deep_merge(obj1, obj2, predicate): +T = typing.TypeVar("T") +def deep_merge(obj1: T, obj2: T, predicate) -> T: if isinstance(obj1, dict) and isinstance(obj2, dict): return deep_merge_dict(obj1, obj2, predicate) elif isinstance(obj1, list) and isinstance(obj2, list): @@ -583,7 +585,7 @@ def deep_merge_list(list1, list2, predicate): return result -def deep_merge_configs(o1: typing.Any, o2: typing.Any) -> typing.Dict: +def deep_merge_configs(configs: typing.List[dict]) -> typing.Dict: def should_merge(d1: dict, d2: dict) -> bool: # is a stage if d1.keys() == d2.keys() and len(d1.keys()) == 1: @@ -595,14 +597,13 @@ def should_merge(d1: dict, d2: dict) -> bool: return False - merged = deep_merge(o1, o2, should_merge) - return merged + return functools.reduce(lambda x, y: deep_merge(x, y, should_merge), configs) class Config: def __init__(self, config: typing.Any, base_config: typing.Optional[typing.Any] = None) -> None: if base_config: - config = deep_merge_configs(base_config, config) + config = deep_merge_configs([base_config, config]) allowed = {"stages", "commands", "startup_input", "temp_dir", "cwd"} required = {"stages"} check_keys(allowed, required, config, type(self).__name__) diff --git a/devcluster/test_config.py b/tests/test_config.py similarity index 90% rename from devcluster/test_config.py rename to tests/test_config.py index 745f115..7fd6d36 100644 --- a/devcluster/test_config.py +++ b/tests/test_config.py @@ -18,7 +18,7 @@ def test_deep_merge_configs(): ] }, ] - merged = deep_merge_configs(configs[0], configs[1]) + merged = dc.deep_merge_configs(configs) assert merged.get("stages")[0] == {"stage1": {"param1": 1, "param2": 3, "param3": 4}} # Test merge lists of dicts with the same pool_name @@ -26,7 +26,7 @@ def test_deep_merge_configs(): {"pools": [{"pool_name": "pool1", "param1": 1}, {"pool_name": "pool2", "param1": 1}]}, {"pools": [{"pool_name": "pool1", "param2": 2}, {"pool_name": "pool2", "param2": 2}]} ] - merged = deep_merge_configs(configs[0], configs[1]) + merged = dc.deep_merge_configs(configs) assert merged == {"pools": [ {"pool_name": "pool1", "param1": 1, "param2": 2}, {"pool_name": "pool2", "param1": 1, "param2": 2} @@ -37,7 +37,7 @@ def test_deep_merge_configs(): {"pools": [{"pool_name": "pool1", "param1": 1}, {"pool_name": "pool2", "param1": 1}]}, {"pools": [{"pool_name": "pool3", "param1": 1}, {"pool_name": "pool4", "param1": 1}]} ] - merged = deep_merge_configs(configs[0], configs[1]) + merged = dc.deep_merge_configs(configs) assert merged == {"pools": [ {"pool_name": "pool1", "param1": 1}, {"pool_name": "pool2", "param1": 1}, From bb53e5766096ade9b73a753364dd01f85a2a6788 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Wed, 17 May 2023 12:30:58 -0700 Subject: [PATCH 04/14] report path expansion --- Pipfile | 23 +++ Pipfile.lock | 326 +++++++++++++++++++++++++++++++++++++++++ devcluster/__main__.py | 1 + initdb.sh | 16 ++ 4 files changed, 366 insertions(+) create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100755 initdb.sh diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..5fedd2f --- /dev/null +++ b/Pipfile @@ -0,0 +1,23 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +devcluster = {editable = true, file = "file:///Users/hmd/projects/da/devcluster"} +black = "==22.3.0" +mypy = "==0.780" +flake8 = ">=3.8.0" +flake8-bugbear = ">=19.8.0" +flake8-builtins = ">=1.5.3" +flake8-colors = ">=0.1.6" +flake8-commas = "==2.0.0" +flake8-comprehensions = ">=2.2.0" +flake8-docstrings = ">=1.4.0" +flake8-quotes = ">=2.1.0" +flake8-tuple = ">=0.4.0" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..ce8b669 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,326 @@ +{ + "_meta": { + "hash": { + "sha256": "73a5048b71ea5b92b1d519d7e7cf512b2000d347eef8d49f0e5c10bfdb916196" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "appdirs": { + "hashes": [ + "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", + "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" + ], + "version": "==1.4.4" + }, + "attrs": { + "hashes": [ + "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", + "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1.0" + }, + "black": { + "hashes": [ + "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b", + "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176", + "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09", + "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a", + "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015", + "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79", + "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb", + "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20", + "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464", + "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968", + "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82", + "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21", + "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0", + "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265", + "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b", + "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a", + "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72", + "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce", + "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0", + "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a", + "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163", + "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad", + "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d" + ], + "index": "pypi", + "version": "==22.3.0" + }, + "click": { + "hashes": [ + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.3" + }, + "devcluster": { + "editable": true, + "file": "file:///Users/hmd/projects/da/devcluster" + }, + "flake8": { + "hashes": [ + "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", + "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907" + ], + "index": "pypi", + "version": "==3.9.2" + }, + "flake8-bugbear": { + "hashes": [ + "sha256:beb5c7efcd7ccc2039ef66a77bb8db925e7be3531ff1cb4d0b7030d0e2113d72", + "sha256:e3e7f74c8a49ad3794a7183353026dabd68c74030d5f46571f84c1fb0eb79363" + ], + "index": "pypi", + "version": "==23.3.12" + }, + "flake8-builtins": { + "hashes": [ + "sha256:12ff1ee96dd4e1f3141141ee6c45a5c7d3b3c440d0949e9b8d345c42b39c51d4", + "sha256:469e8f03d6d0edf4b1e62b6d5a97dce4598592c8a13ec8f0952e7a185eba50a1" + ], + "index": "pypi", + "version": "==2.1.0" + }, + "flake8-colors": { + "hashes": [ + "sha256:35a5483a7d156d0438b402faea2fefe45b411571ce5dc93ba28670fd9429cc46", + "sha256:e80ed1839dc151730adc51207e632823aa1f393d6db32897ffd0e60dceecfd9f" + ], + "index": "pypi", + "version": "==0.1.9" + }, + "flake8-commas": { + "hashes": [ + "sha256:d3005899466f51380387df7151fb59afec666a0f4f4a2c6a8995b975de0f44b7", + "sha256:ee2141a3495ef9789a3894ed8802d03eff1eaaf98ce6d8653a7c573ef101935e" + ], + "index": "pypi", + "version": "==2.0.0" + }, + "flake8-comprehensions": { + "hashes": [ + "sha256:013234637ec7dfcb7cd2900578fb53c512f81db909cefe371c019232695c362d", + "sha256:419ef1a6e8de929203791a5e8ff5e3906caeba13eb3290eebdbf88a9078d502e" + ], + "index": "pypi", + "version": "==3.12.0" + }, + "flake8-docstrings": { + "hashes": [ + "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af", + "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75" + ], + "index": "pypi", + "version": "==1.7.0" + }, + "flake8-quotes": { + "hashes": [ + "sha256:6e26892b632dacba517bf27219c459a8396dcfac0f5e8204904c5a4ba9b480e1" + ], + "index": "pypi", + "version": "==3.3.2" + }, + "flake8-tuple": { + "hashes": [ + "sha256:8a1b42aab134ef4c3fef13c6a8f383363f158b19fbc165bd91aed9c51851a61d", + "sha256:d828cc8e461c50cacca116e9abb0c9e3be565e8451d3f5c00578c63670aae680" + ], + "index": "pypi", + "version": "==0.4.1" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "mypy": { + "hashes": [ + "sha256:00cb1964a7476e871d6108341ac9c1a857d6bd20bf5877f4773ac5e9d92cd3cd", + "sha256:127de5a9b817a03a98c5ae8a0c46a20dc44442af6dcfa2ae7f96cb519b312efa", + "sha256:1f3976a945ad7f0a0727aafdc5651c2d3278e3c88dee94e2bf75cd3386b7b2f4", + "sha256:2f8c098f12b402c19b735aec724cc9105cc1a9eea405d08814eb4b14a6fb1a41", + "sha256:4ef13b619a289aa025f2273e05e755f8049bb4eaba6d703a425de37d495d178d", + "sha256:5d142f219bf8c7894dfa79ebfb7d352c4c63a325e75f10dfb4c3db9417dcd135", + "sha256:62eb5dd4ea86bda8ce386f26684f7f26e4bfe6283c9f2b6ca6d17faf704dcfad", + "sha256:64c36eb0936d0bfb7d8da49f92c18e312ad2e3ed46e5548ae4ca997b0d33bd59", + "sha256:75eed74d2faf2759f79c5f56f17388defd2fc994222312ec54ee921e37b31ad4", + "sha256:974bebe3699b9b46278a7f076635d219183da26e1a675c1f8243a69221758273", + "sha256:a5e5bb12b7982b179af513dddb06fca12285f0316d74f3964078acbfcf4c68f2", + "sha256:d31291df31bafb997952dc0a17ebb2737f802c754aed31dd155a8bfe75112c57", + "sha256:d3b4941de44341227ece1caaf5b08b23e42ad4eeb8b603219afb11e9d4cfb437", + "sha256:eadb865126da4e3c4c95bdb47fe1bb087a3e3ea14d39a3b13224b8a4d9f9a102" + ], + "index": "pypi", + "version": "==0.780" + }, + "mypy-extensions": { + "hashes": [ + "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd" + ], + "markers": "python_version >= '2.7'", + "version": "==0.4.4" + }, + "pathspec": { + "hashes": [ + "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687", + "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293" + ], + "markers": "python_version >= '3.7'", + "version": "==0.11.1" + }, + "platformdirs": { + "hashes": [ + "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f", + "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5" + ], + "markers": "python_version >= '3.7'", + "version": "==3.5.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", + "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.7.0" + }, + "pydocstyle": { + "hashes": [ + "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", + "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1" + ], + "markers": "python_version >= '3.6'", + "version": "==6.3.0" + }, + "pyflakes": { + "hashes": [ + "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", + "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.3.1" + }, + "pyyaml": { + "hashes": [ + "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", + "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", + "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", + "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", + "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", + "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", + "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", + "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", + "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", + "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", + "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", + "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", + "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", + "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", + "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", + "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", + "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", + "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", + "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", + "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", + "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", + "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", + "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", + "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", + "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", + "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", + "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", + "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", + "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", + "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", + "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", + "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", + "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", + "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", + "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", + "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", + "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", + "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", + "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", + "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "version": "==1.16.0" + }, + "snowballstemmer": { + "hashes": [ + "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", + "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" + ], + "version": "==2.2.0" + }, + "typed-ast": { + "hashes": [ + "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace", + "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff", + "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266", + "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528", + "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6", + "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808", + "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4", + "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363", + "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341", + "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04", + "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41", + "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e", + "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3", + "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899", + "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805", + "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c", + "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c", + "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39", + "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a", + "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3", + "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7", + "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f", + "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075", + "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0", + "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40", + "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428", + "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927", + "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3", + "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f", + "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65" + ], + "version": "==1.4.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb", + "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4" + ], + "markers": "python_version >= '3.7'", + "version": "==4.5.0" + } + }, + "develop": {} +} diff --git a/devcluster/__main__.py b/devcluster/__main__.py index 71669bf..4273a63 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -158,6 +158,7 @@ def expand_path(path: str) -> pathlib.Path: if not p.exists(): print(f"Path {path} does not exist", file=sys.stderr) sys.exit(1) + print(f"expaned {path} to {p}") return p diff --git a/initdb.sh b/initdb.sh new file mode 100755 index 0000000..1c7ca6d --- /dev/null +++ b/initdb.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# create users +det u login admin +det user create hamid +det u change-password hamid + +det user create hamid-cadmin +det u change-password hamid-cadmin + +det user create hamid-admin --admin +det u change-password hamid-admin + +# set up roles +det rbac assign-role -u hamid-cadmin ClusterAdmin + From cd4d4ca445ba5d0a40883149bee48aa61e6af993 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Thu, 18 May 2023 10:44:56 -0700 Subject: [PATCH 05/14] cleanup --- Pipfile | 23 ---- Pipfile.lock | 326 --------------------------------------------------- initdb.sh | 16 --- 3 files changed, 365 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100755 initdb.sh diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 5fedd2f..0000000 --- a/Pipfile +++ /dev/null @@ -1,23 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -devcluster = {editable = true, file = "file:///Users/hmd/projects/da/devcluster"} -black = "==22.3.0" -mypy = "==0.780" -flake8 = ">=3.8.0" -flake8-bugbear = ">=19.8.0" -flake8-builtins = ">=1.5.3" -flake8-colors = ">=0.1.6" -flake8-commas = "==2.0.0" -flake8-comprehensions = ">=2.2.0" -flake8-docstrings = ">=1.4.0" -flake8-quotes = ">=2.1.0" -flake8-tuple = ">=0.4.0" - -[dev-packages] - -[requires] -python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index ce8b669..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,326 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "73a5048b71ea5b92b1d519d7e7cf512b2000d347eef8d49f0e5c10bfdb916196" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.11" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "appdirs": { - "hashes": [ - "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", - "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" - ], - "version": "==1.4.4" - }, - "attrs": { - "hashes": [ - "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", - "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" - ], - "markers": "python_version >= '3.7'", - "version": "==23.1.0" - }, - "black": { - "hashes": [ - "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b", - "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176", - "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09", - "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a", - "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015", - "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79", - "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb", - "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20", - "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464", - "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968", - "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82", - "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21", - "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0", - "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265", - "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b", - "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a", - "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72", - "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce", - "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0", - "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a", - "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163", - "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad", - "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d" - ], - "index": "pypi", - "version": "==22.3.0" - }, - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.3" - }, - "devcluster": { - "editable": true, - "file": "file:///Users/hmd/projects/da/devcluster" - }, - "flake8": { - "hashes": [ - "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", - "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907" - ], - "index": "pypi", - "version": "==3.9.2" - }, - "flake8-bugbear": { - "hashes": [ - "sha256:beb5c7efcd7ccc2039ef66a77bb8db925e7be3531ff1cb4d0b7030d0e2113d72", - "sha256:e3e7f74c8a49ad3794a7183353026dabd68c74030d5f46571f84c1fb0eb79363" - ], - "index": "pypi", - "version": "==23.3.12" - }, - "flake8-builtins": { - "hashes": [ - "sha256:12ff1ee96dd4e1f3141141ee6c45a5c7d3b3c440d0949e9b8d345c42b39c51d4", - "sha256:469e8f03d6d0edf4b1e62b6d5a97dce4598592c8a13ec8f0952e7a185eba50a1" - ], - "index": "pypi", - "version": "==2.1.0" - }, - "flake8-colors": { - "hashes": [ - "sha256:35a5483a7d156d0438b402faea2fefe45b411571ce5dc93ba28670fd9429cc46", - "sha256:e80ed1839dc151730adc51207e632823aa1f393d6db32897ffd0e60dceecfd9f" - ], - "index": "pypi", - "version": "==0.1.9" - }, - "flake8-commas": { - "hashes": [ - "sha256:d3005899466f51380387df7151fb59afec666a0f4f4a2c6a8995b975de0f44b7", - "sha256:ee2141a3495ef9789a3894ed8802d03eff1eaaf98ce6d8653a7c573ef101935e" - ], - "index": "pypi", - "version": "==2.0.0" - }, - "flake8-comprehensions": { - "hashes": [ - "sha256:013234637ec7dfcb7cd2900578fb53c512f81db909cefe371c019232695c362d", - "sha256:419ef1a6e8de929203791a5e8ff5e3906caeba13eb3290eebdbf88a9078d502e" - ], - "index": "pypi", - "version": "==3.12.0" - }, - "flake8-docstrings": { - "hashes": [ - "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af", - "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75" - ], - "index": "pypi", - "version": "==1.7.0" - }, - "flake8-quotes": { - "hashes": [ - "sha256:6e26892b632dacba517bf27219c459a8396dcfac0f5e8204904c5a4ba9b480e1" - ], - "index": "pypi", - "version": "==3.3.2" - }, - "flake8-tuple": { - "hashes": [ - "sha256:8a1b42aab134ef4c3fef13c6a8f383363f158b19fbc165bd91aed9c51851a61d", - "sha256:d828cc8e461c50cacca116e9abb0c9e3be565e8451d3f5c00578c63670aae680" - ], - "index": "pypi", - "version": "==0.4.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "mypy": { - "hashes": [ - "sha256:00cb1964a7476e871d6108341ac9c1a857d6bd20bf5877f4773ac5e9d92cd3cd", - "sha256:127de5a9b817a03a98c5ae8a0c46a20dc44442af6dcfa2ae7f96cb519b312efa", - "sha256:1f3976a945ad7f0a0727aafdc5651c2d3278e3c88dee94e2bf75cd3386b7b2f4", - "sha256:2f8c098f12b402c19b735aec724cc9105cc1a9eea405d08814eb4b14a6fb1a41", - "sha256:4ef13b619a289aa025f2273e05e755f8049bb4eaba6d703a425de37d495d178d", - "sha256:5d142f219bf8c7894dfa79ebfb7d352c4c63a325e75f10dfb4c3db9417dcd135", - "sha256:62eb5dd4ea86bda8ce386f26684f7f26e4bfe6283c9f2b6ca6d17faf704dcfad", - "sha256:64c36eb0936d0bfb7d8da49f92c18e312ad2e3ed46e5548ae4ca997b0d33bd59", - "sha256:75eed74d2faf2759f79c5f56f17388defd2fc994222312ec54ee921e37b31ad4", - "sha256:974bebe3699b9b46278a7f076635d219183da26e1a675c1f8243a69221758273", - "sha256:a5e5bb12b7982b179af513dddb06fca12285f0316d74f3964078acbfcf4c68f2", - "sha256:d31291df31bafb997952dc0a17ebb2737f802c754aed31dd155a8bfe75112c57", - "sha256:d3b4941de44341227ece1caaf5b08b23e42ad4eeb8b603219afb11e9d4cfb437", - "sha256:eadb865126da4e3c4c95bdb47fe1bb087a3e3ea14d39a3b13224b8a4d9f9a102" - ], - "index": "pypi", - "version": "==0.780" - }, - "mypy-extensions": { - "hashes": [ - "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd" - ], - "markers": "python_version >= '2.7'", - "version": "==0.4.4" - }, - "pathspec": { - "hashes": [ - "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687", - "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293" - ], - "markers": "python_version >= '3.7'", - "version": "==0.11.1" - }, - "platformdirs": { - "hashes": [ - "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f", - "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5" - ], - "markers": "python_version >= '3.7'", - "version": "==3.5.1" - }, - "pycodestyle": { - "hashes": [ - "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", - "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.7.0" - }, - "pydocstyle": { - "hashes": [ - "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", - "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1" - ], - "markers": "python_version >= '3.6'", - "version": "==6.3.0" - }, - "pyflakes": { - "hashes": [ - "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", - "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.3.1" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", - "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" - ], - "version": "==2.2.0" - }, - "typed-ast": { - "hashes": [ - "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace", - "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff", - "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266", - "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528", - "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6", - "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808", - "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4", - "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363", - "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341", - "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04", - "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41", - "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e", - "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3", - "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899", - "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805", - "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c", - "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c", - "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39", - "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a", - "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3", - "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7", - "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f", - "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075", - "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0", - "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40", - "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428", - "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927", - "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3", - "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f", - "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65" - ], - "version": "==1.4.3" - }, - "typing-extensions": { - "hashes": [ - "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb", - "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4" - ], - "markers": "python_version >= '3.7'", - "version": "==4.5.0" - } - }, - "develop": {} -} diff --git a/initdb.sh b/initdb.sh deleted file mode 100755 index 1c7ca6d..0000000 --- a/initdb.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# create users -det u login admin -det user create hamid -det u change-password hamid - -det user create hamid-cadmin -det u change-password hamid-cadmin - -det user create hamid-admin --admin -det u change-password hamid-admin - -# set up roles -det rbac assign-role -u hamid-cadmin ClusterAdmin - From aea0f32cb6639263489c5aca7fe2bfe8ce6fcec1 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:57:46 -0700 Subject: [PATCH 06/14] allow multiple configs. TODO check order --- devcluster/__main__.py | 16 +++++++++++----- devcluster/config.py | 10 +++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index 0964c7f..bc877f7 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -8,7 +8,7 @@ import subprocess import re import sys -from typing import Iterator, no_type_check, Optional, Sequence +from typing import Iterator, List, no_type_check, Optional, Sequence import appdirs import yaml @@ -101,7 +101,7 @@ def maybe_install_default_config() -> Optional[str]: def main() -> None: parser = argparse.ArgumentParser() - parser.add_argument("-c", "--config", dest="config", action="store") + parser.add_argument("-c", "--config", dest="config", action="store", nargs='+', help="Provide one or more config files") parser.add_argument("-1", "--oneshot", dest="oneshot", action="store_true") parser.add_argument("-q", "--quiet", dest="quiet", action="store_true") parser.add_argument("-C", "--cwd", dest="cwd", action="store") @@ -163,8 +163,10 @@ def expand_path(path: str) -> pathlib.Path: # Read config before the cwd. + config_paths: List[pathlib.Path] = [] if args.config is not None: - config_path = expand_path(args.config) + for path in args.config: + config_paths.append(expand_path(path)) else: check_paths = [] # Always support ~/.devcluster.yaml @@ -215,9 +217,13 @@ def load_config_body(path: str) -> dict: sys.exit(1) return config_body - config_body = load_config_body(str(config_path)) + config_bodies = [load_config_body(str(path)) for path in config_paths] base_config_body = load_config_body(str(BASE_CONFIG_PATH)) - config = dc.Config(dc.expand_env(config_body, env), dc.expand_env(base_config_body, env)) + config = dc.Config( + *[ + dc.expand_env(conf_body, env) for conf_body in [base_config_body] + config_bodies + ] + ) # Process cwd. diff --git a/devcluster/config.py b/devcluster/config.py index a6ef5be..c241822 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -591,9 +591,13 @@ def should_merge(d1: dict, d2: dict) -> bool: class Config: - def __init__(self, config: typing.Any, base_config: typing.Optional[typing.Any] = None) -> None: - if base_config: - config = deep_merge_configs([base_config, config]) + def __init__(self, *configs: typing.Any) -> None: + assert len(configs) > 0, "must provide at least one config" + if len(configs) > 1: + config = deep_merge_configs(list(configs)) + else: + config = configs[0] + assert isinstance(config, dict), "config must be a dict" allowed = {"stages", "commands", "startup_input", "temp_dir", "cwd"} required = {"stages"} check_keys(allowed, required, config, type(self).__name__) From 64beb2cd166e322b4db8293e2703274f2f7c79b6 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:08:49 -0800 Subject: [PATCH 07/14] list out available configs when a config is not found --- devcluster/__main__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index bc877f7..df64dc9 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -157,6 +157,10 @@ def expand_path(path: str) -> pathlib.Path: p = CONFIG_DIR / (path + ".yaml") if not p.exists(): print(f"Path {path} does not exist", file=sys.stderr) + print("Available configs:") + for f in CONFIG_DIR.iterdir(): + if f.is_file(): + print(f" {f.stem}") sys.exit(1) print(f"expaned {path} to {p}") return p From dc452c9ec91ec03977ced7c8aa1016f1b6427f57 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Thu, 14 Mar 2024 11:49:18 -0500 Subject: [PATCH 08/14] disable auto loading base config --- devcluster/__main__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index df64dc9..b9755de 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -222,10 +222,11 @@ def load_config_body(path: str) -> dict: return config_body config_bodies = [load_config_body(str(path)) for path in config_paths] - base_config_body = load_config_body(str(BASE_CONFIG_PATH)) + # base_config_body = load_config_body(str(BASE_CONFIG_PATH)) config = dc.Config( *[ - dc.expand_env(conf_body, env) for conf_body in [base_config_body] + config_bodies + # dc.expand_env(conf_body, env) for conf_body in [base_config_body] + config_bodies + dc.expand_env(conf_body, env) for conf_body in config_bodies ] ) From d2d67b1802f91ebc976a8da9abb9ebd246af7026 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Thu, 14 Mar 2024 12:11:38 -0500 Subject: [PATCH 09/14] throwaway PGSERVICE --- devcluster/__main__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index b9755de..c864cc2 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -117,6 +117,12 @@ def main() -> None: else: mode = "client" + blacklist = ["PGSERVICE"] # det binary lib/pq complains. + for key in blacklist: + if key in os.environ: + print(f"Unsetting {key} from environment") + del os.environ[key] + # Validate args ok = True if mode == "client": From f06bc1cb2d746435ba85fdad6c2111a6896bc766 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:18:28 -0500 Subject: [PATCH 10/14] read DOCKER_LOCALHOST from env --- devcluster/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index c864cc2..daf660e 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -55,7 +55,7 @@ def get_host_addr_for_docker() -> Optional[str]: if "darwin" in sys.platform: # On macOS, docker runs in a VM and host.docker.internal points to the IP # address of this VM. - return "host.docker.internal" + return os.getenv("DOCKER_LOCALHOST", "host.docker.internal") # On non-macOS, host.docker.internal does not exist. Instead, grab the source IP # address we would use if we had to talk to the internet. The sed command From 07204e71b50da44db08a99c4d8a105380869f682 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:12:41 -0500 Subject: [PATCH 11/14] change merging behavior for specific keys needs a more general solution --- devcluster/config.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/devcluster/config.py b/devcluster/config.py index 1a6a36f..35d4889 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -569,7 +569,8 @@ def deep_merge(obj1: T, obj2: T, predicate) -> T: def deep_merge_dict(dict1, dict2, predicate): result = dict1.copy() for key, value in dict2.items(): - if key in dict1: + override_no_merge = ["resource_manager"] + if key in dict1 and not key in override_no_merge: result[key] = deep_merge(dict1[key], value, predicate) else: result[key] = value @@ -588,18 +589,19 @@ def deep_merge_list(list1, list2, predicate): def deep_merge_configs(configs: typing.List[dict]) -> typing.Dict: - def should_merge(d1: dict, d2: dict) -> bool: + def should_merge(base: dict, override: dict) -> bool: + """compare same level keys""" # is a stage - if d1.keys() == d2.keys() and len(d1.keys()) == 1: + if base.keys() == override.keys() and len(base.keys()) == 1: return True # is a rp - if d1.get("pool_name") is not None and d1.get("pool_name") == d2.get("pool_name"): + if base.get("pool_name") is not None and base.get("pool_name") == override.get("pool_name"): return True return False - return functools.reduce(lambda x, y: deep_merge(x, y, should_merge), configs) + return functools.reduce(lambda base, override: deep_merge(base, override, should_merge), configs) class Config: @@ -607,6 +609,8 @@ def __init__(self, *configs: typing.Any) -> None: assert len(configs) > 0, "must provide at least one config" if len(configs) > 1: config = deep_merge_configs(list(configs)) + print("merged config:") + print(yaml.dump(config)) else: config = configs[0] assert isinstance(config, dict), "config must be a dict" From 42fa42f6803a6fa5145e834bad7853ea72202b9c Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Fri, 24 May 2024 11:46:59 -0500 Subject: [PATCH 12/14] Revert "change merging behavior for specific keys" This reverts commit 07204e71b50da44db08a99c4d8a105380869f682. --- devcluster/config.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/devcluster/config.py b/devcluster/config.py index 35d4889..1a6a36f 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -569,8 +569,7 @@ def deep_merge(obj1: T, obj2: T, predicate) -> T: def deep_merge_dict(dict1, dict2, predicate): result = dict1.copy() for key, value in dict2.items(): - override_no_merge = ["resource_manager"] - if key in dict1 and not key in override_no_merge: + if key in dict1: result[key] = deep_merge(dict1[key], value, predicate) else: result[key] = value @@ -589,19 +588,18 @@ def deep_merge_list(list1, list2, predicate): def deep_merge_configs(configs: typing.List[dict]) -> typing.Dict: - def should_merge(base: dict, override: dict) -> bool: - """compare same level keys""" + def should_merge(d1: dict, d2: dict) -> bool: # is a stage - if base.keys() == override.keys() and len(base.keys()) == 1: + if d1.keys() == d2.keys() and len(d1.keys()) == 1: return True # is a rp - if base.get("pool_name") is not None and base.get("pool_name") == override.get("pool_name"): + if d1.get("pool_name") is not None and d1.get("pool_name") == d2.get("pool_name"): return True return False - return functools.reduce(lambda base, override: deep_merge(base, override, should_merge), configs) + return functools.reduce(lambda x, y: deep_merge(x, y, should_merge), configs) class Config: @@ -609,8 +607,6 @@ def __init__(self, *configs: typing.Any) -> None: assert len(configs) > 0, "must provide at least one config" if len(configs) > 1: config = deep_merge_configs(list(configs)) - print("merged config:") - print(yaml.dump(config)) else: config = configs[0] assert isinstance(config, dict), "config must be a dict" From c116d0672718042e723d5c5693b65fa6f3b45879 Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:05:14 -0500 Subject: [PATCH 13/14] skip obvious non-configs as relative config --- devcluster/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devcluster/__main__.py b/devcluster/__main__.py index daf660e..5075a8c 100644 --- a/devcluster/__main__.py +++ b/devcluster/__main__.py @@ -159,7 +159,8 @@ def expand_path(path: str) -> pathlib.Path: if the path doesn't exist try to match it with a known config name. """ p = pathlib.Path(path) - if not p.exists(): + # TODO: check if it looks like a config. + if not p.exists() or not p.is_file(): p = CONFIG_DIR / (path + ".yaml") if not p.exists(): print(f"Path {path} does not exist", file=sys.stderr) From 3d447a3cfd1d7485f3437122f3f401c5b6aa42ee Mon Sep 17 00:00:00 2001 From: Hamid Zare <12127420+hamidzr@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:32:06 -0500 Subject: [PATCH 14/14] fix bad env err msg --- devcluster/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devcluster/config.py b/devcluster/config.py index 1a6a36f..3a95d01 100644 --- a/devcluster/config.py +++ b/devcluster/config.py @@ -479,7 +479,7 @@ def __init__(self, config: Any) -> None: self.name = check_string(config["name"], "CustomConfig.name must be a string") self.env = config.get("env", {}) - check_dict_with_string_keys(self.env, "CustomConfig.pre must be a list of dicts") + check_dict_with_string_keys(self.env, "CustomConfig.env must be dictionary") self.cwd = read_path(config.get("cwd")) if self.cwd is not None: