PyInstallerEx 0.1.9__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {pyinstallerex-0.1.9/src/PyInstallerEx.egg-info → pyinstallerex-0.2.3}/PKG-INFO +83 -7
  2. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/README.md +81 -6
  3. pyinstallerex-0.2.3/bin/launcher_windows.exe +0 -0
  4. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/pyproject.toml +3 -2
  5. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/setup.py +2 -1
  6. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/__main__.py +6 -5
  7. pyinstallerex-0.2.3/src/PyInstallerEx/server.py +291 -0
  8. pyinstallerex-0.2.3/src/PyInstallerEx/web/favicon.ico +0 -0
  9. pyinstallerex-0.2.3/src/PyInstallerEx/web/index.html +664 -0
  10. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3/src/PyInstallerEx.egg-info}/PKG-INFO +83 -7
  11. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx.egg-info/SOURCES.txt +3 -1
  12. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx.egg-info/requires.txt +1 -0
  13. pyinstallerex-0.1.9/bin/launcher_windows.exe +0 -0
  14. pyinstallerex-0.1.9/src/PyInstallerEx/PyInstallerEx.py +0 -0
  15. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/LICENSE +0 -0
  16. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/setup.cfg +0 -0
  17. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/__init__.py +0 -0
  18. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/core/__init__.py +0 -0
  19. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/core/config.py +0 -0
  20. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/core/packager.py +0 -0
  21. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/utils/__init__.py +0 -0
  22. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/utils/compression.py +0 -0
  23. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/utils/file_utils.py +0 -0
  24. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/utils/icon_helper.py +0 -0
  25. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/utils/logging.py +0 -0
  26. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx/utils/system_utils.py +0 -0
  27. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx.egg-info/dependency_links.txt +0 -0
  28. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx.egg-info/entry_points.txt +0 -0
  29. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx.egg-info/not-zip-safe +0 -0
  30. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/src/PyInstallerEx.egg-info/top_level.txt +0 -0
  31. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/test/test_python27_compatibility.py +0 -0
  32. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/test/test_python3x_compatibility.py +0 -0
  33. {pyinstallerex-0.1.9 → pyinstallerex-0.2.3}/test/test_rust_launcher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyInstallerEx
3
- Version: 0.1.9
3
+ Version: 0.2.3
4
4
  Summary: 扩展PyInstaller 使其拥有单文件安装功能不用每次都解压执行
5
5
  Home-page: https://gitee.com/iiixxxiii/py-installer-ex
6
6
  Author: lixin
@@ -27,6 +27,7 @@ Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: PyInstaller>=3.2.1
30
+ Requires-Dist: pyquickwebgui
30
31
  Dynamic: author
31
32
  Dynamic: home-page
32
33
  Dynamic: license-file
@@ -52,6 +53,10 @@ PyInstallerEx 是一个基于 PyInstaller 的增强版打包工具,能够将 P
52
53
  4. **灵活解压模式**:支持解压到系统临时目录或 exe 所在目录(通过 `--extract-mode` 参数控制)
53
54
  5. **跨平台支持**:Windows、Linux x86/ARM全平台覆盖
54
55
  6. **配置灵活**:支持嵌入式配置读取,命令行参数覆盖配置文件
56
+ 7. **命令行参数透传**:打包后的可执行文件支持将命令行参数传递给内部程序
57
+ 8. **Web GUI 界面**:无参数启动时自动打开图形化界面,可视化配置打包参数
58
+ - **多语言支持**:支持中文/英文界面切换,设置持久化保存
59
+ - **文件选择对话框**:原生 tkinter 文件/文件夹选择器,支持初始路径记忆
55
60
 
56
61
  ## 🔧 环境要求
57
62
 
@@ -130,6 +135,26 @@ pip install pyinstallerex
130
135
 
131
136
  ### 基本用法
132
137
 
