From 2e37291a68eb57bdd63afd23b3aa3fa7cf05c272 Mon Sep 17 00:00:00 2001 From: ldericher <40151420+ldericher@users.noreply.github.com> Date: Sat, 6 Nov 2021 03:45:27 +0100 Subject: [PATCH] KiwiCommand API --- kiwi_scp/commands/cli.py | 32 +++++++++++++-------------- kiwi_scp/commands/cmd_list.py | 38 +++++++++++++-------------------- kiwi_scp/commands/decorators.py | 32 ++++++++++++++++++--------- kiwi_scp/instance.py | 31 ++++++++++++++++----------- 4 files changed, 71 insertions(+), 62 deletions(-) diff --git a/kiwi_scp/commands/cli.py b/kiwi_scp/commands/cli.py index 6f519ae..84ebbd1 100644 --- a/kiwi_scp/commands/cli.py +++ b/kiwi_scp/commands/cli.py @@ -5,7 +5,7 @@ from typing import List, Tuple, Iterable, Any, Type import click -from ..instance import Instance +from ..instance import Instance, Project, Services class KiwiCLI(click.MultiCommand): @@ -42,8 +42,8 @@ class KiwiCommand: click.secho(header, fg="green", bold=True) @staticmethod - def print_error(header: str): - click.secho(header, file=sys.stderr, fg="red", bold=True) + def print_error(error: str): + click.secho(error, file=sys.stderr, fg="red", bold=True) @staticmethod def print_list(content: Iterable[str]): @@ -77,24 +77,22 @@ class KiwiCommand: @classmethod def run_for_instance(cls, instance: Instance, **kwargs) -> None: - for project in instance.config.projects: - cls.run_for_project(instance, project.name, **kwargs) + for project_config in instance.config.projects: + project = instance.get_project(project_config.name) + cls.run_for_existing_project(instance, project, **kwargs) @classmethod - def run_for_project(cls, instance: Instance, project_name: str, **kwargs) -> None: - project = instance.get_project(project_name) - - if project is None: - click.secho(f"No project '{project_name}' in kiwi-scp instance at '{instance.directory}'.", fg="red", bold=True) - return - - service_names = [service.name for service in project.get_services().content] - - cls.run_for_services(instance, project_name, service_names, **kwargs) + def run_for_new_project(cls, instance: Instance, project_name: str, **kwargs) -> None: + raise Exception @classmethod - def run_for_services(cls, instance: Instance, project_name: str, service_names: List[str], **kwargs) -> None: - pass + def run_for_existing_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_services(cls, instance: Instance, project: Project, service_names: List[str], **kwargs) -> None: + raise Exception class KiwiCommandType(Enum): diff --git a/kiwi_scp/commands/cmd_list.py b/kiwi_scp/commands/cmd_list.py index af9211b..ac6b420 100644 --- a/kiwi_scp/commands/cmd_list.py +++ b/kiwi_scp/commands/cmd_list.py @@ -4,7 +4,7 @@ import click from .cli import KiwiCommandType, KiwiCommand from .decorators import kiwi_command -from ..instance import Instance +from ..instance import Instance, Project @click.option( @@ -34,37 +34,29 @@ class CMD(KiwiCommand): ) @classmethod - def run_for_project(cls, instance: Instance, project_name: str, show: bool = None, **kwargs) -> None: - project = instance.get_project(project_name) - - if project is None: - KiwiCommand.print_error(f"No project '{project_name}' in kiwi-scp instance at '{instance.directory}'.") - return - - services = project.get_services() + def run_for_existing_project(cls, instance: Instance, project: Project, show: bool = None, **kwargs) -> None: if show: - KiwiCommand.print_header(f"Showing config for all services in project '{project_name}'.") - click.echo_via_pager(str(services)) + KiwiCommand.print_header(f"Showing config for all services in project '{project.name}'.") + click.echo_via_pager(str(project.services)) else: - KiwiCommand.print_header(f"Services in project '{project_name}':") - KiwiCommand.print_list(service.name for service in services.content) + KiwiCommand.print_header(f"Services in project '{project.name}':") + KiwiCommand.print_list(service.name for service in project.services.content) @classmethod - def run_for_services(cls, instance: Instance, project_name: str, service_names: List[str], show: bool = None, + def run_for_new_project(cls, instance: Instance, project_name: str, **kwargs) -> None: + KiwiCommand.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], show: bool = None, **kwargs) -> None: - project = instance.get_project(project_name) - - if project is None: - KiwiCommand.print_error(f"No project '{project_name}' in kiwi-scp instance at '{instance.directory}'.") - return - - services = project.get_services(service_names) + services = project.services.filter_existing(service_names) if show: + service_names = [service.name for service in services.content] KiwiCommand.print_header( - f"Showing config for services '{', '.join(service_names)}' in project '{project_name}'.") + f"Showing config for matching services '{', '.join(service_names)}' in project '{project.name}'.") click.echo_via_pager(str(services)) else: - KiwiCommand.print_header(f"Matching services in project '{project_name}':") + KiwiCommand.print_header(f"Matching services in project '{project.name}':") KiwiCommand.print_list(service.name for service in services.content) diff --git a/kiwi_scp/commands/decorators.py b/kiwi_scp/commands/decorators.py index 3ccaed6..c432779 100644 --- a/kiwi_scp/commands/decorators.py +++ b/kiwi_scp/commands/decorators.py @@ -12,13 +12,14 @@ _pass_instance = click.make_pass_decorator( ) _project_arg = click.argument( - "project", + "project_name", + metavar="[PROJECT]", required=False, type=str, ) _services_arg = click.argument( - "services", + "service_names", metavar="[SERVICE]...", nargs=-1, type=str, @@ -40,24 +41,35 @@ def kiwi_command( **decorator_kwargs, ) @_pass_instance - def cmd(ctx: Instance, project: Optional[str] = None, services: Optional[Tuple[str]] = None, + def cmd(ctx: Instance, project_name: Optional[str] = None, service_names: Optional[Tuple[str]] = None, **kwargs) -> None: - _logger.debug(f"{ctx.directory!r}: {project!r}, {services!r}") - if project is None: + _logger.debug(f"{ctx.directory!r}: {project_name!r}, {service_names!r}") + if project_name is None: # run for whole instance _logger.debug(f"running for instance, kwargs={kwargs}") command_cls.run_for_instance(ctx, **kwargs) - elif not services: + elif not service_names: # run for one entire project - _logger.debug(f"running for project {project}, kwargs={kwargs}") - command_cls.run_for_project(ctx, project, **kwargs) + project = ctx.get_project(project_name) + if project is not None: + _logger.debug(f"running for existing project {project}, kwargs={kwargs}") + command_cls.run_for_existing_project(ctx, project, **kwargs) + + else: + _logger.debug(f"running for new project {project_name}, kwargs={kwargs}") + command_cls.run_for_new_project(ctx, project_name, **kwargs) else: # run for some services - _logger.debug(f"running for services {services} in project {project}, kwargs={kwargs}") - command_cls.run_for_services(ctx, project, list(services), **kwargs) + project = ctx.get_project(project_name) + if project is not None: + _logger.debug(f"running for services {service_names} in project {project}, kwargs={kwargs}") + command_cls.run_for_services(ctx, project, list(service_names), **kwargs) + + else: + KiwiCommand.print_error(f"Project '{project_name}' not in kiwi-scp instance at '{ctx.directory}'!") if command_type is KiwiCommandType.PROJECT: cmd = _project_arg(cmd) diff --git a/kiwi_scp/instance.py b/kiwi_scp/instance.py index 5927f80..a3b2189 100644 --- a/kiwi_scp/instance.py +++ b/kiwi_scp/instance.py @@ -43,6 +43,16 @@ class Services: } }).strip() + def __bool__(self) -> bool: + return bool(self.content) + + def filter_existing(self, service_names: List[str]): + return Services([ + service + for service in self.content + if service.name in service_names + ]) + @attr.s class Project: @@ -54,21 +64,18 @@ class Project: with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf: return YAML().load(cf) - def get_services(self, service_names: Optional[List[str]] = None) -> Services: + @property + def name(self) -> str: + return self.directory.name + + @property + def services(self) -> Services: yml = Project._parse_compose_file(self.directory) - services = [ + + return Services([ Service(name, description) for name, description in yml["services"].items() - ] - - if not service_names: - return Services(services) - else: - return Services([ - service - for service in services - if service.name in service_names - ]) + ]) @attr.s