doxy/doxy/cli.py

205 lines
5.9 KiB
Python

import sys
from pathlib import Path
import click
from click_aliases import ClickAliasedGroup
from doxy import output
from doxy.config import Config
from doxy.services import (
disable_compose_file,
docker_compose_command,
enable_compose_file,
find_disabled_services,
find_services,
get_compose_file,
only_if_service_exists,
)
try:
CONFIG = Config()
CONFIG.load()
except FileNotFoundError as exc:
click.echo(exc, sys.stderr)
sys.exit(1)
def complete_service_name(ctx, param, incomplete):
return [
k
for k in find_services(Path(CONFIG.root_directory), False)
+ find_disabled_services(Path(CONFIG.root_directory), False)
if k.startswith(incomplete)
]
@click.group(cls=ClickAliasedGroup)
@click.option(
"--format",
"-f",
type=click.Choice(["fancy", "simple"], case_sensitive=False),
default="fancy",
show_default=True,
help="output formatting",
)
@click.option(
"--service-root",
"-r",
type=click.Path(exists=True, file_okay=False, dir_okay=True),
default=Path(CONFIG.root_directory),
help="Service root directory",
show_default=True,
)
@click.pass_context
def main(ctx, format, service_root):
ctx.ensure_object(dict)
CONFIG.root_directory = service_root
ctx.obj["CONFIG"] = CONFIG
ctx.obj["FORMAT"] = format.lower()
@main.command(
name="get-service-directory", help="get the service root directory", aliases=["dir"]
)
@click.pass_context
def change_dir(ctx):
click.echo(ctx.obj["CONFIG"].root_directory)
@main.command(help="list available services", aliases=["l", "ls"])
@click.option(
"--sub-services",
"-s",
is_flag=True,
default=False,
help="list sub services from compose file",
)
@click.pass_context
def list(ctx, sub_services):
output.print_services(ctx, find_services(Path(CONFIG.root_directory), sub_services))
output.print_services(
ctx, find_disabled_services(Path(CONFIG.root_directory), sub_services), True
)
@main.command(help="edit the compose file")
@click.argument("service", nargs=1, shell_complete=complete_service_name)
@click.pass_context
@only_if_service_exists
def edit(ctx, service):
output.print_header(ctx, f"Editing {service}")
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
click.edit(filename=str(compose_file))
@main.command(help="disable service")
@click.argument("service", nargs=1, shell_complete=complete_service_name)
@click.option(
"--now",
"-n",
is_flag=True,
default=False,
help="shutdown service prior being disabled",
)
@click.pass_context
@only_if_service_exists
def disable(ctx, service, now):
output.print_header(ctx, f"Disable {service}")
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
if now:
docker_compose_command(["down", "--remove-orphans"], compose_file)
disable_compose_file(Path(CONFIG.root_directory) / service)
@main.command(help="enable service")
@click.argument("service", nargs=1, shell_complete=complete_service_name)
@click.option(
"--now",
"-n",
is_flag=True,
default=False,
help="shutdown service prior being disabled",
)
@click.pass_context
@only_if_service_exists
def enable(ctx, service, now):
output.print_header(ctx, f"Disable {service}")
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
enable_compose_file(Path(CONFIG.root_directory) / service)
if now:
docker_compose_command(["up", "-d"], compose_file)
@main.command(
context_settings=dict(
ignore_unknown_options=True,
),
help="run docker-compose commands",
aliases=["c", "ctrl"],
)
@click.argument("service", nargs=1, shell_complete=complete_service_name)
@click.argument("command", nargs=-1)
@click.pass_context
@only_if_service_exists
def control(ctx, service, command):
output.print_header(ctx, f"Controlling {service}")
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
docker_compose_command(command, compose_file)
@main.command("start-all", help="start all services")
@click.pass_context
def start_all(ctx):
for service in find_services(Path(CONFIG.root_directory), False):
output.print_header(ctx, f"Starting {service}")
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
docker_compose_command(["up", "-d"], compose_file)
@main.command(
help="pull the latest service images and restart", aliases=["upd", "sync"]
)
@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
@only_if_service_exists
def update(ctx, service, remove):
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
command_chain = [
(f"Pulling {service} images", ["pull"]),
(f"Starting {service}", ["up", "-d"]),
]
if remove:
command_chain.insert(0, (f"Stopping {service}", ["down", "--remove-orphans"]))
for title, command in command_chain:
output.print_header(ctx, title)
docker_compose_command(command, compose_file)
@main.command(
help="show service status (images, ps, top, logs)", aliases=["stat", "info"]
)
@click.argument("service", nargs=1, shell_complete=complete_service_name)
@click.option(
"--tail",
type=str,
default=10,
show_default=True,
help="Number of lines to show from the end of the logs",
)
@click.pass_context
@only_if_service_exists
def status(ctx, service, tail):
compose_file = get_compose_file(Path(CONFIG.root_directory) / service)
command_chain = [
("Images", ["images"]),
("Containers", ["ps"]),
("Running processes", ["top"]),
("Log Messages", ["logs", "--tail", tail]),
]
for title, command in command_chain:
output.print_header(ctx, title)
docker_compose_command(command, compose_file)