107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
import os
|
||
import subprocess
|
||
import sys
|
||
import shutil
|
||
import platform
|
||
|
||
MAIN_FILE = "main_nicegui.py"
|
||
# 【关键修改】提取应用名称为变量,确保打包目录和复制目录一致
|
||
APP_NAME = "尚城幼儿园幼儿学期发展报告"
|
||
|
||
|
||
def copy_resources():
|
||
"""
|
||
将资源文件从项目根目录复制到 dist/APP_NAME 文件夹中 (与 exe 同级),
|
||
以便用户可以直接在 exe 旁边修改这些文件。
|
||
"""
|
||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||
project_root = os.path.dirname(current_dir)
|
||
|
||
# 【关键修改】目标目录改为 dist/APP_NAME
|
||
# 这样资源文件才会出现在 exe 旁边,而不是 dist 根目录
|
||
dist_dir = os.path.join(current_dir, "dist", APP_NAME)
|
||
|
||
print(f"\n--- 正在复制外部资源到 {dist_dir} ---")
|
||
|
||
if not os.path.exists(dist_dir):
|
||
print(f"错误: 目标文件夹不存在: {dist_dir}")
|
||
print("请检查是否打包成功,或者是否使用了 --onedir 模式。")
|
||
return
|
||
|
||
# 这里的列表是【给用户看/改的】
|
||
resources_to_copy = [
|
||
("config.toml", ""),
|
||
("fonts", "fonts"),
|
||
("data", "data"),
|
||
("templates", "templates"),
|
||
("public", "public"),
|
||
]
|
||
|
||
for src_name, dest_name in resources_to_copy:
|
||
src_path = os.path.join(project_root, src_name)
|
||
dest_path = os.path.join(dist_dir, dest_name)
|
||
|
||
try:
|
||
if os.path.isfile(src_path):
|
||
shutil.copy2(src_path, dest_path)
|
||
print(f"✅ 已复制文件: {src_name}")
|
||
elif os.path.isdir(src_path):
|
||
# dirs_exist_ok=True 允许覆盖已存在的目录(Python 3.8+)
|
||
shutil.copytree(src_path, dest_path, dirs_exist_ok=True)
|
||
print(f"✅ 已复制目录: {src_name}")
|
||
else:
|
||
print(f"⚠️ 警告: 源文件不存在,跳过: {src_path}")
|
||
except Exception as e:
|
||
print(f"❌ 复制失败 {src_name}: {e}")
|
||
|
||
|
||
def build_exe():
|
||
"""使用 PyInstaller 打包"""
|
||
|
||
sep = ';' if platform.system() == "Windows" else ':'
|
||
|
||
# 内部资源 (打入 exe 内部的)
|
||
resource_paths = [
|
||
f"../config.toml{sep}.",
|
||
f"../fonts{sep}fonts",
|
||
f"../templates{sep}templates",
|
||
f"../ui/assets{sep}ui/assets",
|
||
]
|
||
|
||
try:
|
||
command = [
|
||
sys.executable, "-m", "PyInstaller",
|
||
"--onedir", # 文件夹模式
|
||
"--windowed", # 隐藏控制台 (调试时建议先注释掉)
|
||
f"--name={APP_NAME}", # 【关键修改】使用变量
|
||
"--clean",
|
||
"--distpath=./dist",
|
||
"--workpath=./build",
|
||
"--icon=../public/icon.ico",
|
||
"../" + MAIN_FILE
|
||
]
|
||
|
||
for res in resource_paths:
|
||
command.append(f"--add-data={res}")
|
||
|
||
command.extend(["--hidden-import=nicegui", "--hidden-import=uvicorn"])
|
||
|
||
print("--- 开始打包 (PyInstaller) ---")
|
||
subprocess.run(command, check=True, cwd=os.path.dirname(os.path.abspath(__file__)))
|
||
print("\n--- PyInstaller 打包完成!---")
|
||
|
||
# 打包完成后执行复制
|
||
copy_resources()
|
||
|
||
# 打印最终 exe 的位置提示
|
||
exe_path = os.path.join("dist", APP_NAME, f"{APP_NAME}.exe")
|
||
print(f"\n🎉 全部完成!可执行文件位于: {exe_path}")
|
||
|
||
except subprocess.CalledProcessError as e:
|
||
print(f"\n❌ 打包失败: {e}")
|
||
except Exception as e:
|
||
print(f"\n❌ 发生错误: {e}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
build_exe() |