Metadata-Version: 2.4
Name: PyInstallerEx
Version: 0.1.9
Summary: 扩展PyInstaller 使其拥有单文件安装功能不用每次都解压执行
Home-page: https://gitee.com/iiixxxiii/py-installer-ex
Author: lixin
Author-email: lixin <iiixxxiii@qq.com>
License-Expression: MIT
Project-URL: Homepage, https://gitee.com/iiixxxiii/py-installer-ex
Keywords: PyInstaller,expand,single-file,installer
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyInstaller>=3.2.1
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# PyInstallerEx

增强版 PyInstaller 打包工具，可创建具有安装功能的单文件可执行程序

## 🎯 项目概述

PyInstallerEx 是一个基于 PyInstaller 的增强版打包工具，能够将 Python 应用程序打包成具有安装功能的单文件可执行程序。与传统的 PyInstaller 创建独立可执行文件不同，PyInstallerEx 创建的安装程序可执行文件具有以下特点：

- **首次运行时提取**：应用程序被提取到临时目录
- **重复使用已安装版本**：后续运行使用已经提取的版本
- **自动清理**：智能管理临时文件

## 🌟 特色功能

1. **单文件分发**：单个可执行文件包含完整应用程序
2. **自动安装**：首次运行时自动提取到临时目录
3. **智能缓存**：后续运行直接使用已安装版本，自动清理旧缓存（基于 `ex_{filename}_{md5}` 目录模式）
4. **灵活解压模式**：支持解压到系统临时目录或 exe 所在目录（通过 `--extract-mode` 参数控制）
5. **跨平台支持**：Windows、Linux x86/ARM全平台覆盖
6. **配置灵活**：支持嵌入式配置读取，命令行参数覆盖配置文件

## 🔧 环境要求

### Python
- Python >= 2.7（推荐 Python 3.8+）
- 确保 Python 已添加到系统 PATH

### Rust（仅当需要重新构建启动器时）
- Rust >= 1.70
- 下载地址: https://rustup.rs/

> **注意**: 项目已包含预编译的启动器文件 (`bin/launcher_windows.exe`)，大多数情况下不需要重新构建。

### ⚙️ 工作原理

1. **PyInstaller 打包**：使用 PyInstaller 的 `--onedir` 模式创建完整的应用程序目录
2. **配置处理**：应用用户配置并生成元数据
3. **压缩**：将应用程序目录压缩为 ZIP 文件
4. **二进制合并**：将平台特定的启动器二进制文件与 ZIP 文件合并
5. **最终可执行文件**：创建一个处理提取和执行的单个可执行文件

## 🚀 快速开始

### Windows 用户

#### 方式一：一键安装（推荐）

```bash
# 在项目根目录运行
script\install.bat
```

这将自动完成：
- 创建虚拟环境 `.venv`
- 安装所有依赖
- 验证安装

#### 方式二：手动安装

```bash
# 1. 创建并激活虚拟环境
python -m venv .venv
.venv\Scripts\Activate.ps1  # PowerShell
# 或
.venv\Scripts\activate.bat   # CMD

# 2. 安装项目
pip install -e .

# 3. (可选)构建启动器(如果 bin/launcher_windows.exe 不存在)
script\build_launchers.bat
```

### Linux/Mac 用户

```bash
# 1. 创建并激活虚拟环境
python -m venv .venv
source .venv/bin/activate

# 2. 安装项目
pip install -e .

# 3. (可选)构建启动器
bash build_launchers.sh
```

## 📦 安装

从 PyPI 安装最新版本：
```bash
pip install pyinstallerex
```

## 📖 使用方法

### 基本用法

```bash
# 使用 pyinstallerex 命令
pyinstallerex your_script.py

# 使用 PyInstallerEx 命令
PyInstallerEx your_script.py

# 使用 Python -m 方法（推荐）
python -m PyInstallerEx your_script.py
```

