317 lines
12 KiB
Python
317 lines
12 KiB
Python
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()
|