ShiErFeng/shierfeng-fastapi-backend/cli/wizard/commands.py
2026-07-24 09:43:10 +08:00

317 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from collections.abc import Callable
from dataclasses import dataclass, field
from importlib import import_module
import typer
from cli.context import OutputOption
WizardCommandRegistrar = Callable[[typer.Typer, 'WizardCommandRegistration'], None]
@dataclass(frozen=True)
class WizardCommandRegistration:
"""
wizard 子命令注册元数据。
:param name: 子命令名称
:param help_text: 子命令帮助文案
:param registrar: 对应的注册器函数
"""
name: str
help_text: str
class WizardFlowLoader:
"""
wizard flow 惰性加载器。
该对象负责在命令真正执行时导入对应 flow
避免 `wizard` 入口在模块导入阶段提前拉起全部向导依赖。
"""
def load_runner(self, module_name: str, function_name: str) -> Callable[..., None]:
"""
按模块名和函数名加载向导执行入口。
:param module_name: flow 模块名
:param function_name: flow 执行函数名
:return: 可调用的向导执行函数
"""
flow_module = import_module(module_name)
return getattr(flow_module, function_name)
@dataclass
class WizardCommandBuilder:
"""
wizard 子命令构建器。
:param flow_loader: wizard flow 惰性加载器
"""
flow_loader: WizardFlowLoader = field(default_factory=WizardFlowLoader)
def build(self) -> typer.Typer:
"""
构建 wizard 命令组。
:return: wizard 子应用
"""
app = typer.Typer(
help='交互式向导命令',
no_args_is_help=True,
context_settings={'help_option_names': ['-h', '--help']},
)
self.register_commands(app)
return app
def register_commands(self, app: typer.Typer) -> None:
"""
向 Typer 子应用注册全部 wizard 子命令。
:param app: wizard 子应用
:return: None
"""
for registration, registrar in self.iter_command_registrars():
registrar(app, registration)
def iter_command_registrars(self) -> tuple[tuple[WizardCommandRegistration, WizardCommandRegistrar], ...]:
"""
返回向导命令注册元数据与显式注册器映射。
该方法将命令声明与注册函数绑定关系显式化,避免继续依赖
`registrar_name -> getattr(self, ...)` 的字符串分发。
:return: 注册元数据与注册器映射列表
"""
return (
(
WizardCommandRegistration('app-run', '通过交互方式启动应用'),
self._register_app_run_command,
),
(
WizardCommandRegistration('db-upgrade', '通过交互方式执行数据库升级'),
self._register_db_upgrade_command,
),
(
WizardCommandRegistration('cache-clear', '通过交互方式执行缓存清理'),
self._register_cache_clear_command,
),
(
WizardCommandRegistration('gen-export', '通过交互方式执行代码导出'),
self._register_gen_export_command,
),
(
WizardCommandRegistration('gen-import', '通过交互方式执行物理表导入'),
self._register_gen_import_command,
),
(
WizardCommandRegistration('prod-check', '通过交互方式执行生产巡检'),
self._register_prod_check_command,
),
)
def _register_app_run_command(self, app: typer.Typer, registration: WizardCommandRegistration) -> None:
"""
注册 `app-run` 子命令。
:param app: wizard 子应用
:param registration: 子命令注册元数据
:return: None
"""
@app.command(registration.name, help=registration.help_text)
def app_run() -> None:
"""
通过交互方式启动应用。
:return: None
"""
self.flow_loader.load_runner('cli.wizard.flows.app_run', 'run_app_run_wizard')()
def _register_db_upgrade_command(self, app: typer.Typer, registration: WizardCommandRegistration) -> None:
"""
注册 `db-upgrade` 子命令。
:param app: wizard 子应用
:param registration: 子命令注册元数据
:return: None
"""
@app.command(registration.name, help=registration.help_text)
def db_upgrade(
output: OutputOption = 'text',
default_env: str = typer.Option('dev', '--default-env', help='向导默认环境'),
default_revision: str = typer.Option('head', '--default-revision', help='向导默认目标 revision'),
default_dry_run: bool = typer.Option(
True, '--default-dry-run/--no-default-dry-run', help='向导默认 dry-run 选项'
),
) -> None:
"""
通过交互方式执行数据库升级。
:param output: 输出格式
:param default_env: 向导默认环境
:param default_revision: 向导默认目标 revision
:param default_dry_run: 向导默认 dry-run 选项
:return: None
"""
self.flow_loader.load_runner('cli.wizard.flows.db_upgrade', 'run_db_upgrade_wizard')(
output,
default_env=default_env,
default_revision=default_revision,
default_dry_run=default_dry_run,
)
def _register_cache_clear_command(self, app: typer.Typer, registration: WizardCommandRegistration) -> None:
"""
注册 `cache-clear` 子命令。
:param app: wizard 子应用
:param registration: 子命令注册元数据
:return: None
"""
@app.command(registration.name, help=registration.help_text)
def cache_clear(
output: OutputOption = 'text',
default_env: str = typer.Option('dev', '--default-env', help='向导默认环境'),
default_mode: str = typer.Option('cache-name', '--default-mode', help='向导默认清理模式'),
default_cache_name: str = typer.Option('', '--default-cache-name', help='向导默认缓存名称前缀'),
default_cache_key: str = typer.Option('', '--default-cache-key', help='向导默认缓存键关键字'),
default_dry_run: bool = typer.Option(
True, '--default-dry-run/--no-default-dry-run', help='向导默认 dry-run 选项'
),
) -> None:
"""
通过交互方式执行缓存清理。
:param output: 输出格式
:param default_env: 向导默认环境
:param default_mode: 向导默认清理模式
:param default_cache_name: 向导默认缓存名称前缀
:param default_cache_key: 向导默认缓存键关键字
:param default_dry_run: 向导默认 dry-run 选项
:return: None
"""
self.flow_loader.load_runner('cli.wizard.flows.cache_clear', 'run_cache_clear_wizard')(
output,
default_env=default_env,
default_mode=default_mode,
default_cache_name=default_cache_name,
default_cache_key=default_cache_key,
default_dry_run=default_dry_run,
)
def _register_gen_export_command(self, app: typer.Typer, registration: WizardCommandRegistration) -> None:
"""
注册 `gen-export` 子命令。
:param app: wizard 子应用
:param registration: 子命令注册元数据
:return: None
"""
@app.command(registration.name, help=registration.help_text)
def gen_export(
output: OutputOption = 'text',
default_env: str = typer.Option('dev', '--default-env', help='向导默认环境'),
default_table_names: str = typer.Option('', '--default-table-names', help='向导默认业务表名称列表'),
default_mode: str = typer.Option('zip', '--default-mode', help='向导默认导出模式'),
default_output_file: str = typer.Option('', '--default-output-file', help='向导默认导出目标文件路径'),
default_dry_run: bool = typer.Option(
True, '--default-dry-run/--no-default-dry-run', help='向导默认 dry-run 选项'
),
) -> None:
"""
通过交互方式执行代码导出。
:param output: 输出格式
:param default_env: 向导默认环境
:param default_table_names: 向导默认业务表名称列表
:param default_mode: 向导默认导出模式
:param default_output_file: 向导默认导出目标文件路径
:param default_dry_run: 向导默认 dry-run 选项
:return: None
"""
self.flow_loader.load_runner('cli.wizard.flows.gen_export', 'run_gen_export_wizard')(
output,
default_env=default_env,
default_table_names=default_table_names,
default_mode=default_mode,
default_output_file=default_output_file,
default_dry_run=default_dry_run,
)
def _register_gen_import_command(self, app: typer.Typer, registration: WizardCommandRegistration) -> None:
"""
注册 `gen-import` 子命令。
:param app: wizard 子应用
:param registration: 子命令注册元数据
:return: None
"""
@app.command(registration.name, help=registration.help_text)
def gen_import(
output: OutputOption = 'text',
default_env: str = typer.Option('dev', '--default-env', help='向导默认环境'),
default_table_names: str = typer.Option('', '--default-table-names', help='向导默认物理表名称列表'),
default_dry_run: bool = typer.Option(
True, '--default-dry-run/--no-default-dry-run', help='向导默认 dry-run 选项'
),
) -> None:
"""
通过交互方式执行物理表导入。
:param output: 输出格式
:param default_env: 向导默认环境
:param default_table_names: 向导默认物理表名称列表
:param default_dry_run: 向导默认 dry-run 选项
:return: None
"""
self.flow_loader.load_runner('cli.wizard.flows.gen_import', 'run_gen_import_wizard')(
output,
default_env=default_env,
default_table_names=default_table_names,
default_dry_run=default_dry_run,
)
def _register_prod_check_command(self, app: typer.Typer, registration: WizardCommandRegistration) -> None:
"""
注册 `prod-check` 子命令。
:param app: wizard 子应用
:param registration: 子命令注册元数据
:return: None
"""
@app.command(registration.name, help=registration.help_text)
def prod_check(
output: OutputOption = 'text',
default_env: str = typer.Option('prod', '--default-env', help='向导默认环境'),
default_include_config: bool = typer.Option(
True,
'--default-include-config/--no-default-include-config',
help='向导默认是否附带配置快照',
),
) -> None:
"""
通过交互方式执行生产巡检。
:param output: 输出格式
:param default_env: 向导默认环境
:param default_include_config: 向导默认是否附带配置快照
:return: None
"""
self.flow_loader.load_runner('cli.wizard.flows.prod_check', 'run_prod_check_wizard')(
output,
default_env=default_env,
default_include_config=default_include_config,
)
WIZARD_COMMAND_BUILDER = WizardCommandBuilder()