find-work/find_work/cli/execute.py
Anna “CyberTailor” ae896790e3
*/*: make better use of Pydantic models
This is a big messy commit that extends use of Pydantic for
serialization and deserialization.
2024-04-27 04:29:48 +05:00

73 lines
2.2 KiB
Python

# SPDX-License-Identifier: WTFPL
# SPDX-FileCopyrightText: 2024 Anna <cyber@sysrq.in>
# No warranty
""" CLI subcommand for executing custom aliases. """
from collections.abc import Callable
from importlib import import_module
from typing import Any
import click
from click_aliases import ClickAliasedGroup
from find_work.cli import Options
from find_work.config import ConfigAlias, ConfigModuleOption, load_config
from find_work.types._config import CliOptionKind
def _new_click_option(opt: ConfigModuleOption) -> Callable:
def callback(ctx: click.Context, param: str, value: Any) -> None:
options: Options = ctx.obj
options[opt.module][opt.name] = value
is_flag: bool = False
match opt.kind:
case CliOptionKind.OPTION:
is_flag = False
case CliOptionKind.FLAG:
is_flag = True
case _:
# dumb wrapper
return lambda f: f
return click.option(*opt.value, callback=callback, is_flag=is_flag)
def _callback_from_config(alias: ConfigAlias) -> Callable:
@click.pass_context
def callback(ctx: click.Context, **kwargs: Any) -> None:
cmd_module, cmd_function = alias.command.rsplit(".", maxsplit=1)
cmd_group = cmd_module.rsplit(".", maxsplit=1)[-1]
cmd_obj = getattr(import_module(cmd_module), cmd_function)
options: Options = ctx.obj
for opt in alias.options:
# cli options are processed in their own callbacks
if opt.kind == CliOptionKind.SIMPLE:
options[opt.module][opt.name] = opt.value
options.cache_key.feed(cmd_group)
for key in options[cmd_group].cache_order:
options.cache_key.feed_option(key, options[cmd_group][key])
ctx.invoke(cmd_obj)
for opt in alias.options:
callback = _new_click_option(opt)(callback)
callback.__name__ = alias.name
callback.__doc__ = alias.description
return callback
def load_aliases(group: ClickAliasedGroup) -> None:
"""
Load custom aliases from configuration files.
:param group: click group for new commands
"""
for alias in load_config().aliases:
group.command(aliases=alias.shortcuts)(_callback_from_config(alias))