modify: 0.3.4
This commit is contained in:
@@ -36,6 +36,10 @@ uv run gen_models workers/myplugin/config/workers/myplugin workers/myplugin/work
|
||||
- `--encrypt`:打开加密与混淆 —— `.mbank` 加密存字节码并写 `.key` 密钥文件、做 PyArmor 混淆
|
||||
- `--license`:打开授权 —— 注入厂商授权公钥(缺公钥则构建失败)、跑授权私钥泄漏守卫
|
||||
|
||||
打包收集清单分两处:网关本体依赖在根 `config.toml` `[pyinstaller_build_import]`;
|
||||
内置插件专属依赖(网关本体不 import、只在插件里用)在根目录 `plugins_deps.toml`
|
||||
(按插件分节,可选文件),`pack` 时自动并入 `--hidden-import` / `--include-module`。
|
||||
|
||||
## 项目根目录定位
|
||||
|
||||
脚本需要在项目根目录下读写 `config/`、`src/plugins/`、`workers/` 等路径。
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ requires = ["hatchling"]
|
||||
|
||||
[project]
|
||||
name = "chongming-cli"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
description = "chongming 命令脚本集合:构建打包 / 进程插件打包 / 插件脚手架 / 模型生成 / 机器码授权签发"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
+82
-10
@@ -35,6 +35,13 @@
|
||||
uv run build nuitka --only mbank,prepare
|
||||
uv run build --encrypt --license # 对外分发:加密模块 + 注入授权公钥
|
||||
uv run build # 内部调试:明文模块、不带授权
|
||||
|
||||
依赖收集(--only pack 生效):
|
||||
打包收集清单 = 根 config.toml [pyinstaller_build_import](网关本体依赖)
|
||||
+ 根目录 plugins_deps.toml(内置插件专属依赖 —— 网关本体不 import、只在
|
||||
mbank 内 import 的包,按插件分节声明;文件可选)。
|
||||
mbank 里的 import 静态分析看不到,两条清单都会被展开为 --hidden-import /
|
||||
--include-module,缺一个都会在运行期加载插件时才 ImportError。
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -45,6 +52,7 @@ import subprocess
|
||||
import sys
|
||||
import asyncio
|
||||
import time
|
||||
import tomllib
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
@@ -54,6 +62,8 @@ from sqlite_vfs.core import SQLiteVFS
|
||||
from sqlite_vfs.folder_packer import FolderPacker
|
||||
from chongming_config import get_config, Config
|
||||
|
||||
from ._root import find_project_root
|
||||
|
||||
# ── 常量 ────────────────────────────────────────────────────────────────────
|
||||
|
||||
PYINSTALLER = "pyinstaller"
|
||||
@@ -65,6 +75,12 @@ STEPS = ("mbank", "prepare", "obfuscate", "pack", "clean", "license_guard", "vue
|
||||
|
||||
is_windows = platform.system() == "Windows"
|
||||
|
||||
# 插件专属依赖清单(项目根,可选文件):内置插件(src/plugins/*)专属、网关本体
|
||||
# (src/chongming/)不 import 的第三方依赖,按插件分节声明。放在插件自己的清单里
|
||||
# 而不是 config.toml [pyinstaller_build_import],避免插件依赖混进网关构建配置:
|
||||
# 插件下线/改 external 进程插件时删掉对应节即可,网关配置不受影响。
|
||||
PLUGIN_DEPS_FILE = "plugins_deps.toml"
|
||||
|
||||
# ── 构建结果数据结构 ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -517,16 +533,73 @@ def _stage_pyarmor_obfuscate() -> str:
|
||||
return "✅ 所有文件混淆成功"
|
||||
|
||||
|
||||
# ── 打包收集清单(网关本体依赖 + 插件专属依赖) ─────────────────────────────
|
||||
|
||||
|
||||
def _load_plugin_imports() -> tuple[list[str], str]:
|
||||
"""读取插件专属依赖清单(项目根 plugins_deps.toml,可选),返回 (模块列表, 摘要)。
|
||||
|
||||
文件结构(节名 = src/plugins/ 下的插件名):
|
||||
|
||||
imports = ["httpx"] # 多个插件共用的插件专属依赖
|
||||
[doubao]
|
||||
imports = ["openai", ...] # 单插件专属
|
||||
|
||||
文件不存在 = 无插件专属依赖(其他项目复用本 CLI 时不受影响),返回 ([], "")。
|
||||
配置写错(imports 不是字符串列表、顶层出现非表非 imports 的键)直接抛错:
|
||||
漏收依赖打包期不报错、运行期加载插件才 ImportError,静默放过的排查成本高得多。
|
||||
"""
|
||||
path = find_project_root() / PLUGIN_DEPS_FILE
|
||||
if not path.exists():
|
||||
return [], ""
|
||||
|
||||
with open(path, "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
|
||||
modules: list[str] = []
|
||||
notes: list[str] = []
|
||||
|
||||
def collect(section: str, entry) -> None:
|
||||
if not isinstance(entry, list) or not all(isinstance(m, str) for m in entry):
|
||||
raise ValueError(
|
||||
f"{PLUGIN_DEPS_FILE} 的 [{section}] imports 必须是字符串列表"
|
||||
)
|
||||
modules.extend(entry)
|
||||
if entry:
|
||||
notes.append(f"{section}:{len(entry)}")
|
||||
|
||||
for name, value in data.items():
|
||||
if name == "imports":
|
||||
collect("共用", value)
|
||||
elif isinstance(value, dict):
|
||||
collect(name, value.get("imports"))
|
||||
else:
|
||||
raise ValueError(
|
||||
f"{PLUGIN_DEPS_FILE} 顶层 [{name}] 只能是共用 imports 列表或 [插件名] 表"
|
||||
)
|
||||
return modules, "、".join(notes)
|
||||
|
||||
|
||||
def _collect_build_imports(config: Config) -> tuple[list[str], str]:
|
||||
"""打包收集清单 = 网关本体依赖(config.toml)+ 插件专属依赖(plugins_deps.toml)。
|
||||
|
||||
去重且保持顺序(网关本体在前);摘要空串 = 未声明插件专属依赖。
|
||||
"""
|
||||
base = config.get("pyinstaller_build_import", {})
|
||||
items = list(base.get("base", []))
|
||||
items.extend(base.get("windows", []) if is_windows else base.get("linux", []))
|
||||
plugin_items, summary = _load_plugin_imports()
|
||||
return list(dict.fromkeys([*items, *plugin_items])), summary
|
||||
|
||||
|
||||
# ── 阶段 4: PyInstaller 打包 ────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _stage_pyinstaller(config: Config) -> tuple[str, str]:
|
||||
"""执行 PyInstaller 打包,返回 (状态消息, 可执行文件路径)"""
|
||||
base_imports = config.get("pyinstaller_build_import", {})
|
||||
build_imports = list(base_imports.get("base", []))
|
||||
build_imports.extend(
|
||||
base_imports.get("windows", []) if is_windows else base_imports.get("linux", [])
|
||||
)
|
||||
build_imports, plugin_summary = _collect_build_imports(config)
|
||||
if plugin_summary:
|
||||
print(f" 📎 并入插件专属依赖 {PLUGIN_DEPS_FILE}({plugin_summary})")
|
||||
|
||||
icon = Path("../../public/chongming.ico")
|
||||
cmd = [
|
||||
@@ -581,10 +654,9 @@ def _stage_pyinstaller(config: Config) -> tuple[str, str]:
|
||||
|
||||
def _stage_nuitka(config: Config) -> tuple[str, str]:
|
||||
"""执行 Nuitka 打包,返回 (状态消息, 可执行文件路径)"""
|
||||
base_imports = config.get("pyinstaller_build_import", {}).get("base", [])
|
||||
extra = config.get("pyinstaller_build_import", {}).get(
|
||||
"windows" if is_windows else "linux", []
|
||||
)
|
||||
build_imports, plugin_summary = _collect_build_imports(config)
|
||||
if plugin_summary:
|
||||
print(f" 📎 并入插件专属依赖 {PLUGIN_DEPS_FILE}({plugin_summary})")
|
||||
|
||||
cmd = [
|
||||
sys.executable,
|
||||
@@ -609,7 +681,7 @@ def _stage_nuitka(config: Config) -> tuple[str, str]:
|
||||
if shutil.which("upx"):
|
||||
cmd.append("--enable-plugin=upx")
|
||||
|
||||
for mod in list(base_imports) + extra:
|
||||
for mod in build_imports:
|
||||
cmd.append(f"--include-module={mod}")
|
||||
|
||||
if is_windows:
|
||||
|
||||
Reference in New Issue
Block a user