### 使用配置文件

```bash
python -m PyInstallerEx your_script.py --cfg config.json
```

### 查看帮助

```bash
python -m PyInstallerEx --help
```

### 示例

```bash
# 测试打包
python -m PyInstallerEx test\test_script.py --cfg test\test_config.json

# 运行生成的可执行文件
test\test_script.exe  # Windows
./test/test_script    # Linux/Mac
```

### 示例项目

项目 `examples/` 目录下提供了多个示例，帮助快速上手各种打包模式：

| 序号 | 示例目录 | 演示功能 | 核心参数 |
|------|---------|---------|----------|
| 01 | `01 - hello_world` | 最基础打包，使用默认 PyInstaller 引擎 | 无额外参数 |
| 02 | `02 - hello_world - local` | 使用 `local` 解压模式，文件释放到 exe 同级目录 | `--extract-mode local` |
| 03 | `03 - hello_world - Nuitka` | 使用 Nuitka 编译引擎打包 | `--engine-mode nuitka` |
| 04 | `04 - hello_world - PyOxidizer` | 使用 PyOxidizer 引擎打包 | `--engine-mode pyoxidizer` |
| 05 | `05 - hello_world - icon` | 自定义 exe 图标（`.ico` 格式） | `--icon "exe.ico"` |
| 06 | `06 - hello_world - folder` | 文件夹直接打包，跳过引擎构建，将指定文件夹封装为单文件 | `--folder "hello_folder" --run "hello.exe"` |

> 每个示例均提供 `package.bat`（Windows）和 `package.sh`（Linux/Mac）两套构建脚本。

### 解压模式

PyInstallerEx 支持两种解压模式，通过 `--extract-mode` 参数控制：

| 模式 | 说明 | 解压路径 |
|------|------|----------|
| `temp`（默认） | 解压到系统临时目录 | `%TEMP%\ex_{filename}_{md5}` (Windows) 或 `/tmp/ex_{filename}_{md5}` (Linux) |
| `local` | 解压到 exe 所在目录 | `{exe所在目录}\{exe_stem}_release\` |

```bash
# 默认模式（解压到临时目录）
python -m PyInstallerEx your_script.py

# 本地模式（解压到 exe 所在目录）
python -m PyInstallerEx your_script.py --extract-mode local
```

**使用场景**：
- **temp 模式**：适合分发安装程序，避免污染用户目录
- **local 模式**：适合绿色便携版，所有文件集中在 exe 同级目录

### 打包引擎选择

PyInstallerEx 支持多种打包引擎，通过 `--engine-mode` 参数切换：

| 引擎 | 说明 | 依赖 |
|------|------|------|
| `pyinstaller`（默认） | 使用 PyInstaller 打包 | PyInstaller |
| `nuitka` | 使用 Nuitka 编译为 C 代码 | Nuitka, C编译器 |
| `pyoxidizer` | 使用 PyOxidizer 打包 | PyOxidizer |

```bash
# 默认使用 PyInstaller
python -m PyInstallerEx your_script.py

# 使用 Nuitka
python -m PyInstallerEx your_script.py --engine-mode nuitka

# 使用 PyOxidizer
python -m PyInstallerEx your_script.py --engine-mode pyoxidizer
```

**注意事项**：
- **Nuitka**：需要安装 Nuitka (`pip install nuitka`) 和 C 编译器（如 Visual Studio Build Tools）
- **PyOxidizer**：需要单独安装 PyOxidizer，详见 [PyOxidizer 文档](https://pyoxidizer.readthedocs.io/)

### 文件夹直接打包模式

使用 `--folder` 参数跳过 PyInstaller/Nuitka 等引擎打包流程，直接将指定文件夹压缩并附加到 Rust 启动器尾部，生成最终可执行文件。

```bash
# 将本地文件夹直接打包
python -m PyInstallerEx --folder ./my_app

