forked from fzls/djc_helper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_build.py
163 lines (134 loc) · 6.42 KB
/
_build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# 编译脚本
import argparse
import os
import shutil
import subprocess
from _init_venv_and_requirements import init_venv_and_requirements
from log import color, logger
from util import (
async_message_box,
clear_file,
human_readable_size,
make_sure_dir_exists,
remove_file_or_directory,
show_head_line,
)
def build(disable_douban=False, enable_proxy=False, use_upx=True):
# 初始化相关路径变量
venv_path = ".venv"
pyinstaller_path = os.path.join(venv_path, "Scripts", "pyinstaller")
# 确保test.py内容为空,避免出现异常状况
if os.path.isfile("test.py") and os.stat("test.py").st_size != 0:
with open("test.py", encoding="utf-8") as f:
async_message_box(f"test.py内容不为空,未避免构建过程中执行产生副作用,将清空其内容,其内容如下:\n\n{f.read()}", "警告:test.py的测试代码未移除")
clear_file("test.py")
# 初始化venv和依赖
init_venv_and_requirements(".venv", "requirements.txt", disable_douban, enable_proxy)
show_head_line("将使用.venv环境进行编译", color("bold_yellow"))
temp_remove_file_dir = os.path.join(".cached", "build_temp_remove_files")
site_packages_path = os.path.join(venv_path, "Lib", "site-packages")
dep_files_to_remove_during_build = {
"PyQt5/Qt5": [
"Translations",
],
"PyQt5/Qt5/bin": [
"opengl32sw.dll",
"libEGL.dll",
"libGLESV2.dll",
"Qt5Svg.dll",
"Qt5Network.dll",
"Qt5Qml.dll",
"Qt5QmlModels.dll",
"Qt5Quick.dll",
"Qt5WebSockets.dll",
"d3dcompiler_47.dll",
],
"PyQt5/Qt5/plugins": [
"iconengines/qsvgicon.dll",
"imageformats/qsvg.dll",
"imageformats/qwebp.dll",
"platforms/qwebgl.dll",
],
}
logger.info(color("bold_green") + f"开始编译前先尝试移动这些确定用不到的库文件到临时目录 {temp_remove_file_dir},从而尽可能减少最终编译的大小")
for parent_directory, file_or_directory_name_list in dep_files_to_remove_during_build.items():
for file_or_directory_name in file_or_directory_name_list:
path = os.path.join(site_packages_path, parent_directory, file_or_directory_name)
backup_path = os.path.join(temp_remove_file_dir, parent_directory, file_or_directory_name)
if not os.path.exists(path):
logger.warning(f"\t{path} 不存在,将跳过")
continue
if os.path.exists(backup_path):
remove_file_or_directory(backup_path)
# 将文件移动到备份目录
logger.info(f"\t开始移动 {path}")
make_sure_dir_exists(os.path.dirname(backup_path))
shutil.move(path, backup_path)
# 实际编译流程
build_configs: list[tuple[str, str, str, str, list[str], list[str]]] = [
("main.py", "DNF蚊子腿小助手.exe", "utils/icons/DNF蚊子腿小助手.ico", ".", [], []),
("config_ui.py", "DNF蚊子腿小助手配置工具.exe", "utils/icons/config_ui.ico", ".", [], ["--noconsole"]),
("auto_updater.py", "auto_updater.exe", "", "utils", ["PyQt5"], []),
# ("my_home_special_version.py", "DNF蚊子腿小助手_我的小屋特别版.exe", "utils/icons/my_home.ico", ".", ["PyQt5"], []),
]
# ark_icon = "utils/icons/ark_lottery_special_version.ico"
# build_configs.append(
# ("ark_lottery_special_version.py", "DNF蚊子腿小助手_集卡特别版.exe", ark_icon, ".", ["PyQt5"], []),
# )
for idx, config in enumerate(build_configs):
prefix = f"{idx + 1}/{len(build_configs)}"
src_path, exe_name, icon_path, target_dir, exclude_modules, extra_args = config
logger.info(color("bold_yellow") + f"{prefix} 开始编译 {exe_name}")
cmd_build = [
pyinstaller_path,
"--name",
exe_name,
"-F",
src_path,
]
if icon_path != "":
cmd_build.extend(["--icon", icon_path])
for module in exclude_modules:
cmd_build.extend(["--exclude-module", module])
if use_upx:
cmd_build.extend(["--upx-dir", "utils"])
cmd_build.extend(extra_args)
logger.info(f"{prefix} 开始编译 {exe_name},命令为:{' '.join(cmd_build)}")
subprocess.call(cmd_build)
logger.info("编译结束,进行善后操作")
# 复制二进制
logger.info(f"复制{exe_name}到目标目录{target_dir}")
if not os.path.isdir(target_dir):
os.mkdir(target_dir)
target_path = os.path.join(target_dir, exe_name)
shutil.copyfile(os.path.join("dist", exe_name), target_path)
# 删除临时文件
logger.info("删除临时文件")
for directory in ["build", "dist", "__pycache__"]:
shutil.rmtree(directory, ignore_errors=True)
os.remove(f"{exe_name}.spec")
filesize = os.path.getsize(target_path)
logger.info(color("bold_green") + f"{prefix} 编译{exe_name}结束,最终大小为{human_readable_size(filesize)}")
logger.info(color("bold_green") + f"编译完毕将库文件移动回来 - {site_packages_path}")
for parent_directory, file_or_directory_name_list in dep_files_to_remove_during_build.items():
for file_or_directory_name in file_or_directory_name_list:
path = os.path.join(site_packages_path, parent_directory, file_or_directory_name)
backup_path = os.path.join(temp_remove_file_dir, parent_directory, file_or_directory_name)
if not os.path.exists(backup_path):
logger.warning(f"\t备份文件 {backup_path} 不存在,将跳过")
continue
# 将文件移动到备份目录
logger.info(f"开始还原备份文件/目录 {backup_path}")
make_sure_dir_exists(os.path.dirname(path))
shutil.move(backup_path, path)
logger.info("done")
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--disable_douban", action="store_true")
parser.add_argument("--enable_proxy", action="store_true")
parser.add_argument("--disable_upx", action="store_true")
args = parser.parse_args()
return args
if __name__ == "__main__":
args = parse_args()
build(args.disable_douban, args.enable_proxy, not args.disable_upx)