From 068fb80a4934900fd1f321cb20eb016c56f72c78 Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 12:31:46 +0200 Subject: [PATCH 1/9] add some type hints --- n_utils/utils.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/n_utils/utils.py b/n_utils/utils.py index f9b1757..e8c1fc2 100644 --- a/n_utils/utils.py +++ b/n_utils/utils.py @@ -191,21 +191,25 @@ def interpolate_file( params = deepcopy(os.environ) else: params = {} + if not stack_name and is_ec2() and not skip_stack: params.update(info().stack_data_dict()) elif stack_name and not skip_stack: stack_params, _ = stack_params_and_outputs_and_stack(stack_name=stack_name) params.update(stack_params) + vault = None vault_keys = [] if use_vault: vault = Vault() vault_keys = vault.list_all() + with open(file_name, encoding=encoding) as _infile: with dstfile as _outfile: for line in _infile: line = _process_line(line, params, vault, vault_keys) _outfile.write(_to_bytes(line, encoding=encoding)) + shutil.copy(dstfile.name, destination) os.unlink(dstfile.name) @@ -282,7 +286,7 @@ def expand_only_double_paranthesis_params(line, params, vault, vault_keys): return line -def _process_line(line, params, vault, vault_keys): +def _process_line(line, params, vault: Vault, vault_keys: list[str]): ret = line ret = _process_line_re(ret, params, vault, vault_keys, SIMPLE_PARAM_RE) ret = _process_line_re(ret, params, vault, vault_keys, DOUBLE_PARANTHESIS_RE) @@ -290,7 +294,7 @@ def _process_line(line, params, vault, vault_keys): return ret -def _process_line_re(line, params, vault, vault_keys, matcher): +def _process_line_re(line, params, vault: Vault, vault_keys: list[str], matcher): ret = line next_start = 0 match = matcher.search(line) @@ -325,6 +329,7 @@ def _process_line_re(line, params, vault, vault_keys, matcher): else: ret = ret[: match.start()] + _to_str(param_value) + ret[match.end() :] match = matcher.search(ret, next_start) + return ret From 147442e16362c46fbd8da37daa7d7e36642a3555 Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 13:05:05 +0200 Subject: [PATCH 2/9] fix license in pyproject --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index fecca14..11c55d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ description = "Tools for deploying to AWS via CloudFormation and Serverless fram readme = "README.md" requires-python = ">=3.9" authors = [{ name = "Pasi Niemi", email = "pasi@nitor.com" }] -license = { text = "Apache 2.0" } +license = { text = "Apache-2.0" } dynamic = ["entry-points"] dependencies = [ "argcomplete", From 15b01e55e6a6890f60dbe7aa83e2f5aa2d4c8a05 Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 13:05:12 +0200 Subject: [PATCH 3/9] use https for link --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 11c55d8..b4b2b7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ requires = ["setuptools", "wheel", "build"] build-backend = "setuptools.build_meta" [project.urls] -Homepage = "http://github.com/NitorCreations/nameless-deploy-tools" +Homepage = "https://github.com/NitorCreations/nameless-deploy-tools" Download = "https://github.com/NitorCreations/nameless-deploy-tools/tarball/1.326" [project.scripts] From 916d72d053ac9972414cc15cf05a1b4cf979e898 Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 13:11:12 +0200 Subject: [PATCH 4/9] update nitor vault version to 2.x --- dev-requirements.txt | 22 +++++++--------------- pyproject.toml | 2 +- requirements.txt | 20 ++++++-------------- uv.lock | 31 +++++++++++++++---------------- 4 files changed, 29 insertions(+), 46 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index dad4154..fa0f918 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,12 +4,11 @@ argcomplete==3.5.1 # via # nameless-deploy-tools (pyproject.toml) # ec2-utils - # nitor-vault -boto3==1.35.58 +boto3==1.35.60 # via # nameless-deploy-tools (pyproject.toml) # threadlocal-aws -botocore==1.35.58 +botocore==1.35.60 # via # boto3 # s3transfer @@ -34,9 +33,7 @@ coverage==7.6.4 # nameless-deploy-tools (pyproject.toml) # pytest-cov cryptography==43.0.3 - # via - # nitor-vault - # pyopenssl + # via pyopenssl decorator==5.1.1 # via retry docutils==0.21.2 @@ -44,9 +41,7 @@ docutils==0.21.2 ec2-utils==0.38 # via nameless-deploy-tools (pyproject.toml) future==1.0.0 - # via - # ec2-utils - # nitor-vault + # via ec2-utils idna==3.10 # via requests importlib-metadata==8.5.0 @@ -83,7 +78,7 @@ netifaces==0.11.0 # via ec2-utils nh3==0.2.18 # via readme-renderer -nitor-vault==0.56 +nitor-vault==2.2.0 # via nameless-deploy-tools (pyproject.toml) packaging==24.2 # via @@ -145,7 +140,6 @@ requests==2.32.3 # via # nameless-deploy-tools (pyproject.toml) # ec2-utils - # nitor-vault # requests-toolbelt # threadlocal-aws # twine @@ -163,7 +157,7 @@ s3transfer==0.10.3 # via boto3 scandir==1.10.0 # via nameless-deploy-tools (pyproject.toml) -setuptools==75.4.0 +setuptools==75.5.0 # via # nameless-deploy-tools (pyproject.toml) # pip-tools @@ -174,9 +168,7 @@ termcolor==2.5.0 # nameless-deploy-tools (pyproject.toml) # ec2-utils threadlocal-aws==0.11 - # via - # ec2-utils - # nitor-vault + # via ec2-utils twine==5.1.1 # via nameless-deploy-tools (pyproject.toml) urllib3==2.2.3 diff --git a/pyproject.toml b/pyproject.toml index b4b2b7b..4c0ce6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "ec2-utils>=0.38", "ipaddr", "jmespath", - "nitor-vault~=0.56", + "nitor-vault~=2.2", "pyaml", "pycryptodomex", "Pygments", diff --git a/requirements.txt b/requirements.txt index 14f986b..0165b3a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,12 +4,11 @@ argcomplete==3.5.1 # via # nameless-deploy-tools (pyproject.toml) # ec2-utils - # nitor-vault -boto3==1.35.58 +boto3==1.35.60 # via # nameless-deploy-tools (pyproject.toml) # threadlocal-aws -botocore==1.35.58 +botocore==1.35.60 # via # boto3 # s3transfer @@ -24,17 +23,13 @@ cloudformation-utils==0.0.2 configparser==7.1.0 # via nameless-deploy-tools (pyproject.toml) cryptography==43.0.3 - # via - # nitor-vault - # pyopenssl + # via pyopenssl decorator==5.1.1 # via retry ec2-utils==0.38 # via nameless-deploy-tools (pyproject.toml) future==1.0.0 - # via - # ec2-utils - # nitor-vault + # via ec2-utils idna==3.10 # via requests ipaddr==2.2.0 @@ -47,7 +42,7 @@ jmespath==1.0.1 # ec2-utils netifaces==0.11.0 # via ec2-utils -nitor-vault==0.56 +nitor-vault==2.2.0 # via nameless-deploy-tools (pyproject.toml) py==1.11.0 # via retry @@ -79,7 +74,6 @@ requests==2.32.3 # via # nameless-deploy-tools (pyproject.toml) # ec2-utils - # nitor-vault # threadlocal-aws retry==0.9.2 # via ec2-utils @@ -94,9 +88,7 @@ termcolor==2.5.0 # nameless-deploy-tools (pyproject.toml) # ec2-utils threadlocal-aws==0.11 - # via - # ec2-utils - # nitor-vault + # via ec2-utils urllib3==2.2.3 # via # botocore diff --git a/uv.lock b/uv.lock index 02c4194..25282c0 100644 --- a/uv.lock +++ b/uv.lock @@ -572,7 +572,7 @@ wheels = [ [[package]] name = "nameless-deploy-tools" -version = "1.324" +version = "1.326" source = { editable = "." } dependencies = [ { name = "argcomplete" }, @@ -630,7 +630,7 @@ requires-dist = [ { name = "ipaddr" }, { name = "jmespath" }, { name = "mock", marker = "extra == 'testing'" }, - { name = "nitor-vault", specifier = "~=0.56" }, + { name = "nitor-vault", specifier = "~=2.2" }, { name = "pip-tools", marker = "extra == 'dev'" }, { name = "pyaml" }, { name = "pycryptodomex" }, @@ -692,21 +692,20 @@ wheels = [ [[package]] name = "nitor-vault" -version = "0.56" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "argcomplete" }, - { name = "cryptography" }, - { name = "future" }, - { name = "pypiwin32", marker = "platform_system == 'Windows'" }, - { name = "requests" }, - { name = "threadlocal-aws" }, - { name = "win-unicode-console", marker = "platform_system == 'Windows'" }, - { name = "wmi", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/70/2c8b384cf8bb589b8922a05733ad60439d2152de1734ece2b1a0412d8cf1/nitor_vault-0.56.tar.gz", hash = "sha256:c3415ea77da4cd9dc721928e66194b51d609f229efd4bfe054ae6260b861c1be", size = 15508 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/66/07/72b44a650058b7d7b7b1dd5a23ced33e2fb6231263959c469bef64dc29c0/nitor_vault-0.56-py3-none-any.whl", hash = "sha256:e492e09f7adb8ea3611682cad5a029d60ad70624dc022623697656bafed171db", size = 15330 }, +sdist = { url = "https://files.pythonhosted.org/packages/5b/52/ee7186e2169718d286f6ffc29ef076d6a997b787ad773a46d56356c22ebd/nitor_vault-2.2.0.tar.gz", hash = "sha256:ea6aa547bbbff313508085206eaf54b5cbe5efe94b79769c55b14d0c527db003", size = 77568 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/a0/bcce5a2aecb994900eddf152eb11c76f53618de0423d2f1447a8dfe5feb9/nitor_vault-2.2.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f6d39ed52357d759f10a1d3ba855a382f7da8d8011346fa71250928bb62a2315", size = 5845643 }, + { url = "https://files.pythonhosted.org/packages/0b/a6/1d7978c30924059204864fc72a1e60ec78457dc47cb7d3ef4cfc0385c0b6/nitor_vault-2.2.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ce511c9b7e517035398ed757dec5253ada81d47fa4a0387e4dcba5b8ec4d695a", size = 5634462 }, + { url = "https://files.pythonhosted.org/packages/b9/35/8698bcf47fdccbf41867124556e9db0c5b529b64ab1075363163233ba118/nitor_vault-2.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19924476e44b13b78a19c240db2a7e128b0f51a96a5d260538767f4f4cef6ceb", size = 5123056 }, + { url = "https://files.pythonhosted.org/packages/5a/c8/6f4cdcec231494a014629806ffc2db92eda7060b4b4bb6e78a630eb08273/nitor_vault-2.2.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f19d768d681649c92163e737e80c9198af5e311ae2eff518787a24236d2df7c6", size = 5410915 }, + { url = "https://files.pythonhosted.org/packages/09/48/5f4c6510f6b67d7c6daef6c0f5d9ae5b5a9930fc45665bab61dd35f2be38/nitor_vault-2.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7af914266c6be409e91ae7a4556d957634c1bc039e087c3338d78caca971e80", size = 5368383 }, + { url = "https://files.pythonhosted.org/packages/08/e3/2c3a7abadf1fa2955821aa768e0b683a437c38d1bcb2c070728e4c5e3373/nitor_vault-2.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fee87af3ba53080f50b95f6c65285b742b0a3622d41c5a94933e90abed683273", size = 6707187 }, + { url = "https://files.pythonhosted.org/packages/94/c8/d5c16cbccf9dcd6494faeef39bcf41ed3451f9719d88461eb71e7eb1335e/nitor_vault-2.2.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:b6a286a8ec45770424175570eabf21bfbb4409f14a599cf4c2cf79d87144dd74", size = 6332939 }, + { url = "https://files.pythonhosted.org/packages/d3/45/e98647181b5e6810f6221eda66481836fd4e3723538647a2e05749281da8/nitor_vault-2.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:0260fd3b2e177dce68f997ac85012bd79512c88771414f7f983192ffb3272b80", size = 6605648 }, + { url = "https://files.pythonhosted.org/packages/1a/af/8c52091c124ff818e9e3bf829c9a4fb24dfd119f833804a61136ee946077/nitor_vault-2.2.0-cp39-abi3-win32.whl", hash = "sha256:bbcb75567bea4adfa2667be4c43ec25543391b437030b8c75e279b6c849450be", size = 4371654 }, + { url = "https://files.pythonhosted.org/packages/af/e6/a5301c8052ba28313d012c8f4bfabe34f415f96ab7448651d6d2d8f18b53/nitor_vault-2.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:7dd46ba91e6552e20cd6ebd9a2b2a21e8f0ebd645f348500da926651f811408d", size = 5091018 }, ] [[package]] From 68a1ab5321bd37c7917a7b8868cd695bec363da6 Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 13:26:42 +0200 Subject: [PATCH 5/9] code cleanup for cli --- n_utils/cli.py | 150 +++++++++++++++++++++++++++-------------------- n_utils/utils.py | 9 ++- 2 files changed, 91 insertions(+), 68 deletions(-) diff --git a/n_utils/cli.py b/n_utils/cli.py index c2f8ea6..deaf9b6 100755 --- a/n_utils/cli.py +++ b/n_utils/cli.py @@ -78,6 +78,31 @@ NoneType = type(None) +class SubCCompleter: + def __init__(self, sc_type): + self.sc_type = sc_type + + def __call__(self, prefix="", action=None, parser=None, parsed_args=None): + p_args = {} + if hasattr(parsed_args, "branch") and parsed_args.branch: + p_args["branch"] = parsed_args.branch + if hasattr(parsed_args, "component") and parsed_args.component: + return [ + sc.name + for sc in Project(**p_args).get_component(parsed_args.component).get_subcomponents() + if sc.type == self.sc_type and sc.name.startswith(prefix) + ] + else: + return [sc.name for sc in Project(**p_args).get_all_subcomponents() if sc.type == self.sc_type] + + +class FlowNameCompleter: + def __call__(self, prefix="", action=None, parser=None, parsed_args=None): + instance_id = _resolve_connect_instance(parsed_args) + if instance_id: + return [flow for flow in connect.get_flows(instance_id).keys() if flow.startswith(prefix)] + + def get_parser(formatter=None): func_name = inspect.stack()[1][3] caller = sys._getframe().f_back @@ -138,8 +163,8 @@ def colorprint(data, output_format="yaml"): def yaml_to_json(): - """Convert nameless CloudFormation yaml to CloudFormation json with some - preprosessing + """ + Convert nameless CloudFormation yaml to CloudFormation json with some preprocessing """ parser = get_parser() parser.add_argument("--colorize", "-c", help="Colorize output", action="store_true") @@ -184,7 +209,8 @@ def yaml_to_yaml(): def json_to_yaml(): - """Convert CloudFormation json to an approximation of a nameless CloudFormation + """ + Convert CloudFormation json to an approximation of a nameless CloudFormation yaml with for example scripts externalized """ parser = get_parser() @@ -335,7 +361,8 @@ def resolve_all_includes(): def assume_role(): - """Assume a defined role. Prints out environment variables + """ + Assume a defined role. Prints out environment variables to be eval'd to current context for use: eval $(ndt assume-role 'arn:aws:iam::43243246645:role/DeployRole') """ @@ -433,7 +460,8 @@ def session_to_env(): def clean_snapshots(): - """Clean snapshots that are older than a number of days (30 by default) and + """ + Clean snapshots that are older than a number of days (30 by default) and have one of specified tag values """ parser = get_parser() @@ -468,9 +496,9 @@ def clean_snapshots(): def setup_cli(): - """Setup the command line environment to define an aws cli profile with - the given name and credentials. If an identically named profile exists, - it will not be overwritten. + """ + Setup the command line environment to define an aws cli profile with the given name and credentials. + If an identically named profile exists, it will not be overwritten. """ parser = get_parser() parser.add_argument("-n", "--name", help="Name for the profile to create") @@ -511,7 +539,7 @@ def show_terraform_params(): parser = get_parser() parser.add_argument( "component", help="The component containg the terraform subcomponet" - ).completer = ChoicesCompleter(component_having_a_subcomponent_of_type("terraform")) + ).completer = ChoicesCompleter(_component_having_a_subcomponent_of_type("terraform")) parser.add_argument("terraform", help="The name of the terraform subcomponent").completer = SubCCompleter( "terraform" ) @@ -540,7 +568,7 @@ def show_azure_params(): """Show available parameters for a azure subcomponent""" parser = get_parser() parser.add_argument("component", help="The component containg the azure subcomponet").completer = ChoicesCompleter( - component_having_a_subcomponent_of_type("azure") + _component_having_a_subcomponent_of_type("azure") ) parser.add_argument("azure", help="The name of the azure subcomponent").completer = SubCCompleter("azure") param = parser.add_mutually_exclusive_group(required=False) @@ -595,7 +623,8 @@ def cli_share_to_another_region(): def cli_interpolate_file(): - """Replace placeholders in file with parameter values from stack and + """ + Replace placeholders in file with parameter values from stack and optionally from vault """ parser = get_parser() @@ -644,8 +673,9 @@ def cli_interpolate_file(): def cli_ecr_ensure_repo(): - """Ensure that an ECR repository exists and get the uri and login token for - it""" + """ + Ensure that an ECR repository exists and get the uri and login token for it + """ parser = get_parser() parser.add_argument("name", help="The name of the ecr repository to verify") argcomplete.autocomplete(parser) @@ -758,9 +788,11 @@ def cli_upsert_cloudfront_records(): def cli_mfa_add_token(): - """Adds an MFA token to be used with role assumption. + """ + Adds an MFA token to be used with role assumption. Tokens will be saved in a .ndt subdirectory in the user's home directory. - If a token with the same name already exists, it will not be overwritten.""" + If a token with the same name already exists, it will not be overwritten. + """ parser = get_parser() parser.add_argument( "token_name", @@ -804,7 +836,7 @@ def cli_mfa_add_token(): try: mfa_add_token(args) except ValueError as error: - parser.error(error) + parser.error(str(error)) def cli_mfa_delete_token(): @@ -838,7 +870,8 @@ def cli_mfa_to_qrcode(): def cli_mfa_backup_tokens(): - """Encrypt or decrypt a backup JSON structure of tokens. + """ + Encrypt or decrypt a backup JSON structure of tokens. To output an encrypted backup, provide an encryption secret. @@ -906,7 +939,9 @@ def cli_create_account(): def cli_load_parameters(): - """Load parameters from infra*.properties files in the order: + """ + Load parameters from infra*.properties files in the order: + branch.properties [branch].properties infra.properties, @@ -1037,13 +1072,14 @@ def cli_load_parameters(): "image, stack, doker, serverless, azure, connect, cdk or terraform do not make sense without component" ) filter_arr = [] + filter_types = {} if args.filter: filter_arr = args.filter.split(",") - filter_types = {} for filter_entry in filter_arr.copy(): if len(filter_entry.split(":")) > 1: filter_arr = list(map(lambda x: x.replace(filter_entry, filter_entry.split(":")[0]), filter_arr)) filter_types[filter_entry.split(":")[0]] = filter_entry.split(":")[1] + del args.filter parameters = load_parameters(**vars(args)) if filter_arr: @@ -1052,40 +1088,16 @@ def cli_load_parameters(): del parameters[param_key] elif param_key in filter_types: _cast_param(param_key, parameters, filter_types[param_key]) - print(transform(parameters)) - -def _cast_param(key, params, param_type): - if param_type == "int": - params[key] = int(params[key]) - elif param_type == "bool": - params[key] = params[key] and params[key].lower() == "true" - return - - -class SubCCompleter: - def __init__(self, sc_type): - self.sc_type = sc_type - - def __call__(self, prefix="", action=None, parser=None, parsed_args=None): - p_args = {} - if hasattr(parsed_args, "branch") and parsed_args.branch: - p_args["branch"] = parsed_args.branch - if hasattr(parsed_args, "component") and parsed_args.component: - return [ - sc.name - for sc in Project(**p_args).get_component(parsed_args.component).get_subcomponents() - if sc.type == self.sc_type and sc.name.startswith(prefix) - ] - else: - return [sc.name for sc in Project(**p_args).get_all_subcomponents() if sc.type == self.sc_type] - return None + print(transform(parameters)) def map_to_exports(map): - """Prints the map as eval-able set of environment variables. Keys + """ + Prints the map as eval-able set of environment variables. Keys will be cleaned of all non-word letters and values will be escaped so - that they will be exported as literal values.""" + that they will be exported as literal values. + """ ret = "" keys = [] for key, val in list(map.items()): @@ -1104,13 +1116,16 @@ def map_to_exports(map): key = re.sub("[^a-zA-Z0-9_]", "", key) ret += key + "=" + value + os.linesep keys.append(key) + ret += "export " + " ".join(keys) + os.linesep return ret def map_to_properties(map): - """Prints the map as loadable set of java properties. Keys - will be cleaned of all non-word letters.""" + """ + Prints the map as loadable set of java properties. Keys + will be cleaned of all non-word letters. + """ ret = "" for key, val in list(map.items()): key = re.sub("[^a-zA-Z0-9_]", "", key) @@ -1118,6 +1133,7 @@ def map_to_properties(map): ret += key + "=" + val + os.linesep else: ret += key + "=" + json_save_small(val) + os.linesep + return ret @@ -1127,6 +1143,7 @@ def map_to_tfvars(map): for key, val in list(map.items()): if "${" not in val: ret += key + "=" + json.dumps(val) + "\n" + return ret @@ -1139,6 +1156,7 @@ def map_to_azure_params(map): } for key, val in list(map.items()): ret_map["parameters"][key] = {"value": val} + return json.dumps(ret_map) @@ -1151,8 +1169,10 @@ def cli_assumed_role_name(): def cli_list_jobs(): - """Prints a line for every runnable job in this git repository, in all branches and - optionally exports the properties for each under '$root/job-properties/""" + """ + Prints a line for every runnable job in this git repository, in all branches and + optionally exports the properties for each under '$root/job-properties/ + """ parser = get_parser() parser.add_argument( "-e", @@ -1188,8 +1208,8 @@ def cli_list_jobs(): def branch_components(prefix, parsed_args, **kwargs): if parsed_args.branch: return [c.name for c in Project(branch=parsed_args.branch).get_components()] - else: - return [c.name for c in Project().get_components()] + + return [c.name for c in Project().get_components()] def cli_list_components(): @@ -1375,7 +1395,7 @@ def deploy_connect_contact_flows(): parser.add_argument( "component", help="the component directory where the connect contact flow directory is", - ).completer = ChoicesCompleter(component_having_a_subcomponent_of_type("connect")) + ).completer = ChoicesCompleter(_component_having_a_subcomponent_of_type("connect")) parser.add_argument( "contactflowname", help="the name of the connect subcomponent directory that has the contact flow template", @@ -1398,7 +1418,7 @@ def export_connect_contact_flow(): "-c", "--component", help="the component directory where the connect contact flow directory is", - ).completer = ChoicesCompleter(component_having_a_subcomponent_of_type("connect")) + ).completer = ChoicesCompleter(_component_having_a_subcomponent_of_type("connect")) parser.add_argument( "-f", "--contactflowname", @@ -1432,7 +1452,7 @@ def list_connect_contact_flows(): "-c", "--component", help="the component directory where the connect contact flow directory is", - ).completer = ChoicesCompleter(component_having_a_subcomponent_of_type("connect")) + ).completer = ChoicesCompleter(_component_having_a_subcomponent_of_type("connect")) parser.add_argument( "-f", "--contactflowname", @@ -1458,12 +1478,13 @@ def list_connect_contact_flows(): print(flow) -def component_having_a_subcomponent_of_type(subcomponent_type): +def _component_having_a_subcomponent_of_type(subcomponent_type): ret = [] for dir in [x for x in next(os.walk("."))[1] if not x.startswith(".")]: for subd in next(os.walk(dir))[1]: if subd.startswith(subcomponent_type + "-") and dir not in ret: ret.append(dir) + return ret @@ -1481,11 +1502,14 @@ def _resolve_connect_instance(args): flow_template = yaml_to_dict(template_dir + os.sep + "template.yaml") if "connectInstanceId" in flow_template: return flow_template["connectInstanceId"] + return None -class FlowNameCompleter: - def __call__(self, prefix="", action=None, parser=None, parsed_args=None): - instance_id = _resolve_connect_instance(parsed_args) - if instance_id: - return [flow for flow in connect.get_flows(instance_id).keys() if flow.startswith(prefix)] +def _cast_param(key, params, param_type): + if param_type == "int": + params[key] = int(params[key]) + elif param_type == "bool": + params[key] = params[key] and params[key].lower() == "true" + + return diff --git a/n_utils/utils.py b/n_utils/utils.py index e8c1fc2..72568d7 100644 --- a/n_utils/utils.py +++ b/n_utils/utils.py @@ -46,6 +46,10 @@ INSTANCE_DATA_LINUX = "/opt/nameless/instance-data.json" INSTANCE_DATA_WIN = "C:/nameless/instance-data.json" +PARAM_RE = re.compile(r"\$\{([^\$\{\}]*)\}", re.M) +SIMPLE_PARAM_RE = re.compile(r"\$([a-zA-Z0-9_]*)", re.M) +DOUBLE_PARANTHESIS_RE = re.compile(r"\(\(([^)]+)\)\)", re.M) + def dthandler(obj): return obj.isoformat() if hasattr(obj, "isoformat") else json.JSONEncoder().default(obj) @@ -214,11 +218,6 @@ def interpolate_file( os.unlink(dstfile.name) -PARAM_RE = re.compile(r"\$\{([^\$\{\}]*)\}", re.M) -SIMPLE_PARAM_RE = re.compile(r"\$([a-zA-Z0-9_]*)", re.M) -DOUBLE_PARANTHESIS_RE = re.compile(r"\(\(([^)]+)\)\)", re.M) - - def _apply_simple_regex(re, line, params, vault, vault_keys): ret = line next_start = 0 From d0a9ea6a54f7858d7db5e9b001447a0be7ee0b4b Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 15:32:24 +0200 Subject: [PATCH 6/9] tweaks to github actions --- .github/workflows/pytest.yml | 14 +++++++------- .github/workflows/ruff.yml | 14 ++++++++------ .pre-commit-config.yaml | 12 +++--------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 2811f2b..8ed2395 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -5,15 +5,15 @@ on: branches: - master paths: - - ".github/workflows/pytest.yml" - "**.py" + - ".github/workflows/pytest.yml" - "dev-requirements.txt" - "pyproject.toml" - "requirements.txt" pull_request: paths: - - ".github/workflows/pytest.yml" - "**.py" + - ".github/workflows/pytest.yml" - "dev-requirements.txt" - "pyproject.toml" - "requirements.txt" @@ -43,14 +43,14 @@ jobs: - name: Install dependencies run: | if [ ! -d ".venv" ]; then - python -m venv .venv + python3 -m venv .venv fi source .venv/bin/activate - pip install -U pip setuptools wheel - pip install -r requirements.txt - pip install -r dev-requirements.txt + python3 -m pip install -U pip setuptools wheel + python3 -m pip install -r requirements.txt + python3 -m pip install -r dev-requirements.txt - name: Run tests run: | source .venv/bin/activate - python -m pytest --verbose --color=yes . + python3 -m pytest --verbose --color=yes . diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 64863b2..d1e81fc 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -5,18 +5,20 @@ on: branches: - master paths: - - ".github/workflows/ruff.yml" - "**.py" + - ".github/workflows/ruff.yml" - "pyproject.toml" - "requirements.txt" + - "dev-requirements.txt" pull_request: paths: - - ".github/workflows/ruff.yml" - "**.py" + - ".github/workflows/ruff.yml" - "pyproject.toml" - "requirements.txt" + - "dev-requirements.txt" -# https://github.com/chartboost/ruff-action +# https://github.com/astral-sh/ruff-action jobs: lint: runs-on: ubuntu-latest @@ -27,14 +29,14 @@ jobs: - name: Set up Python environment uses: actions/setup-python@v5 with: - python-version: "3.12" + python-version: 3.x - name: Ruff lint - uses: chartboost/ruff-action@v1 + uses: astral-sh/ruff-action@v1 with: args: check --verbose - name: Ruff format - uses: chartboost/ruff-action@v1 + uses: astral-sh/ruff-action@v1 with: args: format --check --verbose diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4e894e9..6a449de 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: check-merge-conflict - id: check-toml - id: check-yaml - args: [--unsafe] + args: [ --unsafe ] - id: debug-statements - id: end-of-file-fixer exclude: ^docs/commands\.md$ @@ -25,13 +25,7 @@ repos: hooks: - id: ruff name: python ruff lint - args: [--fix, --exit-non-zero-on-fix] + args: [ --fix, --exit-non-zero-on-fix ] - id: ruff-format name: python ruff format - args: [--check] - - - repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - name: python isort + args: [ --check ] From 71042a4eeb69e264d96142ad61519c99a79e17bb Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 15:32:44 +0200 Subject: [PATCH 7/9] simplify c++ compiler selection for faster reg complete script --- faster_register_complete.sh | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/faster_register_complete.sh b/faster_register_complete.sh index 495b26f..80cdc5f 100755 --- a/faster_register_complete.sh +++ b/faster_register_complete.sh @@ -41,25 +41,8 @@ DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # shellcheck source=./common.sh source "$DIR/common.sh" -ARGS=(-std=c++20 -O3 -Wall -Wextra) - -if [ "$BASH_PLATFORM" = mac ]; then - # 03/2023: - # try to use brew llvm / Clang since it is newer than what Apple includes. - # Critically, Clang 14 does not yet support `march` compiler option for Apple Silicon, - # but brew llvm comes with Clang 15 that does support it so we can get the full benefit from the C++ code. - # This can be removed once macOS comes with Clang 15 by default... - if [ -e "$(brew --prefix)/opt/llvm/bin/clang++" ]; then - COMPILER="$(brew --prefix)/opt/llvm/bin/clang++" - ARGS+=(-march=native -mtune=native) - else - echo "You might want to install the latest Clang from brew ('brew install llvm') to get the best results..." - COMPILER="g++" - fi -else - COMPILER="g++" - ARGS+=(-march=native -mtune=native) -fi +ARGS=(-std=c++20 -O3 -Wall -Wextra -march=native -mtune=native) +COMPILER="g++" if [ -n "$(command -v nameless-dt-register-complete)" ]; then print_yellow "Overwriting existing script: nameless-dt-register-complete" From 3160b4b2b07430db07deab8297fb24486a804a0a Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 15:53:33 +0200 Subject: [PATCH 8/9] pre-commit update --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6a449de..5345bc9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,8 +20,8 @@ repos: - id: trailing-whitespace exclude: ^docs/commands\.md$ - - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.7.1 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.7.3 hooks: - id: ruff name: python ruff lint From 14851be7dc7d7fa1e96a6422b63e86b036bbda24 Mon Sep 17 00:00:00 2001 From: Akseli Lukkarila Date: Thu, 14 Nov 2024 16:30:45 +0200 Subject: [PATCH 9/9] readability formatting --- n_utils/aws_infra_util.py | 15 ++++++++------- n_utils/utils.py | 3 +++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/n_utils/aws_infra_util.py b/n_utils/aws_infra_util.py index 3cd40d6..a2faa43 100644 --- a/n_utils/aws_infra_util.py +++ b/n_utils/aws_infra_util.py @@ -173,12 +173,11 @@ def _resolve_ssm_parameter(ssm_key, region=None): def _resolve_vault_parameter(vault_key): - value = None if vault_key in vault_params: - value = vault_params[vault_key] - else: - value = Vault().lookup(vault_key) - vault_params[vault_key] = value + return vault_params[vault_key] + + value = Vault().lookup(vault_key) + vault_params[vault_key] = value return value @@ -322,7 +321,6 @@ def _process_value(value, used_params): def joined_file_lines(filename): with open(filename) as f: prevline = "" - to_yeild = None for line in f.readlines(): if prevline.strip().endswith("\\"): to_yeild = None @@ -1004,6 +1002,7 @@ def param_refresh_callback(): elif isinstance(data, list): for i in range(0, len(data)): data[i] = _preprocess_template(data[i], root, basefile, path + str(i) + "_", template_params) + return data @@ -1135,13 +1134,15 @@ def extract_script(prefix, path, join_args): filename = encode_script_filename(prefix, path) sys.stderr.write(prefix + ": Exported path '" + path + "' contents to file '" + filename + "'\n") - with open(filename, "w") as script_file: # opens file with name of "test.txt" + # opens file with name of "test.txt" + with open(filename, "w") as script_file: script_file.write(code[0]) script_file.write("\n") for var_name, var_decl in list(var_decls.items()): script_file.write(var_decl) script_file.write("\n") script_file.write(code[1]) + return filename diff --git a/n_utils/utils.py b/n_utils/utils.py index 72568d7..c1e0a35 100644 --- a/n_utils/utils.py +++ b/n_utils/utils.py @@ -308,12 +308,14 @@ def _process_line_re(line, params, vault: Vault, vault_keys: list[str], matcher) param_name = param_match name_arg.append(transform) break + if param_name in vault_keys: param_value = vault.lookup(param_name) elif param_name in params: param_value = params[param_name] else: next_start = match.end() + if name_arg: if param_value and (PARAM_RE.search(param_value) or SIMPLE_PARAM_RE.search(param_value)): param_value = None @@ -327,6 +329,7 @@ def _process_line_re(line, params, vault: Vault, vault_keys: list[str], matcher) return param_value else: ret = ret[: match.start()] + _to_str(param_value) + ret[match.end() :] + match = matcher.search(ret, next_start) return ret