# 指定输出文件名
python -m PyInstallerEx --folder ./my_app -n MyApp

# 指定解压后运行的主程序入口
python -m PyInstallerEx --folder ./my_app --run my_app.exe

# 指定运行子目录中的程序
python -m PyInstallerEx --folder ./my_app --run bin/start.exe
```

**参数说明**：

| 参数 | 说明 |
|------|------|
| `--folder <path>` | 指定要打包的本地文件夹路径（与 `script` 互斥） |
| `--run <entry>` | 指定解压后运行的主程序文件名或相对路径（写入配置 `main` 字段） |

**注意事项**：
- `--folder` 与位置参数 `script` 互斥，不能同时使用
- `--folder` 指定的路径必须存在且为有效目录
- 不指定 `--run` 时，默认以文件夹名作为主程序名（Windows 自动添加 `.exe` 后缀）
- 支持与其他参数组合使用，如 `--icon`、`--extract-mode`、`--cfg` 等

**使用场景**：
- 已有编译好的程序目录，只需封装为单文件安装器
- 打包非 Python 项目（如 Node.js、Go 等编译产物）
- 需要精确控制打包内容，跳过引擎构建步骤

### 自定义图标

使用 `--icon` 参数为生成的可执行文件添加图标：

```bash
# 使用自定义图标（必须是 .ico 格式）
python -m PyInstallerEx your_script.py --icon my_icon.ico

# 使用默认图标（如果存在 src/PyInstallerEx/logo.ico）
python -m PyInstallerEx your_script.py
```

**重要提示**：
- ⚠️ **图标文件必须是 `.ico` 格式**，不支持 `.png`、`.jpg` 等其他格式
- ⚠️ 如果指定的图标文件不存在或格式不正确，会输出警告并跳过图标设置
- 💡 可以使用在线工具将 PNG/JPG 转换为 ICO 格式（如 https://convertio.co/png-ico/）

**技术说明**：
- **Windows 平台图标设置方式**：PyInstallerEx 使用 `win32api.UpdateResource` API 在合并 ZIP 数据之前对纯启动器 exe 设置图标，避免破坏附加的 ZIP 数据和配置 JSON
- **自动检测与嵌入**：打包时自动检测图标参数，使用 pywin32 库直接修改 PE 文件的 RT_ICON 和 RT_GROUP_ICON 资源段
- **ICO 文件格式解析**：严格按照 Windows ICO 格式规范解析图像入口（`BBBBHHII` 格式），提取原始 DIB 图像数据写入资源段



## 🛠 开发

### 从源码构建

```bash
# 开发测试安装
pip install -e .

# 使用传统setup.py构建包
python setup.py sdist bdist_wheel

# 构建Rust启动器
./build_launchers.sh          # Linux/Mac
build_launchers.bat           # Windows
```

### 测试

```bash
# 运行测试套件
python test/test_rust_launcher.py

# 测试打包
python -m PyInstallerEx test/test_script.py --cfg test/test_config.json

