diff --git a/doxy/cli.py b/doxy/cli.py index 9066c96..1244863 100644 --- a/doxy/cli.py +++ b/doxy/cli.py @@ -3,6 +3,7 @@ from pathlib import Path import click from rich import print +from rich.rule import Rule from rich.tree import Tree from doxy import services @@ -25,6 +26,7 @@ def main(ctx): @click.command() def list(): + print(Rule(f"Listing services")) tree = Tree("[bold]Available Services") for service in services.find_services(Path(CONFIG.root_directory)): tree.add(service) @@ -42,15 +44,13 @@ def complete_service_name(ctx, param, incomplete): @click.command() @click.argument("service", nargs=1, shell_complete=complete_service_name) @click.pass_context +@services.only_if_service_exists def edit(ctx, service): - try: - compose_file = services.get_compose_file( - Path(ctx.obj["CONFIG"].root_directory) / service - ) - click.edit(filename=Path(compose_file)) - except FileNotFoundError: - click.echo(f"Service `{service}' not found", sys.stderr) - ctx.abort() + print(Rule(f"Editing {service}")) + compose_file = services.get_compose_file( + Path(ctx.obj["CONFIG"].root_directory) / service + ) + click.edit(filename=Path(compose_file)) @click.command( @@ -61,17 +61,43 @@ def edit(ctx, service): @click.argument("service", nargs=1, shell_complete=complete_service_name) @click.argument("command", nargs=-1) @click.pass_context +@services.only_if_service_exists def control(ctx, service, command): - try: - compose_file = services.get_compose_file( - Path(ctx.obj["CONFIG"].root_directory) / service - ) - services.docker_compose_command(command, compose_file) - except FileNotFoundError: - click.echo(f"Service `{service}' not found", sys.stderr) - ctx.abort() + print(Rule(f"Controlling {service}")) + compose_file = services.get_compose_file( + Path(ctx.obj["CONFIG"].root_directory) / service + ) + services.docker_compose_command(command, compose_file) + + +@click.command("update", help="pull the latest service images and restart") +@click.argument("service", nargs=1, shell_complete=complete_service_name) +@click.option( + "--remove", "-r", is_flag=True, default=False, help="remove unused volumes" +) +@click.pass_context +@services.only_if_service_exists +def update(ctx, service, remove): + compose_file = services.get_compose_file( + Path(ctx.obj["CONFIG"].root_directory) / service + ) + print(Rule(f"Updating {service}")) + services.docker_compose_command( + [ + ["stop", "down"][remove], + ], + compose_file, + ) + services.docker_compose_command( + [ + "pull", + ], + compose_file, + ) + services.docker_compose_command(["up", "-d"], compose_file) main.add_command(list) main.add_command(edit) main.add_command(control) +main.add_command(update) diff --git a/doxy/services.py b/doxy/services.py index bed762e..6619e20 100644 --- a/doxy/services.py +++ b/doxy/services.py @@ -1,11 +1,31 @@ import glob import subprocess +import sys +from functools import update_wrapper from pathlib import Path from typing import List import click +def only_if_service_exists(fn): + def wrapper(*args, **kwargs): + ctx = args[0] + service = kwargs["service"] + try: + compose_file = get_compose_file( + Path(ctx.obj["CONFIG"].root_directory) / service + ) + if not compose_file.exists(): + raise FileNotFoundError() + except FileNotFoundError: + click.echo(f"Service `{service}' not found", sys.stderr) + ctx.abort() + return ctx.invoke(fn, *args, **kwargs) + + return update_wrapper(wrapper, fn) + + def find_services(root: Path) -> List[str]: return [_.split("/")[0] for _ in glob.glob("*/docker-compose.y*ml", root_dir=root)]