138
+ #### 启动 Web GUI(图形界面)
139
+
140
+ 直接运行命令,不带任何参数,即可启动 Web GUI 界面:
141
+
142
+ ```bash
143
+ # 以下三种方式均可
144
+ PyInstallerEx
145
+ pyinstallerex
146
+ python -m PyInstallerEx
147
+ ```
148
+
149
+ 启动后会自动打开浏览器窗口,支持:
150
+ - 选择脚本或文件夹打包模式
151
+ - 可视化配置输出名称、版本、引擎、图标等参数
152
+ - 实时查看构建日志和结果
153
+
154
+ #### 命令行模式
155
+
156
+ 带参数时使用命令行模式:
157
+
133
158
  ```bash
134
159
  # 使用 pyinstallerex 命令
135
160
  pyinstallerex your_script.py
@@ -176,6 +201,7 @@ test\test_script.exe # Windows
176
201
  | 04 | `04 - hello_world - PyOxidizer` | 使用 PyOxidizer 引擎打包 | `--engine-mode pyoxidizer` |
177
202
  | 05 | `05 - hello_world - icon` | 自定义 exe 图标(`.ico` 格式) | `--icon "exe.ico"` |
178
203
  | 06 | `06 - hello_world - folder` | 文件夹直接打包,跳过引擎构建,将指定文件夹封装为单文件 | `--folder "hello_folder" --run "hello.exe"` |
204
+ | 07 | `07 - hello_world - parameter` | 命令行参数透传,支持 `--add1` 和 `--add2` 参数进行加法运算 | 无额外打包参数,运行时传参 |
179
205
 
180
206
  > 每个示例均提供 `package.bat`(Windows)和 `package.sh`(Linux/Mac)两套构建脚本。
181
207
 
@@ -225,6 +251,32 @@ python -m PyInstallerEx your_script.py --engine-mode pyoxidizer
225
251
  - **Nuitka**:需要安装 Nuitka (`pip install nuitka`) 和 C 编译器(如 Visual Studio Build Tools)
226
252
  - **PyOxidizer**:需要单独安装 PyOxidizer,详见 [PyOxidizer 文档](https://pyoxidizer.readthedocs.io/)
227
253
 
254
+ ### 命令行参数透传
255
+
256
+ 打包后的可执行文件支持将命令行参数透传给内部程序,无需额外配置:
257
+
258
+ ```bash
259
+ # 打包程序
260
+ python -m PyInstallerEx hello.py -n hello_param
261
+
262
+ # 运行并传递参数
263
+ hello_param.exe --add1 10 --add2 20
264
+ # 输出:Calculation: 10.0 + 20.0 = 30.0
265
+
266
+ # 查看帮助
267
+ hello_param.exe --help
268
+ ```
269
+
270
+ **工作原理**:
271
+ - Rust 启动器在运行内部程序时,自动收集并传递所有命令行参数
272
+ - 支持任意参数格式,完全兼容 `argparse` 等参数解析库
273
+ - 参数透传对所有打包模式(脚本模式、文件夹模式)均有效
274
+
275
+ **使用场景**:
276
+ - 需要接收用户输入的命令行工具
277
+ - 支持配置参数的自动化脚本
278
+ - 需要灵活控制运行时行为的工具程序
279
+
228
280
  ### 文件夹直接打包模式
229
281
 
230
282
  使用 `--folder` 参数跳过 PyInstaller/Nuitka 等引擎打包流程,直接将指定文件夹压缩并附加到 Rust 启动器尾部,生成最终可执行文件。
@@ -327,7 +379,11 @@ py-installer-ex/
327
379
  │ ├── PyInstallerEx/ # Python 主程序
328
380
  │ │ ├── __init__.py
329
381
  │ │ ├── __main__.py # CLI入口点
382
+ │ │ ├── server.py # Web GUI 后端服务
330
383
  │ │ ├── PyInstallerEx.py # 主模块
384
+ │ │ ├── web/
385
+ │ │ │ ├── index.html # Web GUI 前端页面
386
+ │ │ │ └── favicon.ico # 页面图标
331
387
  │ │ ├── core/
332
388
  │ │ │ ├── config.py # 配置管理
333
389
  │ │ │ └── packager.py # 打包逻辑
@@ -433,6 +489,7 @@ script\install.bat
433
489
  - ✅ **智能安装**:首次运行自动提取,后续运行复用已安装版本
434
490
  - ✅ **配置解析**:从可执行文件中读取和处理配置信息
435
491
  - ✅ **临时目录管理**:自动管理临时文件和清理
492
+ - ✅ **命令行参数透传**:自动将启动器的命令行参数传递给内部程序
436
493
 
437
494
  ### 3. 文件夹直接打包
438
495
  - ✅ **`--folder` 参数**:跳过引擎构建,直接将指定文件夹压缩打包
@@ -449,20 +506,39 @@ script\install.bat
449
506
 
450
507
  - **Python 2.7+ / 3.x**: 主要开发语言
451
508
  - **PyInstaller >= 3.2.1**: 应用程序打包基础
509
+ - **pyquickwebgui**: Web GUI 图形界面框架
452
510
  - **Rust (edition 2021)**: 启动器开发语言(serde/serde_json、md5、flate2)
453
511
  - **JSON**: 配置文件格式
454
512
  - **ZIP**: 应用程序压缩格式
455
513
 
456
- ## 🔮 未来扩展方向
514
+ ## 未来扩展方向
457
515
 
458
- 1. **GUI界面**:添加图形化配置界面
459
- 2. **数字签名**:支持代码签名和安全验证
460
- 3. **增量更新**:实现应用程序的增量更新功能
461
- 4. **更多平台**:支持macOS等其他操作系统
462
- 5. **插件系统**:允许扩展自定义打包逻辑
516
+ 1. ~~**GUI界面**~~:✅ 已实现 Web GUI 图形化界面(基于 pyquickwebgui)
517
+ 2. ~~**多语言支持**~~:✅ 已实现中英文双语界面,localStorage + 配置文件双持久化
518
+ 3. **数字签名**:支持代码签名和安全验证
519
+ 4. **增量更新**:实现应用程序的增量更新功能
520
+ 5. **更多平台**:支持macOS等其他操作系统
521
+ 6. **插件系统**:允许扩展自定义打包逻辑
463
522
 
464
523
  ## 更新日志
465
524
 
525
+ - 2026-07-11 V 0.2.3
526
+ - 新增 **命令行参数透传**:Rust 启动器自动将命令行参数传递给内部程序
527
+ - 新增 **示例 07**:`07 - hello_world - parameter` 演示参数透传功能(`--add1`、`--add2`)
528
+ - 优化 `package.sh` 脚本:添加错误处理、路径优化、环境检查
529
+
530
+ - 2026-07-07 V 0.2.2
531
+ - 新增 **Web GUI 多语言支持**:支持中文/英文界面实时切换
532
+ - 新增 **语言设置持久化**:使用用户主目录下 `.pyinstallerex/ui_config.json` 配置文件保存语言偏好
533
+
534
+
535
+ - 2026-07-07 V 0.2.1
536
+ - 新增 **Web GUI 图形界面**:不带参数直接运行 `PyInstallerEx` 即可启动
537
+ - 基于 `pyquickwebgui` 实现,支持脚本模式/文件夹模式切换
538
+ - 可视化配置打包参数(引擎、图标、解压模式、输出目录等)
539
+ - 实时日志输出与构建状态轮询
540
+ - 新增 `server.py` 后端服务及 `web/` 前端页面
541
+
466
542
  - 2026-07-03 V 0.1.10
467
543
  - 新增 `--folder` 参数,支持文件夹直接打包模式:跳过引擎构建,直接将指定文件夹压缩并附加到启动器
468
544
  - 新增 `--run` 参数,支持自定义解压后运行的主程序入口(配置 `main` 字段)
@@ -18,6 +18,10 @@ PyInstallerEx 是一个基于 PyInstaller 的增强版打包工具,能够将 P
18
18
  4. **灵活解压模式**:支持解压到系统临时目录或 exe 所在目录(通过 `--extract-mode` 参数控制)
19
19
  5. **跨平台支持**:Windows、Linux x86/ARM全平台覆盖
20
20
  6. **配置灵活**:支持嵌入式配置读取,命令行参数覆盖配置文件
21
+ 7. **命令行参数透传**:打包后的可执行文件支持将命令行参数传递给内部程序
22
+ 8. **Web GUI 界面**:无参数启动时自动打开图形化界面,可视化配置打包参数
23
+ - **多语言支持**:支持中文/英文界面切换,设置持久化保存
24
+ - **文件选择对话框**:原生 tkinter 文件/文件夹选择器,支持初始路径记忆
21
25
 
22
26
  ## 🔧 环境要求
23
27
 
@@ -96,6 +100,26 @@ pip install pyinstallerex
96
100
 
97
101
  ### 基本用法
98
102
 
103
+ #### 启动 Web GUI(图形界面)
104
+
105
+ 直接运行命令,不带任何参数,即可启动 Web GUI 界面:
106
+
107
+ ```bash
108
+ # 以下三种方式均可
109
+ PyInstallerEx
110
+ pyinstallerex
111
+ python -m PyInstallerEx
112
+ ```
113
+
114
+ 启动后会自动打开浏览器窗口,支持:
115
+ - 选择脚本或文件夹打包模式
116
+ - 可视化配置输出名称、版本、引擎、图标等参数
117
+ - 实时查看构建日志和结果
118
+
119
+ #### 命令行模式
120
+
121
+ 带参数时使用命令行模式:
122
+
99
123
  ```bash