# 运行生成的可执行文件
test/test_script.exe  # Windows
./test/test_script    # Linux/Mac
```

## 📁 项目文件结构

```
py-installer-ex/
├── bin/                          # 预编译的启动器
│   ├── launcher_windows.exe      # Windows 启动器 (64-bit)
│   ├── launcher_linux_x86        # Linux x86 启动器 (64-bit)
│   └── launcher_linux_arm        # Linux ARM 启动器 (64-bit)
├── src/
│   ├── PyInstallerEx/            # Python 主程序
│   │   ├── __init__.py
│   │   ├── __main__.py           # CLI入口点
│   │   ├── PyInstallerEx.py      # 主模块
│   │   ├── core/
│   │   │   ├── config.py         # 配置管理
│   │   │   └── packager.py       # 打包逻辑
│   │   └── utils/
│   │       ├── compression.py    # 压缩工具
│   │       ├── file_utils.py     # 文件操作
│   │       ├── logging.py        # 日志处理
│   │       └── system_utils.py   # 系统检测
│   └── launcher/                 # Rust 启动器源码
│       ├── src/main.rs           # 启动器主程序
│       ├── Cargo.toml            # Cargo配置
│       └── Cargo.lock
├── script/                       # 安装和构建脚本
│   ├── install.bat               # Windows 安装脚本
│   ├── build_launchers.bat       # Windows 启动器构建
│   └── build_launchers.sh        # Linux/Mac 启动器构建
├── test/                         # 测试用例
│   ├── test_script.py
│   ├── test_config.json
│   ├── test_rust_launcher.py
│   └── test_python27_compatibility.py
├── build_launchers.bat           # 启动器构建脚本(Windows)
├── build_launchers.sh            # 启动器构建脚本(Linux/Mac)
├── pyproject.toml
├── setup.py
└── README.md
```

## 🔧 常见问题

### Q: 找不到 `launcher_windows.exe`?

**A**: 确保 `bin/` 目录下存在该文件。如果不存在:
1. 检查是否从 Git 克隆时遗漏了 `bin/` 目录
2. 或运行 `script\build_launchers.bat` 重新构建（需要安装 Rust）

### Q: Python 版本要求?

**A**: 
- 最低支持: Python 2.7
- 推荐使用: Python 3.8+

### Q: linux 版本要求?

**A**: 
- 最低支持: CentOS-9
- 推荐使用: CentOS-9 以上版本

### Q: 需要安装 Rust 吗?

**A**: 
- **不需要**: 项目已包含预编译的启动器 (`bin/launcher_windows.exe`)
- **需要**: 仅当你想修改或重新构建启动器时

### Q: 如何清理虚拟环境?

**A**: 
```bash
# Windows
rmdir /s /q .venv

# Linux/Mac
rm -rf .venv
```

### Q: PowerShell 无法激活虚拟环境?

**A**: 执行以下命令后重试：
```powershell
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
```

## 🔄 CI/CD 集成

在 CI/CD 环境中，可以使用环境变量跳过交互提示：

```bash
# 设置环境变量跳过交互确认
set CI=true

