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

101 lines
2.8 KiB
Python

import sys
from dataclasses import dataclass
from cli.core import (
DEFAULT_CORE_SERVICES,
CliApplicationBuilder,
CompletionDispatcher,
ProjectRuntimeLocator,
)
@dataclass(frozen=True)
class CliImportArgvScope:
"""
CLI 导入期参数作用域。
该对象负责在根应用构建阶段暂时切换 `sys.argv`,只保留导入期
需要的最小参数集,避免该过程继续以内联 `try/finally` 形式散落
在入口运行器中。
:param project_runtime_locator: CLI 项目运行时定位器
"""
project_runtime_locator: ProjectRuntimeLocator
def run(self, callback: object) -> object:
"""
在导入期参数作用域内执行回调。
:param callback: 待执行回调
:return: 回调执行结果
"""
original_argv = list(sys.argv)
try:
sys.argv = self.project_runtime_locator.extract_import_argv(original_argv)
return callback()
finally:
sys.argv = original_argv
@dataclass(frozen=True)
class CliMainRunner:
"""
CLI 根入口运行器。
该运行器负责串联项目目录定位、导入期参数裁剪、根应用构建、
completion 分发与 Typer 应用启动,避免 `main.py` 继续停留在
模块级散乱编排状态。
:param project_runtime_locator: CLI 项目运行时定位器
:param completion_dispatcher: shell completion 分发器
:param application_builder: 根应用构建器
"""
project_runtime_locator: ProjectRuntimeLocator
completion_dispatcher: CompletionDispatcher
application_builder: CliApplicationBuilder
import_argv_scope: CliImportArgvScope
def build_cli(self) -> object:
"""
构建 CLI 根应用,并在导入期仅保留最小化参数集。
:return: Typer 根应用
"""
self.project_runtime_locator.ensure_backend_dir_on_sys_path()
return self.import_argv_scope.run(self.application_builder.build)
def run(self) -> None:
"""
执行 Typer CLI 根应用。
:return: None
"""
cli = self.build_cli()
self.completion_dispatcher.dispatch(cli)
cli(prog_name='shierfeng')
CLI_APPLICATION_BUILDER = CliApplicationBuilder(output_renderer=DEFAULT_CORE_SERVICES.output_renderer)
PROJECT_RUNTIME_LOCATOR = ProjectRuntimeLocator()
CLI_MAIN_RUNNER = CliMainRunner(
project_runtime_locator=PROJECT_RUNTIME_LOCATOR,
completion_dispatcher=CompletionDispatcher(),
application_builder=CLI_APPLICATION_BUILDER,
import_argv_scope=CliImportArgvScope(project_runtime_locator=PROJECT_RUNTIME_LOCATOR),
)
def main() -> None:
"""
执行 CLI 根入口运行器。
:return: None
"""
CLI_MAIN_RUNNER.run()
if __name__ == '__main__':
main()