KiwiCommand API

This commit is contained in:
Jörn-Michael Miehe 2021-11-06 03:45:27 +01:00
parent 52f0e9b8a3
commit 2e37291a68
4 changed files with 71 additions and 62 deletions

View file

@ -5,7 +5,7 @@ from typing import List, Tuple, Iterable, Any, Type
import click import click
from ..instance import Instance from ..instance import Instance, Project, Services
class KiwiCLI(click.MultiCommand): class KiwiCLI(click.MultiCommand):
@ -42,8 +42,8 @@ class KiwiCommand:
click.secho(header, fg="green", bold=True) click.secho(header, fg="green", bold=True)
@staticmethod @staticmethod
def print_error(header: str): def print_error(error: str):
click.secho(header, file=sys.stderr, fg="red", bold=True) click.secho(error, file=sys.stderr, fg="red", bold=True)
@staticmethod @staticmethod
def print_list(content: Iterable[str]): def print_list(content: Iterable[str]):
@ -77,24 +77,22 @@ class KiwiCommand:
@classmethod @classmethod
def run_for_instance(cls, instance: Instance, **kwargs) -> None: def run_for_instance(cls, instance: Instance, **kwargs) -> None:
for project in instance.config.projects: for project_config in instance.config.projects:
cls.run_for_project(instance, project.name, **kwargs) project = instance.get_project(project_config.name)
cls.run_for_existing_project(instance, project, **kwargs)
@classmethod @classmethod
def run_for_project(cls, instance: Instance, project_name: str, **kwargs) -> None: def run_for_new_project(cls, instance: Instance, project_name: str, **kwargs) -> None:
project = instance.get_project(project_name) raise Exception
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)
@classmethod @classmethod
def run_for_services(cls, instance: Instance, project_name: str, service_names: List[str], **kwargs) -> None: def run_for_existing_project(cls, instance: Instance, project: Project, **kwargs) -> None:
pass 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): class KiwiCommandType(Enum):

View file

@ -4,7 +4,7 @@ import click
from .cli import KiwiCommandType, KiwiCommand from .cli import KiwiCommandType, KiwiCommand
from .decorators import kiwi_command from .decorators import kiwi_command
from ..instance import Instance from ..instance import Instance, Project
@click.option( @click.option(
@ -34,37 +34,29 @@ class CMD(KiwiCommand):
) )
@classmethod @classmethod
def run_for_project(cls, instance: Instance, project_name: str, show: bool = None, **kwargs) -> None: def run_for_existing_project(cls, instance: Instance, project: Project, 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()
if show: if show:
KiwiCommand.print_header(f"Showing config for all services in project '{project_name}'.") KiwiCommand.print_header(f"Showing config for all services in project '{project.name}'.")
click.echo_via_pager(str(services)) click.echo_via_pager(str(project.services))
else: else:
KiwiCommand.print_header(f"Services in project '{project_name}':") KiwiCommand.print_header(f"Services in project '{project.name}':")
KiwiCommand.print_list(service.name for service in services.content) KiwiCommand.print_list(service.name for service in project.services.content)
@classmethod @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: **kwargs) -> None:
project = instance.get_project(project_name) services = project.services.filter_existing(service_names)
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)
if show: if show:
service_names = [service.name for service in services.content]
KiwiCommand.print_header( 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)) click.echo_via_pager(str(services))
else: 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) KiwiCommand.print_list(service.name for service in services.content)

View file

@ -12,13 +12,14 @@ _pass_instance = click.make_pass_decorator(
) )
_project_arg = click.argument( _project_arg = click.argument(
"project", "project_name",
metavar="[PROJECT]",
required=False, required=False,
type=str, type=str,
) )
_services_arg = click.argument( _services_arg = click.argument(
"services", "service_names",
metavar="[SERVICE]...", metavar="[SERVICE]...",
nargs=-1, nargs=-1,
type=str, type=str,
@ -40,24 +41,35 @@ def kiwi_command(
**decorator_kwargs, **decorator_kwargs,
) )
@_pass_instance @_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: **kwargs) -> None:
_logger.debug(f"{ctx.directory!r}: {project!r}, {services!r}") _logger.debug(f"{ctx.directory!r}: {project_name!r}, {service_names!r}")
if project is None: if project_name is None:
# run for whole instance # run for whole instance
_logger.debug(f"running for instance, kwargs={kwargs}") _logger.debug(f"running for instance, kwargs={kwargs}")
command_cls.run_for_instance(ctx, **kwargs) command_cls.run_for_instance(ctx, **kwargs)
elif not services: elif not service_names:
# run for one entire project # run for one entire project
_logger.debug(f"running for project {project}, kwargs={kwargs}") project = ctx.get_project(project_name)
command_cls.run_for_project(ctx, project, **kwargs) 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: else:
# run for some services # run for some services
_logger.debug(f"running for services {services} in project {project}, kwargs={kwargs}") project = ctx.get_project(project_name)
command_cls.run_for_services(ctx, project, list(services), **kwargs) 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: if command_type is KiwiCommandType.PROJECT:
cmd = _project_arg(cmd) cmd = _project_arg(cmd)

View file

@ -43,6 +43,16 @@ class Services:
} }
}).strip() }).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 @attr.s
class Project: class Project:
@ -54,21 +64,18 @@ class Project:
with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf: with open(directory.joinpath(COMPOSE_FILE_NAME), "r") as cf:
return YAML().load(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) yml = Project._parse_compose_file(self.directory)
services = [
return Services([
Service(name, description) Service(name, description)
for name, description in yml["services"].items() 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 @attr.s