From ea9f5e227968e2175dacc6aa5586d4eb857d2053 Mon Sep 17 00:00:00 2001 From: ldericher <40151420+ldericher@users.noreply.github.com> Date: Thu, 2 Dec 2021 17:19:14 +0100 Subject: [PATCH] Split cli.py --- kiwi_scp/commands/cli.py | 181 +----------------------------- kiwi_scp/commands/cmd.py | 184 +++++++++++++++++++++++++++++++ kiwi_scp/commands/cmd_build.py | 2 +- kiwi_scp/commands/cmd_cmd.py | 2 +- kiwi_scp/commands/cmd_disable.py | 2 +- kiwi_scp/commands/cmd_down.py | 2 +- kiwi_scp/commands/cmd_enable.py | 2 +- kiwi_scp/commands/cmd_init.py | 2 +- kiwi_scp/commands/cmd_list.py | 2 +- kiwi_scp/commands/cmd_logs.py | 2 +- kiwi_scp/commands/cmd_up.py | 2 +- kiwi_scp/commands/decorators.py | 2 +- 12 files changed, 195 insertions(+), 190 deletions(-) create mode 100644 kiwi_scp/commands/cmd.py diff --git a/kiwi_scp/commands/cli.py b/kiwi_scp/commands/cli.py index cc4cb04..f38b72e 100644 --- a/kiwi_scp/commands/cli.py +++ b/kiwi_scp/commands/cli.py @@ -1,19 +1,9 @@ import importlib -import logging import os -import sys -from enum import Enum, auto -from typing import List, Iterable, Type, Optional, TypeVar +from typing import List, Optional import click -from ..instance import Instance -from ..project import Project -from ..services import Services -from ..wstring import WParagraph, WAlignment - -_logger = logging.getLogger(__name__) - class KiwiCLI(click.MultiCommand): """Command Line Interface spread over multiple files in this directory""" @@ -42,172 +32,3 @@ class KiwiCLI(click.MultiCommand): return member -class KiwiCommandType(Enum): - INSTANCE = auto() - PROJECT = auto() - PROJECTS = auto() - SERVICES = auto() - - -T = TypeVar("T") - - -class KiwiCommand: - type: KiwiCommandType = KiwiCommandType.SERVICES - enabled_only: bool = False - - @staticmethod - def print_header(header: str) -> None: - click.secho(header, fg="green", bold=True) - - @staticmethod - def print_error(error: str) -> None: - click.secho(error, file=sys.stderr, fg="red", bold=True) - - @staticmethod - def print_list(content: Iterable[str]) -> None: - for item in content: - click.echo(click.style(" - ", fg="green") + click.style(item, fg="blue")) - - @staticmethod - def user_query(description: str, default: T, cast_to: Type[T] = str) -> T: - # prompt user as per argument - while True: - try: - prompt = \ - click.style(f"Enter {description} [", fg="green") + \ - click.style(default, fg="blue") + \ - click.style("] ", fg="green") - str_value = input(prompt).strip() - if str_value: - return cast_to(str_value) - else: - return default - - except EOFError: - click.echo("Input aborted.") - return default - - except Exception as e: - click.echo(f"Invalid input: {e}") - - @staticmethod - def danger_confirm(*prompt_lines: str, default: Optional[bool] = None) -> bool: - if default is True: - suffix = "[YES|no]" - default_answer = "yes" - - elif default is False: - suffix = "[yes|NO]" - default_answer = "no" - - else: - suffix = "[yes|no]" - default_answer = None - - dumb = WParagraph.from_strings( - click.style("WARNING", bold=True, underline=True, blink=True, fg="red"), - click.style("ここにゴミ", fg="cyan"), - click.style("を捨てないで下さい", fg="cyan"), - click.style("DO NOT DUMB HERE", fg="yellow"), - click.style("NO DUMB AREA", fg="yellow"), - ).align(WAlignment.CENTER).surround("!") - - prompt = WParagraph.from_strings(*prompt_lines).align(WAlignment.LEFT).emphasize(3) - - answer = input( - f"{dumb}\n\n" - f"{prompt}\n\n" - f"Are you sure you want to proceed? {suffix}: " - ).strip().lower() - - if not answer: - answer = default_answer - - while answer not in ["yes", "no"]: - answer = input("Please type 'yes' or 'no' explicitly: ").strip().lower() - - return answer == "yes" - - @classmethod - def run(cls, instance: Instance, project_names: List[str], service_names: List[str], **kwargs) -> None: - - _logger.debug(f"{instance.directory!r}: {project_names!r}, {service_names!r}") - - projects = [ - project - for project in instance.projects - if project.name in project_names - ] - - if not projects: - # run for whole instance - _logger.debug(f"running for instance, kwargs={kwargs}") - cls.run_for_instance(instance, **kwargs) - - elif not service_names: - # run for entire project(s) - for project_name, project in zip(project_names, projects): - if project is None: - _logger.debug(f"running for new project {project_name}, kwargs={kwargs}") - cls.run_for_new_project(instance, project_name, **kwargs) - - else: - if cls.enabled_only and not project.config.enabled: - cls.print_error(f"Can't interact with disabled project {project_name}!") - return - - _logger.debug(f"running for project {project.name}, kwargs={kwargs}") - cls.run_for_project(instance, project, **kwargs) - - else: - # run for some services - project_name = project_names[0] - project = projects[0] - - if project is None: - cls.print_error(f"Project '{project_name}' not in kiwi-scp instance at '{instance.directory}'!") - - else: - if cls.enabled_only and not project.config.enabled: - cls.print_error(f"Can't interact with disabled project {project_name}!") - return - - _logger.debug(f"running for services {service_names} in project {project_name}, kwargs={kwargs}") - cls.run_for_services(instance, project, service_names, **kwargs) - - @classmethod - def run_for_instance(cls, instance: Instance, **kwargs) -> None: - for project in instance.projects: - if cls.enabled_only and not project.config.enabled: - cls.print_header(f"Skipping disabled project {project.name}") - continue - - cls.run_for_project(instance, project, **kwargs) - - @classmethod - def run_for_project(cls, instance: Instance, project: Project, **kwargs) -> None: - service_names = [service.name for service in project.services.content] - cls.run_for_services(instance, project, service_names, **kwargs) - - @classmethod - def run_for_new_project(cls, instance: Instance, project_name: str, **kwargs) -> None: - cls.print_error(f"Project '{project_name}' not in kiwi-scp instance at '{instance.directory}'!") - - @classmethod - def run_for_services(cls, instance: Instance, project: Project, service_names: List[str], **kwargs) -> None: - services = project.services.filter_existing(service_names) - - new_service_names = [ - service_name - for service_name - in service_names - if service_name not in list(services.names) - ] - - cls.run_for_filtered_services(instance, project, services, new_service_names, **kwargs) - - @classmethod - def run_for_filtered_services(cls, instance: Instance, project: Project, services: Services, - new_service_names: List[str], **kwargs) -> None: - raise Exception diff --git a/kiwi_scp/commands/cmd.py b/kiwi_scp/commands/cmd.py new file mode 100644 index 0000000..6163526 --- /dev/null +++ b/kiwi_scp/commands/cmd.py @@ -0,0 +1,184 @@ +import logging +import sys +from enum import Enum, auto +from typing import TypeVar, Iterable, Type, Optional, List + +import click + +from kiwi_scp.instance import Instance +from kiwi_scp.project import Project +from kiwi_scp.services import Services +from kiwi_scp.wstring import WParagraph, WAlignment + +_logger = logging.getLogger(__name__) + + +class KiwiCommandType(Enum): + INSTANCE = auto() + PROJECT = auto() + PROJECTS = auto() + SERVICES = auto() + + +T = TypeVar("T") + + +class KiwiCommand: + type: KiwiCommandType = KiwiCommandType.SERVICES + enabled_only: bool = False + + @staticmethod + def print_header(header: str) -> None: + click.secho(header, fg="green", bold=True) + + @staticmethod + def print_error(error: str) -> None: + click.secho(error, file=sys.stderr, fg="red", bold=True) + + @staticmethod + def print_list(content: Iterable[str]) -> None: + for item in content: + click.echo(click.style(" - ", fg="green") + click.style(item, fg="blue")) + + @staticmethod + def user_query(description: str, default: T, cast_to: Type[T] = str) -> T: + # prompt user as per argument + while True: + try: + prompt = \ + click.style(f"Enter {description} [", fg="green") + \ + click.style(default, fg="blue") + \ + click.style("] ", fg="green") + str_value = input(prompt).strip() + if str_value: + return cast_to(str_value) + else: + return default + + except EOFError: + click.echo("Input aborted.") + return default + + except Exception as e: + click.echo(f"Invalid input: {e}") + + @staticmethod + def danger_confirm(*prompt_lines: str, default: Optional[bool] = None) -> bool: + if default is True: + suffix = "[YES|no]" + default_answer = "yes" + + elif default is False: + suffix = "[yes|NO]" + default_answer = "no" + + else: + suffix = "[yes|no]" + default_answer = None + + dumb = WParagraph.from_strings( + click.style("WARNING", bold=True, underline=True, blink=True, fg="red"), + click.style("ここにゴミ", fg="cyan"), + click.style("を捨てないで下さい", fg="cyan"), + click.style("DO NOT DUMB HERE", fg="yellow"), + click.style("NO DUMB AREA", fg="yellow"), + ).align(WAlignment.CENTER).surround("!") + + prompt = WParagraph.from_strings(*prompt_lines).align(WAlignment.LEFT).emphasize(3) + + answer = input( + f"{dumb}\n\n" + f"{prompt}\n\n" + f"Are you sure you want to proceed? {suffix}: " + ).strip().lower() + + if not answer: + answer = default_answer + + while answer not in ["yes", "no"]: + answer = input("Please type 'yes' or 'no' explicitly: ").strip().lower() + + return answer == "yes" + + @classmethod + def run(cls, instance: Instance, project_names: List[str], service_names: List[str], **kwargs) -> None: + + _logger.debug(f"{instance.directory!r}: {project_names!r}, {service_names!r}") + + projects = [ + project + for project in instance.projects + if project.name in project_names + ] + + if not projects: + # run for whole instance + _logger.debug(f"running for instance, kwargs={kwargs}") + cls.run_for_instance(instance, **kwargs) + + elif not service_names: + # run for entire project(s) + for project_name, project in zip(project_names, projects): + if project is None: + _logger.debug(f"running for new project {project_name}, kwargs={kwargs}") + cls.run_for_new_project(instance, project_name, **kwargs) + + else: + if cls.enabled_only and not project.config.enabled: + cls.print_error(f"Can't interact with disabled project {project_name}!") + return + + _logger.debug(f"running for project {project.name}, kwargs={kwargs}") + cls.run_for_project(instance, project, **kwargs) + + else: + # run for some services + project_name = project_names[0] + project = projects[0] + + if project is None: + cls.print_error(f"Project '{project_name}' not in kiwi-scp instance at '{instance.directory}'!") + + else: + if cls.enabled_only and not project.config.enabled: + cls.print_error(f"Can't interact with disabled project {project_name}!") + return + + _logger.debug(f"running for services {service_names} in project {project_name}, kwargs={kwargs}") + cls.run_for_services(instance, project, service_names, **kwargs) + + @classmethod + def run_for_instance(cls, instance: Instance, **kwargs) -> None: + for project in instance.projects: + if cls.enabled_only and not project.config.enabled: + cls.print_header(f"Skipping disabled project {project.name}") + continue + + cls.run_for_project(instance, project, **kwargs) + + @classmethod + def run_for_project(cls, instance: Instance, project: Project, **kwargs) -> None: + service_names = [service.name for service in project.services.content] + cls.run_for_services(instance, project, service_names, **kwargs) + + @classmethod + def run_for_new_project(cls, instance: Instance, project_name: str, **kwargs) -> None: + cls.print_error(f"Project '{project_name}' not in kiwi-scp instance at '{instance.directory}'!") + + @classmethod + def run_for_services(cls, instance: Instance, project: Project, service_names: List[str], **kwargs) -> None: + services = project.services.filter_existing(service_names) + + new_service_names = [ + service_name + for service_name + in service_names + if service_name not in list(services.names) + ] + + cls.run_for_filtered_services(instance, project, services, new_service_names, **kwargs) + + @classmethod + def run_for_filtered_services(cls, instance: Instance, project: Project, services: Services, + new_service_names: List[str], **kwargs) -> None: + raise Exception \ No newline at end of file diff --git a/kiwi_scp/commands/cmd_build.py b/kiwi_scp/commands/cmd_build.py index 338f5b7..720632c 100644 --- a/kiwi_scp/commands/cmd_build.py +++ b/kiwi_scp/commands/cmd_build.py @@ -1,6 +1,6 @@ from typing import List -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from ..executable import COMPOSE_EXE from ..instance import Instance diff --git a/kiwi_scp/commands/cmd_cmd.py b/kiwi_scp/commands/cmd_cmd.py index 15cfdfa..8a03692 100644 --- a/kiwi_scp/commands/cmd_cmd.py +++ b/kiwi_scp/commands/cmd_cmd.py @@ -2,7 +2,7 @@ from typing import Tuple import click -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from ..executable import COMPOSE_EXE from ..instance import Instance diff --git a/kiwi_scp/commands/cmd_disable.py b/kiwi_scp/commands/cmd_disable.py index 8b6b2ef..e7ee373 100644 --- a/kiwi_scp/commands/cmd_disable.py +++ b/kiwi_scp/commands/cmd_disable.py @@ -1,6 +1,6 @@ import click -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from .._constants import KIWI_CONF_NAME from ..instance import Instance diff --git a/kiwi_scp/commands/cmd_down.py b/kiwi_scp/commands/cmd_down.py index 960559a..7476013 100644 --- a/kiwi_scp/commands/cmd_down.py +++ b/kiwi_scp/commands/cmd_down.py @@ -2,7 +2,7 @@ from typing import List import click -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from ..executable import COMPOSE_EXE from ..instance import Instance diff --git a/kiwi_scp/commands/cmd_enable.py b/kiwi_scp/commands/cmd_enable.py index 6f3676b..54d89be 100644 --- a/kiwi_scp/commands/cmd_enable.py +++ b/kiwi_scp/commands/cmd_enable.py @@ -1,6 +1,6 @@ import click -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from .._constants import KIWI_CONF_NAME from ..instance import Instance diff --git a/kiwi_scp/commands/cmd_init.py b/kiwi_scp/commands/cmd_init.py index ab8ee98..a93d565 100644 --- a/kiwi_scp/commands/cmd_init.py +++ b/kiwi_scp/commands/cmd_init.py @@ -5,7 +5,7 @@ from pathlib import Path import click -from .cli import KiwiCommandType, KiwiCommand +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from .._constants import KIWI_CONF_NAME from ..config import KiwiConfig diff --git a/kiwi_scp/commands/cmd_list.py b/kiwi_scp/commands/cmd_list.py index e07719a..8fc82a4 100644 --- a/kiwi_scp/commands/cmd_list.py +++ b/kiwi_scp/commands/cmd_list.py @@ -2,7 +2,7 @@ from typing import List import click -from .cli import KiwiCommandType, KiwiCommand +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from ..instance import Instance from ..project import Project diff --git a/kiwi_scp/commands/cmd_logs.py b/kiwi_scp/commands/cmd_logs.py index 581c966..d7669a1 100644 --- a/kiwi_scp/commands/cmd_logs.py +++ b/kiwi_scp/commands/cmd_logs.py @@ -2,7 +2,7 @@ from typing import List import click -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from ..executable import COMPOSE_EXE from ..instance import Instance diff --git a/kiwi_scp/commands/cmd_up.py b/kiwi_scp/commands/cmd_up.py index 8764953..7c6a777 100644 --- a/kiwi_scp/commands/cmd_up.py +++ b/kiwi_scp/commands/cmd_up.py @@ -2,7 +2,7 @@ from typing import List import click -from .cli import KiwiCommand, KiwiCommandType +from .cmd import KiwiCommandType, KiwiCommand from .decorators import kiwi_command from ..executable import COMPOSE_EXE from ..instance import Instance diff --git a/kiwi_scp/commands/decorators.py b/kiwi_scp/commands/decorators.py index f8b9ca7..7b28fc9 100644 --- a/kiwi_scp/commands/decorators.py +++ b/kiwi_scp/commands/decorators.py @@ -2,7 +2,7 @@ from typing import Callable, Type, Optional, Tuple import click -from .cli import KiwiCommandType, KiwiCommand +from .cmd import KiwiCommandType, KiwiCommand from ..instance import Instance _pass_instance = click.make_pass_decorator(