From 81ea0425e736d04cdb282d2c066532c41bf752e3 Mon Sep 17 00:00:00 2001 From: fabiobarkoski Date: Mon, 22 Jan 2024 14:01:07 -0300 Subject: [PATCH] feat(CLI): Create the basics of the cli to up created some basics commands, options and help option for up and the its commands --- README.md | 21 ++++++++++ upcli/poetry.lock | 79 ++++++++++++++++++++++++++++++++++++- upcli/pyproject.toml | 1 + upcli/up/__version__.py | 2 + upcli/up/commands.py | 82 +++++++++++++++++++++++++++++++++++++++ upcli/up/help_texts.py | 35 +++++++++++++++++ upcli/up/main.py | 36 ++++++++--------- upcli/up/options.py | 51 ++++++++++++++++++++++++ upcli/up/utils.py | 10 +++++ uplib/uplib/__init__.py | 4 +- uplib/uplib/config.py | 8 ++-- uplib/uplib/containers.py | 10 +++-- uplib/uplib/logging.py | 4 +- 13 files changed, 314 insertions(+), 29 deletions(-) create mode 100644 upcli/up/__version__.py create mode 100644 upcli/up/commands.py create mode 100644 upcli/up/help_texts.py create mode 100644 upcli/up/options.py create mode 100644 upcli/up/utils.py diff --git a/README.md b/README.md index c901669..c27e309 100755 --- a/README.md +++ b/README.md @@ -31,3 +31,24 @@ Provide a framework so that solutions can be automated with Ansible, and leverag For a better integration with the Ansible ecosystem, this project is mostly written in python, using pluggy as a plugin system. +# Documentation + +## The CLI + +### How do I use up? +Below, an example usage of up: +```bash +$ up ansible --version # will output the Ansible version +``` +"But what if I want to pass a port or volume?" So you have 2 options: first: set the volume/port inside the `up.yaml` of your plugin, or in the example case the Ansible plugin; or second: pass the volume/port on the command, e.g: +```bash +$ up -Xp=8080/tcp:5000 ansible --version # will set the port in the container +$ up -Xv=/home:/mnt/vol3,rw ansible --version # will set the volume in the container +``` +### Does up have some internal command? +Yes, the current available commands are in `plugin` reserved keyword: +```bash +$ up plugin list # List all installed plugins +$ up plugin prompts ansible # Shows the prompts from up.yaml of a plugin +$ up plugin details ansible --version # Shows the prompt configuration from up.yaml of a plugin +``` diff --git a/upcli/poetry.lock b/upcli/poetry.lock index ffa3bc3..a06fb22 100644 --- a/upcli/poetry.lock +++ b/upcli/poetry.lock @@ -1,5 +1,82 @@ # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +[[package]] +name = "ruamel-yaml" +version = "0.18.5" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruamel.yaml-0.18.5-py3-none-any.whl", hash = "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada"}, + {file = "ruamel.yaml-0.18.5.tar.gz", hash = "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = false +python-versions = ">=3.6" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + [[package]] name = "up-ansible" version = "0.2.19" @@ -68,4 +145,4 @@ url = "../uplib" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "497e71b21cfd072d61e638e3b23af28ef43e25cd1d731f95d88e2521f9946f72" +content-hash = "179cb217c2eb1052ef7ff2e4c3275f17bfac95d04bf63a0d148909d5e0c64891" diff --git a/upcli/pyproject.toml b/upcli/pyproject.toml index c32852b..08bb16e 100644 --- a/upcli/pyproject.toml +++ b/upcli/pyproject.toml @@ -15,6 +15,7 @@ up-splat = "^0.2.19" up-ansible = "^0.2.19" up-aws = "^0.2.19" up-demo = "^0.2.19" +ruamel-yaml = "^0.18.5" [build-system] requires = ["poetry-core"] diff --git a/upcli/up/__version__.py b/upcli/up/__version__.py new file mode 100644 index 0000000..a4cc8de --- /dev/null +++ b/upcli/up/__version__.py @@ -0,0 +1,2 @@ +version = "0.2.19" + diff --git a/upcli/up/commands.py b/upcli/up/commands.py new file mode 100644 index 0000000..379032c --- /dev/null +++ b/upcli/up/commands.py @@ -0,0 +1,82 @@ +import sys +import pkgutil +from pathlib import Path +from ruamel.yaml import YAML +from typing import TypeAlias +from collections.abc import Callable, Iterator +from importlib.util import find_spec + +from uplib import Prompt +from up.help_texts import list_help_text, details_help_text, prompts_help_text + +yaml=YAML() + +Arguments: TypeAlias = list[str] +Commands: TypeAlias = dict[str, tuple[Callable[[Arguments], None], str]] + +def _get_prompts(plugin_name: str) -> Iterator[dict]: + plugin_path = Path(find_spec(f"up_{plugin_name}").origin).parent + prompts_path = Path(plugin_path, 'up.yaml') + try: + with open(prompts_path, 'r') as file: + prompts = (yaml.load(file))['prompts'] + for prompt in prompts: + yield prompt + except FileNotFoundError: + raise FileNotFoundError("Plugin doens't have yaml file!") + +def _list_plugins(args: Arguments): + """ + Shows all installed plugins + """ + plugins = [] + for pkg in pkgutil.iter_modules(): + if pkg.name.startswith("up_"): + plugins.append(pkg.name) + print("Installed plugins:") + print("\n".join(plugins)) + +def _list_prompts(args: Arguments): + """ + Shows the prompts from up.yaml of a plugin + """ + for prompt in _get_prompts(args[0]): + yaml.dump(prompt, sys.stdout) + +def _prompt_details(args: Arguments): + """ + Shows the prompt configuration from up.yaml of a plugin + """ + for prompt in _get_prompts(args[0]): + if prompt['prompt'] == ' '.join(args): + yaml.dump(prompt, sys.stdout) + break + +_commands: Commands = { + "list": (_list_plugins, list_help_text), + "prompts": (_list_prompts, prompts_help_text), + "details": (_prompt_details, details_help_text), +} + +def _get_command_description(command:str) -> str: + description = _commands[command][0].__doc__.replace('\n','') + return description.lstrip() + +def cmd_in_prompt(prompt: Prompt) -> bool: + reserved_keyword = prompt[0] + if reserved_keyword != 'plugin' or len(prompt) <= 1: + return False + command = prompt[1] + match command: + case cmd if cmd in _commands.keys(): + return True + case _: + raise Exception('Command not found!') + +def run_cmd(command: str, arguments: Arguments): + if len(arguments) == 1 and '--help' in arguments or '-h' in arguments: + cmd_description = _get_command_description(command) + print(_commands[command][1] % cmd_description) + exit(0) + _commands[command][0](arguments) + exit(0) diff --git a/upcli/up/help_texts.py b/upcli/up/help_texts.py new file mode 100644 index 0000000..dc58d12 --- /dev/null +++ b/upcli/up/help_texts.py @@ -0,0 +1,35 @@ +up_help_text = """\rUnified and Pluggable CLI - Version %s + \n\rUsage: + up + or + up plugin + \n\rPrompt options: + -Xv\t Set a volume to be used + -Xp\t Set a port to be used + \n\rAvailable commands: + \r%s + + \rExamples: + up ansible --version\t Shows ansible version + up -Xp={8080/tcp: 5000} ansible -h\t Will set the port to ansible + up plugin prompts ansible\t List all ansible prompts from up.yaml + """ +list_help_text = """\rDescription: %s + \n\rUsage: + up plugin list + """ +details_help_text = """\rDescription: %s + \n\rUsage: + up plugin details + + \rExample: + up plugin details ansible --version\t Shows prompt configuration from up.yaml + """ +prompts_help_text = """Description: %s + \n\rUsage: + up plugin prompts + + \rExample: + up plugin details ansible\t List all ansible prompts from up.yaml + """ + diff --git a/upcli/up/main.py b/upcli/up/main.py index 757d063..3966cde 100644 --- a/upcli/up/main.py +++ b/upcli/up/main.py @@ -1,42 +1,42 @@ import sys from datetime import datetime -import shlex -import pkgutil import uplib +from up.__version__ import version +from up.options import setup_options +from up.help_texts import up_help_text +from up.utils import get_commands_information +from up.commands import cmd_in_prompt, run_cmd log = uplib.log -def print_help(): - log.debug("up [prompt]") - -def get_modules(): - up_plugins = [] - for pkg in pkgutil.iter_modules(): - if pkg.name.startswith("up_"): - up_plugins.append(pkg.name) - return up_plugins +def _print_up_help(args) -> bool: + if len(args) == 2: + if args[1] == "--help" or args[1] == "-h": + return True + return False def exit_cli(code=-1): if code: log.error("Exiting up cli with code %s", code) - if code == "NO_COMMAND_SPECIFIED": - log.error(f"installed plugins:\n{'\n'.join(get_modules())}") sys.exit(code) def cli_main(): now = datetime.now() log.info(f"Starting UP cli at {now.isoformat()}") args = sys.argv - len_args = len(args) - if len_args <= 1: - print_help() - exit_cli("NO_COMMAND_SPECIFIED") + if len(args) <= 1 or _print_up_help(args): + print(up_help_text % (version, get_commands_information())) + exit(0) executable = args[0] prompt = args[1:] + if cmd_in_prompt(prompt): + run_cmd(prompt[1], prompt[2:]) context = {"executable": executable} try: - uplib.up_main(context, prompt) + prompt_without_options = setup_options(prompt) + print(prompt_without_options) + uplib.up_main(context, prompt_without_options) except Exception as e: log.error(e) # print stack trace diff --git a/upcli/up/options.py b/upcli/up/options.py new file mode 100644 index 0000000..5271925 --- /dev/null +++ b/upcli/up/options.py @@ -0,0 +1,51 @@ +import re +from shlex import join + +from uplib import options_map, Prompt + +_options_pattern = re.compile(r'\-X\w+\=\S+') + +def _have_options(prompt: Prompt) -> bool: + if _options_pattern.match(join(prompt)): + return True + return False + +def _match_value(pattern: str, string: str) -> str: + value = re.match(pattern, string) + return value.groups()[0] + +def _set_ports(value: str): + formated_value = value.split(':') + options_map['ports'] = {formated_value[0]: formated_value[1]} + +def _set_volumes(value: str): + formated_value = value.split(':') + volume_key = formated_value[0] + volume_bind = formated_value[1].split(',')[0] + volume_mode = formated_value[1].split(',')[1] + options_map['volumes'] = { + volume_key: { + 'bind': volume_bind, + 'mode': volume_mode, + }, + } + +_options = { + 'p': _set_ports, + 'v': _set_volumes, +} + +def _set_option(option: str): + key = _match_value(r'\-X(\w)', option) + value = _match_value(r'\-X\w.(.+)', option) + _options[key](value) + +def setup_options(prompt: Prompt) -> Prompt: + prompt_without_options = join(prompt) + if _have_options(prompt): + for option in _options_pattern.findall(join(prompt)): + _set_option(option) + prompt_without_options = _options_pattern.sub( + '', prompt_without_options) + return prompt_without_options.lstrip().split() + return prompt diff --git a/upcli/up/utils.py b/upcli/up/utils.py new file mode 100644 index 0000000..2b483e5 --- /dev/null +++ b/upcli/up/utils.py @@ -0,0 +1,10 @@ +from up.commands import _commands + +def get_commands_information() -> str: + commands = [] + for key, value in _commands.items(): + command = key + command_description = value[0].__doc__.replace('\n','') + commands.append(f" {command}\t {command_description}") + return "\n".join(commands) + diff --git a/uplib/uplib/__init__.py b/uplib/uplib/__init__.py index 2c080d2..2c71aae 100644 --- a/uplib/uplib/__init__.py +++ b/uplib/uplib/__init__.py @@ -1,9 +1,10 @@ import pluggy -from typing import TypeAlias +from typing import TypeAlias, Union Context: TypeAlias = dict[str, str] Prompt: TypeAlias = list[str] +Options: TypeAlias = dict[str, dict[str, dict[str, str] | str]] # TODO: Consider moving all globals to a single object @@ -11,6 +12,7 @@ hookimpl = pluggy.HookimplMarker("up") pm = pluggy.PluginManager("up") settings_maps = {} +options_map: Options = {} from .match import does_match, if_prompt_matches from .containers import ContainerRun, ContainerRuns diff --git a/uplib/uplib/config.py b/uplib/uplib/config.py index e78ecfd..bcd78df 100644 --- a/uplib/uplib/config.py +++ b/uplib/uplib/config.py @@ -68,7 +68,7 @@ class Config(Enum): # (key, default_value) default_image = ("default_image", "fedora") welcome_message = ("welcome_message", "Thank your for running UP!") - log_level = ("log_level", "INFO") + log_level = ("log_level", "ERROR") volumes = ("volumes", {}) ports = ("ports", {}) prompts = ("prompts", []) @@ -80,6 +80,8 @@ def get(self): def get_log_level(): - return Config.log_level.get() - + try: + return Settings().settings.log_level + except AttributeError: + return Config.log_level.get() diff --git a/uplib/uplib/containers.py b/uplib/uplib/containers.py index ac005e9..f7d4d74 100644 --- a/uplib/uplib/containers.py +++ b/uplib/uplib/containers.py @@ -9,7 +9,7 @@ from typing import TypeAlias from .logging import log from datetime import datetime -from . import settings_maps +from . import settings_maps, options_map # https://docker-py.readthedocs.io/en/stable/containers.html @dataclass @@ -55,19 +55,21 @@ def volumes_of(cls, run: ContainerRun, prompt: str): "mode": "rw" } } + options_volumes = options_map.get('volumes', {}) print(type(run.volumes)) print(run.volumes) - result = run.volumes | settings_vols | default_vols + result = run.volumes | settings_vols | default_vols | options_volumes return result @classmethod def ports_of(cls, prompt: str): plugin_name = prompt.split()[0] + options_ports = options_map.get('ports', {}) default_ports = settings_maps.get(plugin_name, {}).get("ports", {}) ports = default_ports.to_dict() if default_ports else {} if settings_maps.get(plugin_name, {} ).get(prompt): ports = ports | settings_maps[plugin_name][prompt].get("ports", {}) - return ports + return ports | options_ports def run(self, run: ContainerRun): client = docker.from_env() @@ -76,7 +78,7 @@ def run(self, run: ContainerRun): #TODO: Consider if every command should be auto-wrapped in bash (perhaops detect if contains pipes or redirects) command = run.command - prompt = ' '.join(run.command[1:]) + prompt = ' '.join(run.command) if (run.bash_wrap): command = ["sh", "-c", subprocess.list2cmdline(command)] log.debug("$: %s", run) diff --git a/uplib/uplib/logging.py b/uplib/uplib/logging.py index d06f900..94254cd 100644 --- a/uplib/uplib/logging.py +++ b/uplib/uplib/logging.py @@ -1,12 +1,12 @@ import sys import logging -from .config import get_log_level from rich.logging import RichHandler +from .config import get_log_level TRACE = 5 def init_logging(): - sys.set_int_max_str_digits(999999) + sys.set_int_max_str_digits(999999) level = get_log_level() print("Initializing logging with level "+str(level)) logging.basicConfig(