100
124
  # 使用 pyinstallerex 命令
101
125
  pyinstallerex your_script.py
@@ -142,6 +166,7 @@ test\test_script.exe # Windows
142
166
  | 04 | `04 - hello_world - PyOxidizer` | 使用 PyOxidizer 引擎打包 | `--engine-mode pyoxidizer` |
143
167
  | 05 | `05 - hello_world - icon` | 自定义 exe 图标(`.ico` 格式) | `--icon "exe.ico"` |
144
168
  | 06 | `06 - hello_world - folder` | 文件夹直接打包,跳过引擎构建,将指定文件夹封装为单文件 | `--folder "hello_folder" --run "hello.exe"` |
169
+ | 07 | `07 - hello_world - parameter` | 命令行参数透传,支持 `--add1` 和 `--add2` 参数进行加法运算 | 无额外打包参数,运行时传参 |
145
170
 
146
171
  > 每个示例均提供 `package.bat`(Windows)和 `package.sh`(Linux/Mac)两套构建脚本。
147
172
 
@@ -191,6 +216,32 @@ python -m PyInstallerEx your_script.py --engine-mode pyoxidizer
191
216
  - **Nuitka**:需要安装 Nuitka (`pip install nuitka`) 和 C 编译器(如 Visual Studio Build Tools)