# 运行安装脚本
script\install.bat
```

## 📊 测试结果

- ✅ 打包流程测试通过
- ✅ 生成的安装器可正常执行
- ✅ 跨平台启动器编译成功
- ✅ 配置系统工作正常
- ✅ 错误处理机制完善

## ✅ 已完成的功能

### 1. 核心打包功能
- ✅ **PyInstaller集成**：使用 `--onedir` 模式创建完整的应用程序目录
- ✅ **配置系统**：JSON格式的配置文件支持
- ✅ **ZIP压缩**：将应用程序目录压缩为ZIP文件
- ✅ **二进制合并**：将Rust启动器与ZIP文件合并为最终可执行文件

### 2. Rust启动器实现
- ✅ **跨平台支持**：Windows、Linux x86、Linux ARM
- ✅ **智能安装**：首次运行自动提取，后续运行复用已安装版本
- ✅ **配置解析**：从可执行文件中读取和处理配置信息
- ✅ **临时目录管理**：自动管理临时文件和清理

### 3. 文件夹直接打包
- ✅ **`--folder` 参数**：跳过引擎构建，直接将指定文件夹压缩打包
- ✅ **`--run` 参数**：自定义解压后运行的主程序入口
- ✅ **互斥校验**：`--folder` 与 `script` 位置参数互斥处理

### 4. 项目结构完善
- ✅ **模块化设计**：清晰的代码组织结构
- ✅ **错误处理**：完善的异常处理和日志记录
- ✅ **构建脚本**：自动化编译和测试脚本
- ✅ **文档完整**：详细的使用说明和API文档

## 🔧 技术栈

- **Python 2.7+ / 3.x**: 主要开发语言
- **PyInstaller >= 3.2.1**: 应用程序打包基础
- **Rust (edition 2021)**: 启动器开发语言（serde/serde_json、md5、flate2）
- **JSON**: 配置文件格式
- **ZIP**: 应用程序压缩格式

## 🔮 未来扩展方向

1. **GUI界面**：添加图形化配置界面
2. **数字签名**：支持代码签名和安全验证
3. **增量更新**：实现应用程序的增量更新功能
4. **更多平台**：支持macOS等其他操作系统
5. **插件系统**：允许扩展自定义打包逻辑

##  更新日志

- 2026-07-03 V 0.1.10
  - 新增 `--folder` 参数，支持文件夹直接打包模式：跳过引擎构建，直接将指定文件夹压缩并附加到启动器
  - 新增 `--run` 参数，支持自定义解压后运行的主程序入口（配置 `main` 字段）
  - 新增参数互斥校验：`--folder` 与 `script` 位置参数不能同时使用
  - 支持将非 Python 项目（如编译产物）封装为单文件安装器

- 2026-07-02 V 0.1.9
  - 新增 `--engine-mode` 参数，支持选择打包引擎：`pyinstaller`（默认）、`nuitka`、`pyoxidizer`
  - 新增 `--icon` 参数，支持自定义可执行文件图标（仅支持 `.ico` 格式）
  - 增强图标参数校验：检查文件是否存在、验证文件格式，无效时输出警告
  - **新增 ZIP 数据 MD5 完整性校验**：打包时计算 ZIP 数据的 MD5 哈希值并写入配置，运行时 Rust 启动器自动校验，防止数据损坏
  - 更新 Nuitka 示例脚本，添加 `--engine-mode nuitka` 参数

- 2026-07-01 V 0.1.8
  - 新增 `--extract-mode` 参数，支持选择解压到系统临时目录（`temp`）或 exe 所在目录（`local`）
  - 修复相对路径下 `output_dir` 为空导致的打包失败问题

- 2026-06-30 V 0.1.7
  - 将启动器从 Go 重写为 Rust，减小体积并提升性能
  - 修复临时目录缓存问题，使用 exe 内容哈希标识版本，内容变化时自动重新解压
  - 修复 PyInstaller 调用方式，使用 `sys.executable -m PyInstaller` 替代直接命令
  - 修复 Windows 终端下 emoji 字符编码导致的 GBK 输出错误
  - 修复 `setup.py` 中 `data_files` 引用不存在文件导致构建失败的问题

- 2025-11-07 V 0.1.6
  - 修复了包分发中缺少启动器二进制文件的问题
  - 改进了启动器文件搜索逻辑以支持包数据资源
  - 增强了跨平台兼容性

- 2025-11-06 V 0.1.5
  - 更新文档，包含最新版本信息和更新日志

- 2025-11-06 V 0.1.4
  - 修复了Linux系统上找不到启动器文件的问题
  - 改进了启动器文件搜索逻辑以支持通过data_files安装的文件
  - 增强了跨平台兼容性

- 2025-11-06 V 0.1.3
  - 修复了包分发问题，确保启动器二进制文件正确包含
  - 改进了包构建和安装过程

- 2025-11-06 V 0.1.2
  - 增强了缓存管理，自动清理旧目录
  - 改进了配置处理，支持嵌入式配置读取
  - 添加了对Linux ARM64平台的支持
  - 添加了指定输出文件名的命令行选项

- 2025-10-23 V 0.1.1
  - 初始版本，实现临时文件安装功能
  - 完整的Rust启动器实现
  - 跨平台支持（Windows、Linux x86/ARM）
  - 配置系统
  - 自动化构建脚本

## 📄 许可证

MIT许可证 - 详见 LICENSE 文件

---

**项目状态**：✅ 已完成核心功能开发
**测试状态**：✅ 功能测试通过
**文档状态**：✅ 文档完整可用
