modify: nuitka 支持
This commit is contained in:
+12
-1
@@ -23,10 +23,14 @@ RUN \
|
|||||||
LIB_PATH="/lib/aarch64-linux-gnu"; \
|
LIB_PATH="/lib/aarch64-linux-gnu"; \
|
||||||
LD_LINKER="/lib/ld-linux-aarch64.so.1"; \
|
LD_LINKER="/lib/ld-linux-aarch64.so.1"; \
|
||||||
LD_LINKER_TARGET="/tmp/rootfs/lib/ld-linux-aarch64.so.1"; \
|
LD_LINKER_TARGET="/tmp/rootfs/lib/ld-linux-aarch64.so.1"; \
|
||||||
|
GCC_LIB_PATH="/lib/aarch64-linux-gnu"; \
|
||||||
|
GCC_USR_PATH="/usr/lib/aarch64-linux-gnu"; \
|
||||||
else \
|
else \
|
||||||
LIB_PATH="/lib/x86_64-linux-gnu"; \
|
LIB_PATH="/lib/x86_64-linux-gnu"; \
|
||||||
LD_LINKER="/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"; \
|
LD_LINKER="/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"; \
|
||||||
LD_LINKER_TARGET="/tmp/rootfs/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"; \
|
LD_LINKER_TARGET="/tmp/rootfs/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"; \
|
||||||
|
GCC_LIB_PATH="/lib/x86_64-linux-gnu"; \
|
||||||
|
GCC_USR_PATH="/usr/lib/x86_64-linux-gnu"; \
|
||||||
fi && \
|
fi && \
|
||||||
mkdir -p /tmp/rootfs/app && \
|
mkdir -p /tmp/rootfs/app && \
|
||||||
mkdir -p /tmp/rootfs/tmp && chmod 1777 /tmp/rootfs/tmp && \
|
mkdir -p /tmp/rootfs/tmp && chmod 1777 /tmp/rootfs/tmp && \
|
||||||
@@ -43,7 +47,7 @@ RUN \
|
|||||||
cp ${LIB_PATH}/ld-linux-x86-64.so.2 /tmp/rootfs${LIB_PATH}/ && \
|
cp ${LIB_PATH}/ld-linux-x86-64.so.2 /tmp/rootfs${LIB_PATH}/ && \
|
||||||
ln -s ${LIB_PATH}/ld-linux-x86-64.so.2 /tmp/rootfs/lib64/ld-linux-x86-64.so.2; \
|
ln -s ${LIB_PATH}/ld-linux-x86-64.so.2 /tmp/rootfs/lib64/ld-linux-x86-64.so.2; \
|
||||||
fi && \
|
fi && \
|
||||||
# === 依赖库 ===
|
# === 基础依赖库 ===
|
||||||
mkdir -p /tmp/rootfs${LIB_PATH} && \
|
mkdir -p /tmp/rootfs${LIB_PATH} && \
|
||||||
cp ${LIB_PATH}/libdl.so.2 /tmp/rootfs${LIB_PATH}/ && \
|
cp ${LIB_PATH}/libdl.so.2 /tmp/rootfs${LIB_PATH}/ && \
|
||||||
cp ${LIB_PATH}/libz.so.1 /tmp/rootfs${LIB_PATH}/ && \
|
cp ${LIB_PATH}/libz.so.1 /tmp/rootfs${LIB_PATH}/ && \
|
||||||
@@ -55,6 +59,11 @@ RUN \
|
|||||||
cp ${LIB_PATH}/libnss_dns.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \
|
cp ${LIB_PATH}/libnss_dns.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \
|
||||||
cp ${LIB_PATH}/libnss_files.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \
|
cp ${LIB_PATH}/libnss_files.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \
|
||||||
cp ${LIB_PATH}/libresolv.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \
|
cp ${LIB_PATH}/libresolv.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \
|
||||||
|
# === Nuitka 额外需要的 GCC 运行时库 ===
|
||||||
|
mkdir -p /tmp/rootfs${GCC_LIB_PATH} && \
|
||||||
|
mkdir -p /tmp/rootfs${GCC_USR_PATH} && \
|
||||||
|
cp ${GCC_LIB_PATH}/libgcc_s.so.1 /tmp/rootfs${GCC_LIB_PATH}/ && \
|
||||||
|
cp ${GCC_USR_PATH}/libstdc++.so.6 /tmp/rootfs${GCC_USR_PATH}/ 2>/dev/null || true && \
|
||||||
# === 时区数据 ===
|
# === 时区数据 ===
|
||||||
mkdir -p /tmp/rootfs/usr/share/zoneinfo && \
|
mkdir -p /tmp/rootfs/usr/share/zoneinfo && \
|
||||||
cp -r /usr/share/zoneinfo/Asia /tmp/rootfs/usr/share/zoneinfo/ 2>/dev/null || true && \
|
cp -r /usr/share/zoneinfo/Asia /tmp/rootfs/usr/share/zoneinfo/ 2>/dev/null || true && \
|
||||||
@@ -67,6 +76,8 @@ RUN \
|
|||||||
mkdir -p /tmp/rootfs/proc /tmp/rootfs/sys /tmp/rootfs/dev
|
mkdir -p /tmp/rootfs/proc /tmp/rootfs/sys /tmp/rootfs/dev
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
|
ENV PYTHONIOENCODING=utf-8
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
|||||||
+36
-4
@@ -80,14 +80,46 @@ max_size = 10485760 # 10MB
|
|||||||
|
|
||||||
[production.cors]
|
[production.cors]
|
||||||
allow_credentials = true
|
allow_credentials = true
|
||||||
allow_headers = ["Authorization", "Content-Type"]
|
allow_headers = ["*"]
|
||||||
allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
allow_methods = ["*"]
|
||||||
allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
|
allow_origins = ["http://192.168.137.5:8000", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||||
|
|
||||||
[production.module_system]
|
[production.module_system]
|
||||||
path = ["resources/app.mbank", "resources/plugins.mbank"]
|
path = [
|
||||||
|
["resources/app.mbank", "src/chongming/app", "app"],
|
||||||
|
["resources/plugins.mbank", "src/plugins", "plugins"],
|
||||||
|
]
|
||||||
type = "module-bank"
|
type = "module-bank"
|
||||||
|
|
||||||
[production.file_system]
|
[production.file_system]
|
||||||
path = "static.svfs"
|
path = "static.svfs"
|
||||||
type = "svfs"
|
type = "svfs"
|
||||||
|
|
||||||
|
[pyinstaller_build_import]
|
||||||
|
base = [
|
||||||
|
"utils", # public 骨架
|
||||||
|
"utils.launch",
|
||||||
|
"utils.config",
|
||||||
|
"server",
|
||||||
|
"module_bank", # 模块化打包工具
|
||||||
|
"sqlite_vfs",
|
||||||
|
"sqlite_vfs.core",
|
||||||
|
"fastapi", # web 应用依赖
|
||||||
|
"fastapi.staticfiles",
|
||||||
|
"fastapi.middleware.cors",
|
||||||
|
"uvicorn",
|
||||||
|
"sqlmodel",
|
||||||
|
"aiosqlite",
|
||||||
|
"aiofiles",
|
||||||
|
"apscheduler",
|
||||||
|
"diskcache",
|
||||||
|
"bcrypt",
|
||||||
|
"python_multipart",
|
||||||
|
"jwt",
|
||||||
|
]
|
||||||
|
linux = [
|
||||||
|
"gunicorn.glogging",
|
||||||
|
"gunicorn.app",
|
||||||
|
"gunicorn.app.wsgiapp",
|
||||||
|
]
|
||||||
|
windows = []
|
||||||
|
|||||||
@@ -17,11 +17,12 @@ ARCH=$(uname -m)
|
|||||||
case "$ARCH" in
|
case "$ARCH" in
|
||||||
x86_64|amd64)
|
x86_64|amd64)
|
||||||
DEFAULT_IMAGE="chongming:latest"
|
DEFAULT_IMAGE="chongming:latest"
|
||||||
ARCH_FLAG="x86_64"
|
EXTRA_OPTS=""
|
||||||
;;
|
;;
|
||||||
aarch64|arm64)
|
aarch64|arm64)
|
||||||
DEFAULT_IMAGE="chongming:arm64"
|
DEFAULT_IMAGE="chongming:arm64"
|
||||||
ARCH_FLAG="aarch64"
|
# ARM64 嵌入式设备(如 BM1684)Docker 线程限制较严格,需要放开 seccomp
|
||||||
|
EXTRA_OPTS="--security-opt seccomp=unconfined"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log_error "不支持的架构: $ARCH"
|
log_error "不支持的架构: $ARCH"
|
||||||
@@ -56,8 +57,8 @@ fi
|
|||||||
|
|
||||||
# 2. 创建目录
|
# 2. 创建目录
|
||||||
log_info "创建数据目录..."
|
log_info "创建数据目录..."
|
||||||
mkdir -p "$DATA_DIR"/{data,uploads,logs}
|
mkdir -p "$DATA_DIR"/{data,uploads,logs,config}
|
||||||
chmod 755 "$DATA_DIR"/{data,uploads,logs}
|
chmod 755 "$DATA_DIR"/{data,uploads,logs,config}
|
||||||
|
|
||||||
# 3. 复制初始数据(仅在目录为空时)
|
# 3. 复制初始数据(仅在目录为空时)
|
||||||
if [ -z "$(ls -A $DATA_DIR/data 2>/dev/null)" ]; then
|
if [ -z "$(ls -A $DATA_DIR/data 2>/dev/null)" ]; then
|
||||||
@@ -71,33 +72,36 @@ else
|
|||||||
log_info "数据库已存在,跳过初始化"
|
log_info "数据库已存在,跳过初始化"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 如果外部 config.toml 不存在,从镜像中复制一份模板
|
||||||
|
CONFIG_FILE="$DATA_DIR/config/config.toml"
|
||||||
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
|
log_info "首次部署,从镜像中提取 config.toml 配置模板..."
|
||||||
|
TMP_CONTAINER="chongming-config-tmp-$$"
|
||||||
|
docker create --name "$TMP_CONTAINER" "$IMAGE" &> /dev/null
|
||||||
|
docker cp "$TMP_CONTAINER:/app/config.toml" "$CONFIG_FILE" &> /dev/null
|
||||||
|
docker rm "$TMP_CONTAINER" &> /dev/null
|
||||||
|
log_info "配置模板已就绪: $CONFIG_FILE"
|
||||||
|
log_info "可按需修改配置后重启容器生效"
|
||||||
|
else
|
||||||
|
log_info "配置文件已存在,跳过初始化: $CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
# 检查端口是否被占用
|
# 检查端口是否被占用
|
||||||
if ss -tlnp | grep -q ":${PORT}"; then
|
if ss -tlnp | grep -q ":${PORT}"; then
|
||||||
log_error "端口 ${PORT} 已被占用,请修改 PORT 变量或释放端口"
|
log_error "端口 ${PORT} 已被占用,请修改 PORT 变量或释放端口"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 根据架构设置默认 worker 数
|
|
||||||
case "$ARCH" in
|
|
||||||
aarch64|arm64)
|
|
||||||
DEFAULT_WORKERS=2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
DEFAULT_WORKERS=4
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# 4. 启动容器
|
# 4. 启动容器
|
||||||
log_info "启动容器..."
|
log_info "启动容器..."
|
||||||
log_info "架构: $ARCH, workers: ${APP_WORKERS:-$DEFAULT_WORKERS}, 端口: $PORT"
|
log_info "架构: $ARCH, 镜像: $IMAGE, 端口: $PORT"
|
||||||
docker run -d \
|
docker run -d \
|
||||||
-p "$PORT:8000" \
|
-p "$PORT:8000" \
|
||||||
-v "$DATA_DIR/data:/app/data" \
|
-v "$DATA_DIR/data:/app/data" \
|
||||||
-v "$DATA_DIR/uploads:/app/uploads" \
|
-v "$DATA_DIR/uploads:/app/uploads" \
|
||||||
-v "$DATA_DIR/logs:/app/logs" \
|
-v "$DATA_DIR/logs:/app/logs" \
|
||||||
-e "APP_WORKERS=${APP_WORKERS:-$DEFAULT_WORKERS}" \
|
-v "$DATA_DIR/config/config.toml:/app/config.toml:ro" \
|
||||||
--ulimit nproc=65535 \
|
$EXTRA_OPTS \
|
||||||
--ulimit nofile=65535 \
|
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
--name "$CONTAINER" \
|
--name "$CONTAINER" \
|
||||||
"$IMAGE"
|
"$IMAGE"
|
||||||
|
|||||||
+7
-4
@@ -78,12 +78,15 @@ max_size = 10485760 # 10MB
|
|||||||
|
|
||||||
[production.cors]
|
[production.cors]
|
||||||
allow_credentials = true
|
allow_credentials = true
|
||||||
allow_headers = ["Authorization", "Content-Type"]
|
allow_headers = ["*"]
|
||||||
allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
allow_methods = ["*"]
|
||||||
allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
|
allow_origins = ["http://192.168.137.5:8000", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||||
|
|
||||||
[production.module_system]
|
[production.module_system]
|
||||||
path = ["resources/app.mbank", "resources/plugins.mbank"]
|
path = [
|
||||||
|
"resources/app.mbank",
|
||||||
|
"resources/plugins.mbank",
|
||||||
|
]
|
||||||
type = "module-bank"
|
type = "module-bank"
|
||||||
|
|
||||||
[production.file_system]
|
[production.file_system]
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import os
|
|||||||
from module_bank import PythonToSQLite
|
from module_bank import PythonToSQLite
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
key = None
|
|
||||||
|
|
||||||
|
|
||||||
def init_module_bank(config):
|
def init_module_bank(config):
|
||||||
@@ -27,10 +26,11 @@ def init_module_bank(config):
|
|||||||
|
|
||||||
# 为每个模块路径创建PythonToSQLite打包器实例
|
# 为每个模块路径创建PythonToSQLite打包器实例
|
||||||
packer_list = [
|
packer_list = [
|
||||||
PythonToSQLite(module_path, key=key) for module_path in MODULE_BANK_PATH_LIST
|
PythonToSQLite(module_path) for module_path in MODULE_BANK_PATH_LIST
|
||||||
]
|
]
|
||||||
# 遍历所有打包器,列出模块信息并安装导入器
|
# 遍历所有打包器,列出模块信息并安装导入器
|
||||||
for packer in packer_list:
|
for packer in packer_list:
|
||||||
|
key = packer.get_key()
|
||||||
modules = packer.list_modules()
|
modules = packer.list_modules()
|
||||||
for module in modules:
|
for module in modules:
|
||||||
print(f"{module['module_name']} {'[包]' if module['is_package'] else ''}")
|
print(f"{module['module_name']} {'[包]' if module['is_package'] else ''}")
|
||||||
|
|||||||
+6
-1
@@ -16,7 +16,7 @@ dependencies = [
|
|||||||
"diskcache",
|
"diskcache",
|
||||||
"fastapi[uvicorn]",
|
"fastapi[uvicorn]",
|
||||||
"gunicorn",
|
"gunicorn",
|
||||||
"module-bank",
|
"module-bank==0.2.4",
|
||||||
"pyjwt",
|
"pyjwt",
|
||||||
"python-multipart",
|
"python-multipart",
|
||||||
"sqlite-vfs",
|
"sqlite-vfs",
|
||||||
@@ -31,14 +31,19 @@ dependencies = [
|
|||||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||||
default = true
|
default = true
|
||||||
|
|
||||||
|
[[tool.uv.index]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
|
||||||
[[tool.uv.index]]
|
[[tool.uv.index]]
|
||||||
url = "https://mirrors.ustc.edu.cn/pypi/web/simple/"
|
url = "https://mirrors.ustc.edu.cn/pypi/web/simple/"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
|
"nuitka>=4.0.8",
|
||||||
"pyarmor",
|
"pyarmor",
|
||||||
"pyinstaller",
|
"pyinstaller",
|
||||||
"ruff>=0.15.10",
|
"ruff>=0.15.10",
|
||||||
|
"zstandard>=0.23.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
|
|||||||
+154
-149
@@ -10,9 +10,19 @@ from module_bank import PythonToSQLite
|
|||||||
from module_bank.encryption import Encryption
|
from module_bank.encryption import Encryption
|
||||||
from sqlite_vfs.core import SQLiteVFS
|
from sqlite_vfs.core import SQLiteVFS
|
||||||
from sqlite_vfs.folder_packer import FolderPacker
|
from sqlite_vfs.folder_packer import FolderPacker
|
||||||
|
from ..app.core.config import get_config
|
||||||
|
|
||||||
|
|
||||||
|
PYINSTALLER = "pyinstaller"
|
||||||
|
NUITKA = "nuitka"
|
||||||
|
|
||||||
is_windows = platform.system() == "Windows"
|
is_windows = platform.system() == "Windows"
|
||||||
|
build_mode = PYINSTALLER
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
build_mode = sys.argv[1]
|
||||||
|
|
||||||
|
if build_mode not in [PYINSTALLER, NUITKA]:
|
||||||
|
raise ValueError(f"不支持{build_mode}打包模式")
|
||||||
|
|
||||||
|
|
||||||
def build_vue_web():
|
def build_vue_web():
|
||||||
@@ -112,6 +122,95 @@ def run_pyarmor_obfuscate():
|
|||||||
print(result.stdout)
|
print(result.stdout)
|
||||||
print(f"打包文件: {file}")
|
print(f"打包文件: {file}")
|
||||||
|
|
||||||
|
def run_nuitka():
|
||||||
|
"""
|
||||||
|
兼容旧版 Nuitka 的打包函数(不使用任何可能不支持的参数)
|
||||||
|
编译后手动 strip + upx 压缩
|
||||||
|
"""
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
config = get_config()
|
||||||
|
build_import_base = config \
|
||||||
|
.get("pyinstaller_build_import", {}) \
|
||||||
|
.get("base", [])
|
||||||
|
linux_extra = config \
|
||||||
|
.get("pyinstaller_build_import", {}) \
|
||||||
|
.get("linux", [])
|
||||||
|
windows_extra = config \
|
||||||
|
.get("pyinstaller_build_import", {}) \
|
||||||
|
.get("windows", [])
|
||||||
|
|
||||||
|
all_imports = list(build_import_base)
|
||||||
|
if is_windows:
|
||||||
|
all_imports.extend(windows_extra)
|
||||||
|
else:
|
||||||
|
all_imports.extend(linux_extra)
|
||||||
|
|
||||||
|
packages = [
|
||||||
|
"module_bank", "sqlite_vfs", "fastapi", "uvicorn", "gunicorn",
|
||||||
|
"diskcache", "bcrypt", "apscheduler", "aiofiles", "aiosqlite",
|
||||||
|
"sqlmodel", "jwt", "python_multipart", "tomli", "typing_extensions"
|
||||||
|
]
|
||||||
|
|
||||||
|
# 最基础的参数(兼容所有 Nuitka 版本)
|
||||||
|
cmd = [
|
||||||
|
sys.executable, "-m", "nuitka",
|
||||||
|
"--standalone",
|
||||||
|
"--onefile",
|
||||||
|
"--follow-imports",
|
||||||
|
"--static-libpython=no",
|
||||||
|
"--remove-output",
|
||||||
|
"--assume-yes-for-downloads",
|
||||||
|
]
|
||||||
|
|
||||||
|
# 尝试添加 LTO(如果不支持,会在此阶段失败,我们在下方会用 try/except 回退)
|
||||||
|
cmd.append("--lto=yes")
|
||||||
|
|
||||||
|
# 尝试启用 UPX 插件(旧版可能不支持)
|
||||||
|
if shutil.which("upx"):
|
||||||
|
cmd.append("--enable-plugin=upx")
|
||||||
|
|
||||||
|
for pkg in packages:
|
||||||
|
cmd.append(f"--include-package={pkg}")
|
||||||
|
|
||||||
|
for mod in all_imports:
|
||||||
|
cmd.append(f"--include-module={mod}")
|
||||||
|
|
||||||
|
cmd.append("--disable-plugin=tk-inter")
|
||||||
|
cmd.append("--disable-plugin=numpy")
|
||||||
|
cmd += ["--output-dir=.", "--output-filename=chongming", "main.py"]
|
||||||
|
cmd.append("--jobs=2")
|
||||||
|
|
||||||
|
if is_windows:
|
||||||
|
icon_path = Path("../../public/chongming.ico")
|
||||||
|
if icon_path.exists():
|
||||||
|
cmd.append(f"--windows-icon-from-ico={icon_path}")
|
||||||
|
|
||||||
|
print("正在运行 Nuitka 编译...")
|
||||||
|
try:
|
||||||
|
subprocess.run(cmd, cwd="./build", check=True, capture_output=False, text=True)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
# 如果因为 --lto=yes 或 --enable-plugin=upx 失败,则用更基础的命令重试
|
||||||
|
print("检测到参数不支持,移除 --lto=yes 和 --enable-plugin=upx 重新编译...")
|
||||||
|
fallback_cmd = [arg for arg in cmd if arg not in ("--lto=yes", "--enable-plugin=upx")]
|
||||||
|
subprocess.run(fallback_cmd, cwd="./build", check=True, capture_output=False, text=True)
|
||||||
|
|
||||||
|
print("Nuitka 编译完成!开始后处理瘦身...")
|
||||||
|
|
||||||
|
exe_path = Path("./build/chongming")
|
||||||
|
if not is_windows and exe_path.exists():
|
||||||
|
# 手动 strip 去掉符号表
|
||||||
|
subprocess.run(["strip", str(exe_path)], check=False)
|
||||||
|
print("已执行 strip,去除调试符号")
|
||||||
|
if shutil.which("upx") and exe_path.exists():
|
||||||
|
# 手动 UPX 极限压缩
|
||||||
|
subprocess.run(["upx", "--best", str(exe_path)], check=False)
|
||||||
|
print("已执行 UPX 压缩")
|
||||||
|
|
||||||
|
# 清理临时入口文件
|
||||||
|
shutil.rmtree("build/utils", ignore_errors=True)
|
||||||
|
os.remove("build/main.py")
|
||||||
|
os.remove("build/server.py")
|
||||||
|
|
||||||
def run_pyinstaller():
|
def run_pyinstaller():
|
||||||
"""
|
"""
|
||||||
@@ -126,141 +225,50 @@ def run_pyinstaller():
|
|||||||
Returns:
|
Returns:
|
||||||
None: 无返回值,通过打印信息反馈执行结果
|
None: 无返回值,通过打印信息反馈执行结果
|
||||||
"""
|
"""
|
||||||
|
config = get_config()
|
||||||
try:
|
try:
|
||||||
# 构建 PyInstaller 命令
|
# 构建 PyInstaller 命令
|
||||||
|
build_import_base = config \
|
||||||
|
.get("pyinstaller_build_import", {}) \
|
||||||
|
.get("base", [])
|
||||||
|
cmd = [
|
||||||
|
sys.executable,
|
||||||
|
"-m",
|
||||||
|
"PyInstaller",
|
||||||
|
"--onefile",
|
||||||
|
"--noconfirm",
|
||||||
|
"--optimize",
|
||||||
|
"2",
|
||||||
|
"--strip",
|
||||||
|
"--name",
|
||||||
|
"chongming",
|
||||||
|
"--distpath",
|
||||||
|
".",
|
||||||
|
"--workpath",
|
||||||
|
"./build_temp",
|
||||||
|
"--specpath",
|
||||||
|
"./specs",
|
||||||
|
"--clean",
|
||||||
|
# 其他选项
|
||||||
|
"--icon",
|
||||||
|
"../../public/chongming.ico",
|
||||||
|
"main.py",
|
||||||
|
]
|
||||||
if is_windows:
|
if is_windows:
|
||||||
cmd = [
|
windows_build_import = config \
|
||||||
sys.executable,
|
.get("pyinstaller_build_import", {}) \
|
||||||
"-m",
|
.get("windows", []) + build_import_base
|
||||||
"PyInstaller",
|
|
||||||
"--onefile",
|
for build_import in windows_build_import:
|
||||||
"--noconfirm",
|
cmd.append("--hidden-import")
|
||||||
"--optimize",
|
cmd.append(build_import)
|
||||||
"2",
|
|
||||||
"--strip",
|
|
||||||
"--name",
|
|
||||||
"chongming",
|
|
||||||
"--distpath",
|
|
||||||
".",
|
|
||||||
"--workpath",
|
|
||||||
"./build_temp",
|
|
||||||
"--specpath",
|
|
||||||
"./specs",
|
|
||||||
"--clean",
|
|
||||||
# 隐藏导入
|
|
||||||
"--hidden-import",
|
|
||||||
"utils",
|
|
||||||
"--hidden-import",
|
|
||||||
"utils.launch",
|
|
||||||
"--hidden-import",
|
|
||||||
"utils.config",
|
|
||||||
"--hidden-import",
|
|
||||||
"server",
|
|
||||||
"--hidden-import",
|
|
||||||
"module_bank",
|
|
||||||
"--hidden-import",
|
|
||||||
"fastapi",
|
|
||||||
"--hidden-import",
|
|
||||||
"fastapi.staticfiles",
|
|
||||||
"--hidden-import",
|
|
||||||
"fastapi.middleware.cors",
|
|
||||||
"--hidden-import",
|
|
||||||
"uvicorn",
|
|
||||||
"--hidden-import",
|
|
||||||
"sqlmodel",
|
|
||||||
"--hidden-import",
|
|
||||||
"aiosqlite",
|
|
||||||
"--hidden-import",
|
|
||||||
"aiofiles",
|
|
||||||
"--hidden-import",
|
|
||||||
"apscheduler",
|
|
||||||
"--hidden-import",
|
|
||||||
"diskcache",
|
|
||||||
"--hidden-import",
|
|
||||||
"bcrypt",
|
|
||||||
"--hidden-import",
|
|
||||||
"sqlite_vfs",
|
|
||||||
"--hidden-import",
|
|
||||||
"python_multipart",
|
|
||||||
"--hidden-import",
|
|
||||||
"sqlite_vfs.core",
|
|
||||||
"--hidden-import",
|
|
||||||
"jwt",
|
|
||||||
# 其他选项
|
|
||||||
"--icon",
|
|
||||||
"../../public/chongming.ico",
|
|
||||||
"main.py",
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
cmd = [
|
linux_build_import = config \
|
||||||
sys.executable,
|
.get("pyinstaller_build_import", {}) \
|
||||||
"-m",
|
.get("linux", []) + build_import_base
|
||||||
"PyInstaller",
|
for build_import in linux_build_import:
|
||||||
"--onefile",
|
cmd.append("--hidden-import")
|
||||||
"--noconfirm",
|
cmd.append(build_import)
|
||||||
"--optimize",
|
|
||||||
"2",
|
|
||||||
"--strip",
|
|
||||||
"--name",
|
|
||||||
"chongming",
|
|
||||||
"--distpath",
|
|
||||||
".",
|
|
||||||
"--workpath",
|
|
||||||
"./build_temp",
|
|
||||||
"--specpath",
|
|
||||||
"./specs",
|
|
||||||
"--clean",
|
|
||||||
# 隐藏导入
|
|
||||||
"--hidden-import",
|
|
||||||
"utils",
|
|
||||||
"--hidden-import",
|
|
||||||
"utils.launch",
|
|
||||||
"--hidden-import",
|
|
||||||
"utils.config",
|
|
||||||
"--hidden-import",
|
|
||||||
"server",
|
|
||||||
"--hidden-import",
|
|
||||||
"module_bank",
|
|
||||||
"--hidden-import",
|
|
||||||
"fastapi",
|
|
||||||
"--hidden-import",
|
|
||||||
"fastapi.staticfiles",
|
|
||||||
"--hidden-import",
|
|
||||||
"fastapi.middleware.cors",
|
|
||||||
"--hidden-import",
|
|
||||||
"uvicorn",
|
|
||||||
"--hidden-import",
|
|
||||||
"sqlmodel",
|
|
||||||
"--hidden-import",
|
|
||||||
"aiosqlite",
|
|
||||||
"--hidden-import",
|
|
||||||
"aiofiles",
|
|
||||||
"--hidden-import",
|
|
||||||
"apscheduler",
|
|
||||||
"--hidden-import",
|
|
||||||
"diskcache",
|
|
||||||
"--hidden-import",
|
|
||||||
"bcrypt",
|
|
||||||
"--hidden-import",
|
|
||||||
"sqlite_vfs",
|
|
||||||
"--hidden-import",
|
|
||||||
"python_multipart",
|
|
||||||
"--hidden-import",
|
|
||||||
"sqlite_vfs.core",
|
|
||||||
"--hidden-import",
|
|
||||||
"jwt",
|
|
||||||
# gunicorn
|
|
||||||
"--hidden-import",
|
|
||||||
"gunicorn.glogging",
|
|
||||||
"--hidden-import",
|
|
||||||
"gunicorn.app",
|
|
||||||
"--hidden-import",
|
|
||||||
"gunicorn.app.wsgiapp",
|
|
||||||
# 其他选项
|
|
||||||
"--icon",
|
|
||||||
"../../public/chongming.ico",
|
|
||||||
"main.py",
|
|
||||||
]
|
|
||||||
|
|
||||||
print(f"正在运行 PyInstaller: {' '.join(cmd)}")
|
print(f"正在运行 PyInstaller: {' '.join(cmd)}")
|
||||||
result = subprocess.run(cmd, cwd="./build", capture_output=True, text=True)
|
result = subprocess.run(cmd, cwd="./build", capture_output=True, text=True)
|
||||||
@@ -301,7 +309,6 @@ async def init_database():
|
|||||||
from sqlalchemy.exc import OperationalError
|
from sqlalchemy.exc import OperationalError
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||||
|
|
||||||
from ..app.core.config import get_config
|
|
||||||
from ..app.task.dev_init_db import init_permission, init_default_roles, dev_init_admin
|
from ..app.task.dev_init_db import init_permission, init_default_roles, dev_init_admin
|
||||||
|
|
||||||
database = get_config()["database"]
|
database = get_config()["database"]
|
||||||
@@ -358,19 +365,18 @@ async def main():
|
|||||||
None: 无返回值
|
None: 无返回值
|
||||||
"""
|
"""
|
||||||
# 打包模块
|
# 打包模块
|
||||||
key = Encryption.generate_key()
|
|
||||||
resources_path = Path("resources")
|
resources_path = Path("resources")
|
||||||
if not resources_path.exists():
|
if not resources_path.exists():
|
||||||
resources_path.mkdir()
|
resources_path.mkdir()
|
||||||
app_packer = PythonToSQLite("./resources/app.mbank", key)
|
|
||||||
app_packer.pack_directory("src/chongming/app", "app")
|
|
||||||
app_packer.verify_package_structure()
|
|
||||||
app_packer.delete_source_code(None)
|
|
||||||
|
|
||||||
plugin_packer = PythonToSQLite("./resources/plugins.mbank", key)
|
mbank_list = get_config()["production"].get("module_system", {}).get("path", [])
|
||||||
plugin_packer.pack_directory("src/plugins", "plugins")
|
for mbank in mbank_list:
|
||||||
plugin_packer.verify_package_structure()
|
key = Encryption.generate_key()
|
||||||
plugin_packer.delete_source_code(None)
|
app_packer = PythonToSQLite(mbank[0], key)
|
||||||
|
app_packer.pack_directory(mbank[1], mbank[2])
|
||||||
|
app_packer.verify_package_structure()
|
||||||
|
app_packer.packer_key(key)
|
||||||
|
app_packer.delete_source_code(None)
|
||||||
|
|
||||||
# 创建 build 目录
|
# 创建 build 目录
|
||||||
build_path = Path("build")
|
build_path = Path("build")
|
||||||
@@ -403,12 +409,6 @@ async def main():
|
|||||||
# 复制 utils 文件夹到 build 文件夹
|
# 复制 utils 文件夹到 build 文件夹
|
||||||
shutil.copytree("public/utils", "build/utils")
|
shutil.copytree("public/utils", "build/utils")
|
||||||
|
|
||||||
with open("./build/utils/launch.py", "r", encoding="utf-8") as f:
|
|
||||||
context = f.read()
|
|
||||||
context = context.replace("key = None", f"key = '{key}'")
|
|
||||||
with open("./build/utils/launch.py", "w", encoding="utf-8") as f:
|
|
||||||
f.write(context)
|
|
||||||
|
|
||||||
jwt_key = Encryption.generate_key()
|
jwt_key = Encryption.generate_key()
|
||||||
with open("./build/config.toml", "r", encoding="utf-8") as f:
|
with open("./build/config.toml", "r", encoding="utf-8") as f:
|
||||||
context = f.read()
|
context = f.read()
|
||||||
@@ -416,12 +416,11 @@ async def main():
|
|||||||
with open("build/config.toml", "w", encoding="utf-8") as f:
|
with open("build/config.toml", "w", encoding="utf-8") as f:
|
||||||
f.write(context)
|
f.write(context)
|
||||||
|
|
||||||
|
if build_mode == PYINSTALLER:
|
||||||
# 混淆
|
# 混淆
|
||||||
run_pyarmor_obfuscate()
|
run_pyarmor_obfuscate()
|
||||||
|
|
||||||
# 运行 PyInstaller
|
# 运行 PyInstaller
|
||||||
run_pyinstaller()
|
run_pyinstaller()
|
||||||
|
|
||||||
# 清理临时文件
|
# 清理临时文件
|
||||||
shutil.rmtree(r"build/build_temp", ignore_errors=True)
|
shutil.rmtree(r"build/build_temp", ignore_errors=True)
|
||||||
shutil.rmtree(r"build/specs", ignore_errors=True)
|
shutil.rmtree(r"build/specs", ignore_errors=True)
|
||||||
@@ -429,6 +428,12 @@ async def main():
|
|||||||
shutil.rmtree(r"build/pyarmor_runtime_000000", ignore_errors=True)
|
shutil.rmtree(r"build/pyarmor_runtime_000000", ignore_errors=True)
|
||||||
os.remove(r"build/main.py")
|
os.remove(r"build/main.py")
|
||||||
os.remove(r"build/server.py")
|
os.remove(r"build/server.py")
|
||||||
|
elif build_mode == NUITKA:
|
||||||
|
run_nuitka()
|
||||||
|
# Nuitka 编译后清理临时文件
|
||||||
|
shutil.rmtree(r"build/utils", ignore_errors=True)
|
||||||
|
# os.remove(r"build/main.py")
|
||||||
|
# os.remove(r"build/server.py")
|
||||||
|
|
||||||
print("构建完成")
|
print("构建完成")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user