mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
refactor: 推进后端分层架构治理
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
"""生成并校验 ``app.schemas`` 根入口的惰性导出清单。"""
|
||||
|
||||
import argparse
|
||||
import importlib
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
OUTPUT_PATH = PROJECT_ROOT / "app" / "schemas" / "exports.py"
|
||||
SCHEMA_MODULES = (
|
||||
"agent",
|
||||
"cache",
|
||||
"category",
|
||||
"common",
|
||||
"context",
|
||||
"dashboard",
|
||||
"download",
|
||||
"event",
|
||||
"exception",
|
||||
"file",
|
||||
"history",
|
||||
"llm",
|
||||
"mediaserver",
|
||||
"message",
|
||||
"mfa",
|
||||
"music",
|
||||
"monitoring",
|
||||
"notification",
|
||||
"plugin",
|
||||
"response",
|
||||
"rule",
|
||||
"search",
|
||||
"storage",
|
||||
"openai",
|
||||
"servarr",
|
||||
"servcookie",
|
||||
"site",
|
||||
"subscribe",
|
||||
"system",
|
||||
"tmdb",
|
||||
"token",
|
||||
"transfer",
|
||||
"user",
|
||||
"workflow",
|
||||
"mcp",
|
||||
)
|
||||
|
||||
|
||||
def collect_exports() -> tuple[dict[str, tuple[str, str]], dict[str, list[str]]]:
|
||||
"""按旧星号导入顺序收集最终导出所有者和重名来源。"""
|
||||
exports: dict[str, tuple[str, str]] = {}
|
||||
sources: dict[str, list[str]] = {}
|
||||
for module_basename in SCHEMA_MODULES:
|
||||
module_name = f"app.schemas.{module_basename}"
|
||||
module = importlib.import_module(module_name)
|
||||
names = getattr(module, "__all__", None)
|
||||
if names is None:
|
||||
names = [name for name in vars(module) if not name.startswith("_")]
|
||||
for name in names:
|
||||
if not hasattr(module, name):
|
||||
continue
|
||||
exports[name] = (module_name, name)
|
||||
sources.setdefault(name, []).append(module_name)
|
||||
conflicts = {
|
||||
name: module_names
|
||||
for name, module_names in sources.items()
|
||||
if len(set(module_names)) > 1
|
||||
}
|
||||
return dict(sorted(exports.items())), dict(sorted(conflicts.items()))
|
||||
|
||||
|
||||
def render_manifest() -> str:
|
||||
"""把导出与冲突清单渲染为稳定、可审查的 Python 模块。"""
|
||||
exports, conflicts = collect_exports()
|
||||
lines = [
|
||||
'"""由 scripts/schema/exports.py 生成,请勿手工编辑。"""',
|
||||
"",
|
||||
"SCHEMA_EXPORTS = {",
|
||||
]
|
||||
lines.extend(
|
||||
f" {name!r}: ({module_name!r}, {symbol_name!r}),"
|
||||
for name, (module_name, symbol_name) in exports.items()
|
||||
)
|
||||
lines.extend(["}", "", "SCHEMA_CONFLICTS = {"])
|
||||
lines.extend(
|
||||
f" {name!r}: {module_names!r},"
|
||||
for name, module_names in conflicts.items()
|
||||
)
|
||||
lines.extend(["}", ""])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""解析写入或校验动作。"""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
action = parser.add_mutually_exclusive_group(required=True)
|
||||
action.add_argument("--write", action="store_true")
|
||||
action.add_argument("--check", action="store_true")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""写入清单,或检查当前 schema 公开面是否发生漂移。"""
|
||||
args = parse_args()
|
||||
rendered = render_manifest()
|
||||
if args.write:
|
||||
OUTPUT_PATH.write_text(rendered, encoding="utf-8")
|
||||
print(f"已写入 {OUTPUT_PATH.relative_to(PROJECT_ROOT)}")
|
||||
return 0
|
||||
current = OUTPUT_PATH.read_text(encoding="utf-8")
|
||||
if current == rendered:
|
||||
return 0
|
||||
print(
|
||||
"schema 导出清单已变化;确认兼容性后运行 "
|
||||
"scripts/schema/exports.py --write",
|
||||
)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user