192
217
  - **PyOxidizer**:需要单独安装 PyOxidizer,详见 [PyOxidizer 文档](https://pyoxidizer.readthedocs.io/)
193
218
 
219
+ ### 命令行参数透传
220
+
221
+ 打包后的可执行文件支持将命令行参数透传给内部程序,无需额外配置:
222
+
223
+ ```bash
224
+ # 打包程序
225
+ python -m PyInstallerEx hello.py -n hello_param
226
+
227
+ # 运行并传递参数
228
+ hello_param.exe --add1 10 --add2 20
229
+ # 输出:Calculation: 10.0 + 20.0 = 30.0
230
+
231
+ # 查看帮助
232
+ hello_param.exe --help
233
+ ```
234
+
235
+ **工作原理**:
236
+ - Rust 启动器在运行内部程序时,自动收集并传递所有命令行参数
237
+ - 支持任意参数格式,完全兼容 `argparse` 等参数解析库
238
+ - 参数透传对所有打包模式(脚本模式、文件夹模式)均有效
239
+
240
+ **使用场景**:
241
+ - 需要接收用户输入的命令行工具
242
+ - 支持配置参数的自动化脚本
243
+ - 需要灵活控制运行时行为的工具程序
244
+
194
245
  ### 文件夹直接打包模式
195
246
 
196
247
  使用 `--folder` 参数跳过 PyInstaller/Nuitka 等引擎打包流程,直接将指定文件夹压缩并附加到 Rust 启动器尾部,生成最终可执行文件。
@@ -293,7 +344,11 @@ py-installer-ex/
293
344
  │ ├── PyInstallerEx/ # Python 主程序
294
345
  │ │ ├── __init__.py
295
346
  │ │ ├── __main__.py # CLI入口点
347
+ │ │ ├── server.py # Web GUI 后端服务
296
348
  │ │ ├── PyInstallerEx.py # 主模块
349
+ │ │ ├── web/
350
+ │ │ │ ├── index.html # Web GUI 前端页面
351
+ │ │ │ └── favicon.ico # 页面图标
297
352
  │ │ ├── core/
298
353
  │ │ │ ├── config.py # 配置管理
299
354
  │ │ │ └── packager.py # 打包逻辑
@@ -399,6 +454,7 @@ script\install.bat
399
454
  - ✅ **智能安装**:首次运行自动提取,后续运行复用已安装版本
400
455
  - ✅ **配置解析**:从可执行文件中读取和处理配置信息
401
456
  - ✅ **临时目录管理**:自动管理临时文件和清理
457
+ - ✅ **命令行参数透传**:自动将启动器的命令行参数传递给内部程序
402
458
 
403
459
  ### 3. 文件夹直接打包
404
460
  - ✅ **`--folder` 参数**:跳过引擎构建,直接将指定文件夹压缩打包
@@ -415,20 +471,39 @@ script\install.bat
415
471
 
416
472
  - **Python 2.7+ / 3.x**: 主要开发语言
417
473
  - **PyInstaller >= 3.2.1**: 应用程序打包基础
474
+ - **pyquickwebgui**: Web GUI 图形界面框架
418
475
  - **Rust (edition 2021)**: 启动器开发语言(serde/serde_json、md5、flate2)
419
476
  - **JSON**: 配置文件格式
420
477
  - **ZIP**: 应用程序压缩格式
421
478
 
422
- ## 🔮 未来扩展方向
479
+ ## 未来扩展方向
423
480
 
424
- 1. **GUI界面**:添加图形化配置界面
425
- 2. **数字签名**:支持代码签名和安全验证
426
- 3. **增量更新**:实现应用程序的增量更新功能
427
- 4. **更多平台**:支持macOS等其他操作系统
428
- 5. **插件系统**:允许扩展自定义打包逻辑
481
+ 1. ~~**GUI界面**~~:✅ 已实现 Web GUI 图形化界面(基于 pyquickwebgui)
482
+ 2. ~~**多语言支持**~~:✅ 已实现中英文双语界面,localStorage + 配置文件双持久化
483
+ 3. **数字签名**:支持代码签名和安全验证
484
+ 4. **增量更新**:实现应用程序的增量更新功能
485
+ 5. **更多平台**:支持macOS等其他操作系统
486
+ 6. **插件系统**:允许扩展自定义打包逻辑
429
487
 
430
488
  ## 更新日志
431
489
 
490
+ - 2026-07-11 V 0.2.3
491
+ - 新增 **命令行参数透传**:Rust 启动器自动将命令行参数传递给内部程序
492
+ - 新增 **示例 07**:`07 - hello_world - parameter` 演示参数透传功能(`--add1`、`--add2`)
493
+ - 优化 `package.sh` 脚本:添加错误处理、路径优化、环境检查
494
+
495
+ - 2026-07-07 V 0.2.2
496
+ - 新增 **Web GUI 多语言支持**:支持中文/英文界面实时切换
497
+ - 新增 **语言设置持久化**:使用用户主目录下 `.pyinstallerex/ui_config.json` 配置文件保存语言偏好
498
+
499
+
500
+ - 2026-07-07 V 0.2.1
501
+ - 新增 **Web GUI 图形界面**:不带参数直接运行 `PyInstallerEx` 即可启动
502
+ - 基于 `pyquickwebgui` 实现,支持脚本模式/文件夹模式切换
503
+ - 可视化配置打包参数(引擎、图标、解压模式、输出目录等)
504
+ - 实时日志输出与构建状态轮询
505
+ - 新增 `server.py` 后端服务及 `web/` 前端页面
506
+
432
507
  - 2026-07-03 V 0.1.10
433
508
  - 新增 `--folder` 参数,支持文件夹直接打包模式:跳过引擎构建,直接将指定文件夹压缩并附加到启动器
434
509
  - 新增 `--run` 参数,支持自定义解压后运行的主程序入口(配置 `main` 字段)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyInstallerEx"
7
- version = "0.1.9"
7
+ version = "0.2.3"
8
8
  description = "扩展PyInstaller 使其拥有单文件安装功能不用每次都解压执行"
9
9
  readme = "README.md"
10
10
  requires-python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@@ -32,6 +32,7 @@ classifiers = [
32
32
  ]
33
33
  dependencies = [
34
34
  "PyInstaller>=3.2.1",
35
+ "pyquickwebgui",
35
36
  ]
36
37
 
37
38
  [project.urls]
@@ -45,4 +46,4 @@ PyInstallerEx = "PyInstallerEx.__main__:main"
45
46
  where = ["src"]
46
47
 
47
48
  [tool.setuptools.package-data]
48
- PyInstallerEx = ["../bin/*"]
49
+ PyInstallerEx = ["../bin/*", "web/*"]
@@ -25,7 +25,7 @@ setup(
25
25
  packages=find_packages(where="src"), # 自动发现src目录下的子包
26
26
  include_package_data=True, # 包含包数据文件
27
27
  package_data={
28
- "PyInstallerEx": ["../bin/*"], # 包含bin目录中的所有文件
28
+ "PyInstallerEx": ["../bin/*", "web/*"], # 包含bin目录中的所有文件及web前端文件
29
29
  },
30
30
  data_files=[
31
31
  ('bin', [
@@ -35,6 +35,7 @@ setup(
35
35
  python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", # 兼容 2.7 和 3.4+
36
36
  install_requires=[ # 依赖列表
37
37
  "PyInstaller>=3.2.1",
38
+ "pyquickwebgui",
38
39
  # Windows平台可选依赖,用于设置exe图标(需要手动安装)
39
40
  # pip install pywin32 或 pip install pefile
40
41
  ],
@@ -46,6 +46,12 @@ def main():
46
46
 
47
47
  args = parser.parse_args()
48
48
 
49
+ # 无任何参数时启动 Web GUI 模式
50
+ if not args.script and not args.folder:
51
+ from .server import start_web_gui
52
+ start_web_gui()
53
+ return
54
+
49
55
  # 设置日志
50
56
  setup_logging(args.verbose)
51
57
 
@@ -55,11 +61,6 @@ def main():
55
61
  print("[FAIL] Error: 'script' and '--folder' are mutually exclusive. Please specify only one.", file=sys.stderr)
56
62
  sys.exit(1)
57
63
 
58
- # 必须提供 script 或 --folder 之一
59
- if not args.script and not args.folder:
60
- print("[FAIL] Error: either 'script' or '--folder' must be specified.", file=sys.stderr)
61
- sys.exit(1)
62
-
63
64
  # --folder 模式校验:目录必须存在
64
65
  if args.folder:
65
66
  if not os.path.isdir(args.folder):
@@ -0,0 +1,291 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ PyInstallerEx Web GUI 服务器
4
+ 基于 pyquickwebgui 提供图形化打包界面
5
+ """
6
+
7
+ from __future__ import print_function
8
+ import os
9
+ import sys
10
+ import json
11
+ import threading
12
+
13
+ from pyquickwebgui import QuikeUI
14
+
15
+ from .core.packager import PackageBuilder
16
+ from .core.config import PackageConfig
17
+ from .utils.logging import setup_logging
18
+
19
+
20
+ # 全局构建状态
21
+ _build_status = {
22
+ "running": False,
23
+ "progress": "",
24
+ "output": "",
25
+ "success": None,
26
+ "log": [],
27
+ }
28
+
29
+ # UI 配置文件路径(存储语言等设置)- 放在用户主目录下
30
+ _user_home = os.path.expanduser('~')
31
+ _ui_config_dir = os.path.join(_user_home, '.pyinstallerex')
32
+ if not os.path.exists(_ui_config_dir):
33
+ try:
34
+ os.makedirs(_ui_config_dir)
35
+ except Exception:
36
+ pass
37
+ _ui_config_file = os.path.join(_ui_config_dir, 'ui_config.json')
38
+
39
+
40
+ def _load_ui_config():
41
+ """加载 UI 配置(语言等)"""
42
+ try:
43
+ if os.path.exists(_ui_config_file):
44
+ with open(_ui_config_file, 'r', encoding='utf-8') as f:
45
+ return json.load(f)
46
+ except Exception:
47
+ pass
48
+ return {"language": "en"}
49
+
50
+
51
+ def _save_ui_config(config):
52
+ """保存 UI 配置"""
53
+ try:
54
+ with open(_ui_config_file, 'w', encoding='utf-8') as f:
55
+ json.dump(config, f, ensure_ascii=False, indent=2)
56
+ except Exception as e:
57
+ print("[PyInstallerEx] Failed to save UI config: {0}".format(e))
58
+
59
+ # 全局 QuikeUI 实例
60
+ _web_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "web")
61
+ qui = QuikeUI(
62
+ web_path=_web_dir,
63
+ index_html="index.html",
64
+ title="PyInstallerEx",
65
+ icon="favicon.ico",
66
+ width=900,
67
+ height=680,
68
+ debug=False,
69
+ )
70
+
71
+
72
+ def _reset_status():
73
+ """重置构建状态"""
74
+ _build_status["running"] = False
75
+ _build_status["progress"] = ""
76
+ _build_status["output"] = ""
77
+ _build_status["success"] = None
78
+ _build_status["log"] = []
79
+
80
+
81
+ def _append_log(msg):
82
+ """追加日志"""
83
+ _build_status["log"].append(msg)
84
+ print(msg)
85
+
86
+
87
+ @qui.expose
88
+ def get_status():
89
+ """获取当前构建状态"""
90
+ return dict(_build_status)
91
+
92
+
93
+ @qui.expose
94
+ def pick_file(initial_dir, file_types):
95
+ """打开文件选择对话框
96
+
97
+ Args:
98
+ initial_dir: 初始目录
99
+ file_types: 文件类型过滤,如 '.py' 或 '.ico'
100
+ """
101
+ try:
102
+ import tkinter as tk
103
+ from tkinter import filedialog
104
+ if initial_dir and os.path.isdir(initial_dir):
105
+ print("[PyInstallerEx] pick_file folder: {0}".format(initial_dir))
106
+ root = tk.Tk()
107
+ root.attributes("-topmost", True)
108
+ root.withdraw()
109
+ ft = [("{0} files".format(file_types), "*{0}".format(file_types)), ("All files", "*.*")]
110
+ result = filedialog.askopenfilename(initialdir=initial_dir, filetypes=ft)
111
+ print("[PyInstallerEx] pick_file result: {0}".format(repr(result)))
112
+ return result if result else ""
113
+ else:
114
+ return 'Not valid folder'
115
+ except Exception as e:
116
+ print("[PyInstallerEx] pick_file error: {0}".format(e))
117
+ return "Error: {0}".format(e)
118
+
119
+
120
+ @qui.expose
121
+ def pick_folder(initial_dir):
122
+ """打开文件夹选择对话框
123
+
124
+ Args:
125
+ initial_dir: 初始目录
126
+ """
127
+ try:
128
+ import tkinter as tk
129
+ from tkinter import filedialog
130
+ if initial_dir and os.path.isdir(initial_dir):
131
+ print("[PyInstallerEx] pick_folder folder: {0}".format(initial_dir))
132
+ root = tk.Tk()
133
+ root.attributes("-topmost", True)
134
+ root.withdraw()
135
+ result = filedialog.askdirectory(initialdir=initial_dir)
136
+ print("[PyInstallerEx] pick_folder result: {0}".format(repr(result)))
137
+ return result if result else ""
138
+ else:
139
+ return 'Not valid folder'
140
+ except Exception as e:
141
+ print("[PyInstallerEx] pick_folder error: {0}".format(e))
142
+ return "Error: {0}".format(e)
143
+
144
+
145
+ @qui.expose
146
+ def start_build(config_json):
147
+ """
148
+ 启动打包构建任务
149
+
150
+ Args:
151
+ config_json: JSON 字符串,包含打包配置
152
+ """
153
+ if _build_status["running"]:
154
+ return {"success": False, "message": "A build task is already running"}
155
+
156
+ _reset_status()
157
+ _build_status["running"] = True
158
+
159
+ try:
160
+ cfg = json.loads(config_json)
161
+ except Exception as e:
162
+ _build_status["running"] = False
163
+ return {"success": False, "message": "Invalid config JSON: {0}".format(e)}
164
+
165
+ def _run_build():
166
+ try:
167
+ _append_log("[INFO] Starting build...")
168
+ _build_status["progress"] = "Initializing..."
169
+
170
+ # 构建 PackageConfig
171
+ config = PackageConfig()
172
+ config.filename = cfg.get("filename", "{filename}")
173
+ config.version = cfg.get("version", "1.0.0")
174
+ config.description = cfg.get("description", "")
175
+ config.author = cfg.get("author", "Unknown")
176
+ config.extract_mode = cfg.get("extract_mode", "temp")
177
+ config.engine_mode = cfg.get("engine_mode", "pyinstaller")
178
+ config.main = cfg.get("main", None)
179
+
180
+ # 图标处理
181
+ icon_path = cfg.get("icon", None)
182
+ if icon_path and os.path.exists(icon_path):
183
+ config.icon = icon_path
184
+ else:
185
+ default_icon = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logo.ico")
186
+ if os.path.exists(default_icon):
187
+ config.icon = default_icon
188
+ else:
189
+ config.icon = None
190
+
191
+ # 设置日志级别
192
+ verbose = cfg.get("verbose", False)
193
+ setup_logging(verbose)
194
+
195
+ builder = PackageBuilder(config, verbose=verbose)
196
+ output_dir = cfg.get("output_dir", None) or None
197
+
198
+ # 文件夹模式 or 脚本模式
199
+ folder_path = cfg.get("folder", None)
200
+ script_path = cfg.get("script", None)
201
+
202
+ if folder_path:
203
+ _build_status["progress"] = "Packaging folder..."
204
+ if not os.path.isdir(folder_path):
205
+ raise ValueError("Folder not found: {0}".format(folder_path))
206
+
207
+ if cfg.get("name"):
208
+ config.filename = cfg["name"]
209
+ elif config.filename == "{filename}":
210
+ config.filename = os.path.basename(folder_path)
211
+
212
+ result_path = builder.build_folder(folder_path, output_dir)
213
+ elif script_path:
214
+ _build_status["progress"] = "Packaging script..."
215
+ if not os.path.isfile(script_path):
216
+ raise ValueError("Script not found: {0}".format(script_path))
217
+
218
+ if cfg.get("name"):
219
+ config.filename = cfg["name"]
220
+ elif config.filename == "{filename}":
221
+ config.filename = os.path.splitext(os.path.basename(script_path))[0]
222
+
223
+ result_path = builder.build(script_path, output_dir)
224
+ else:
225
+ raise ValueError("Either 'script' or 'folder' must be specified")
226
+
227
+ _build_status["progress"] = "Done"
228
+ _build_status["output"] = result_path
229
+ _build_status["success"] = True
230
+ _append_log("[OK] Build completed: {0}".format(result_path))
231
+
232
+ except Exception as e:
233
+ _build_status["progress"] = "Failed"
234
+ _build_status["success"] = False
235
+ _build_status["output"] = str(e)
236
+ _append_log("[FAIL] Build failed: {0}".format(e))
237
+ finally:
238
+ _build_status["running"] = False
239
+
240
+ # 在后台线程执行构建
241
+ t = threading.Thread(target=_run_build)
242
+ t.daemon = True
243
+ t.start()
244
+
245
+ return {"success": True, "message": "Build started"}
246
+
247
+
248
+ @qui.expose
249
+ def get_default_config():
250
+ """获取默认配置模板"""
251
+ default_icon = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logo.ico")
252
+ ui_config = _load_ui_config()
253
+ return {
254
+ "filename": "{filename}",
255
+ "version": "1.0.0",
256
+ "description": "Application packaged with PyInstallerEx",
257
+ "author": "Unknown",
258
+ "extract_mode": "temp",
259
+ "engine_mode": "pyinstaller",
260
+ "icon": default_icon if os.path.exists(default_icon) else "",
261
+ "output_dir": "",
262
+ "verbose": False,
263
+ "language": ui_config.get("language", "en"),
264
+ }
265
+
266
+
267
+ @qui.expose
268
+ def set_language(lang):
269
+ """设置界面语言并保存到配置文件
270
+
271
+ Args:
272
+ lang: 'en' or 'cn'
273
+ """
274
+ if lang not in ('en', 'cn'):
275
+ return {"success": False, "message": "Invalid language: {0}".format(lang)}
276
+
277
+ ui_config = _load_ui_config()
278
+ ui_config["language"] = lang
279
+ _save_ui_config(ui_config)
280
+ print("[PyInstallerEx] Language saved: {0}".format(lang))
281
+ return {"success": True, "language": lang}
282
+
283
+
284
+ def start_web_gui():
285
+ """启动 Web GUI"""
286
+ print("[PyInstallerEx] Starting Web GUI...")
287
+ qui.run()
288
+
289
+
290
+ if __name__ == "__main__":
291
+ start_web_gui()