Metadata-Version: 2.4
Name: winpkgmaker
Version: 0.1.0
Summary: 把任意 Python 项目打包成 Windows 安装器；运行时与代码分离，目标机无需 Python
Author: PyDeploy Contributors
License: MIT License
        
        Copyright (c) 2026 PyDeploy contributors
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/pydeploy/pydeploy
Project-URL: Issues, https://github.com/pydeploy/pydeploy/issues
Keywords: pyinstaller,package,windows,installer,deploy,distribution
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: native
Requires-Dist: cython>=3.0; extra == "native"
Requires-Dist: setuptools>=68; extra == "native"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# PyDeploy —— 把任意 Python 项目打包成 Windows 安装器

PyDeploy 是一个**独立于任何 Python 项目**的打包工具。只要在项目里放一个
`pydeploy.toml` 配置文件，就能在开发机上把项目打包成两个安装器，目标机
**不需要安装 Python**。

| 产物 | 内容 | 大小 | 安装次数 |
| --- | --- | --- | --- |
| `runtime-setup-<python>-<arch>.exe` | Python 运行时 | 约 23 MB（slim 裁剪后） | 每台目标机装 **一次** |
| `<应用id>-<版本>-setup.exe` | 项目代码 + 项目依赖 | 几 MB ~ 几十 MB | 每个项目装一次 |

运行时与项目代码分离打包：目标机只装一次 Python 运行时，之后每装一个新项目
只需拷贝几 MB 到几十 MB 的小安装器。

## 目录

- [快速开始](#快速开始)
- [命令详解](#命令详解)
- [pydeploy.toml 参数参考](#pydeploytoml-参数参考)
- [构建产物](#构建产物)
- [目标机安装与卸载](#目标机安装与卸载)
- [环境变量](#环境变量)
- [常见使用场景](#常见使用场景)
- [开发与测试](#开发与测试)

## 快速开始

### 1. 安装工具（二选一）

直接用仓库里的包装脚本（无需安装）：

```bat
C:\Code\package-py\pydeploy.cmd --help
```

或者安装进 Python 环境后使用 `pydeploy` 命令：

```bat
python -m pip install C:\Code\package-py
pydeploy --help
```

### 2. 在项目里生成配置

```bat
cd C:\Code\FCBOP

:: 生成 pydeploy.toml（参数含义见下文「命令详解」）
C:\Code\package-py\pydeploy.cmd init --name "TRV Calculator" ^
    --entry trv_calculator.py --requirements requirements.txt ^
    --include trv_calculator.py --include data
```

### 3. 查看配置与预览打包内容

```bat
C:\Code\package-py\pydeploy.cmd info      :: 查看配置摘要
C:\Code\package-py\pydeploy.cmd files     :: 预览最终会打包的每个文件
C:\Code\package-py\pydeploy.cmd doctor    :: 检查本机打包工具链
```

### 4. 构建运行时安装器（每台目标机只装一次）

```bat
:: 首次约 12~60 秒（复制并压缩本机 Python）；之后会命中缓存，秒级完成
C:\Code\package-py\pydeploy.cmd runtime-build
```

### 5. 构建应用安装器

```bat
:: 自动下载目标平台依赖 wheel，需要开发机联网
C:\Code\package-py\pydeploy.cmd build

:: 可选：构建后自动安装到临时目录并启动入口验证
C:\Code\package-py\pydeploy.cmd build --smoke
```

所有命令都支持 `--project <项目目录>` 指定目标项目（默认当前目录）。

## 命令详解

### `pydeploy init` —— 生成 `pydeploy.toml`

| 参数 | 默认值 | 含义 |
| --- | --- | --- |
| `--project <目录>` | `.` | 项目目录 |
| `--name <名称>` | `myapp` | 应用显示名称：用于快捷方式、开始菜单、安装器文件属性 |
| `--id <id>` | 由 name 生成 | 安装目录 id；默认把 name 转小写、非字母数字替换为 `-`。**中文名建议显式指定 ASCII id** |
| `--version <版本>` | `1.0.0` | 应用版本，参与产物名 `<id>-<version>-setup.exe` |
| `--entry <文件>` | `main.py` | 入口脚本，相对项目根；必须被 `include` 覆盖，否则构建报错 |
| `--gui` / `--console` | 控制台 | GUI 应用用 `--gui`（快捷方式指向 `pythonw.exe`，无黑色控制台窗口） |
| `--requirements <文件>` | 无 | 依赖文件路径，如 `requirements.txt` |
| `--icon <文件>` | 无 | `.ico` 图标：嵌入安装器 exe 并用于快捷方式；文件缺失会构建报错 |
| `--description <描述>` | 同 name | 应用描述（快捷方式提示、安装器属性） |
| `--include <路径>` | 整个项目 | 要打包的文件/目录，可多次指定；`"."` 表示整个项目内容 |
| `--compile` / `--no-compile` | 不编译 | 编译为 `.pyc` 并删除源码（目标机看不到明文代码） |
| `--native` / `--no-native` | 不启用 | 用 Cython + MSVC 编译为原生 `.pyd`（更强保护，构建机需额外工具） |
| `--force` | 否 | 覆盖已存在的 `pydeploy.toml` |

### `pydeploy doctor` —— 检查工具链

检查 Python 版本、pip、`csc.exe`（.NET Framework 编译器）、`tar`、PowerShell。

| 参数 | 含义 |
| --- | --- |
| `--project <目录>` | 可选：额外校验该项目的配置（compile 模式 Python 版本一致、native 依赖 Cython/MSVC、icon/入口/依赖文件存在） |

### `pydeploy info` —— 查看配置摘要

读取并打印 `pydeploy.toml` 的关键配置，方便确认无误再构建。支持 `--project`。

### `pydeploy files` —— 预览打包文件

列出最终会进包的每个文件、总数与总大小，并提示入口是否在打包范围内。支持 `--project`。
与实际打包共用同一套 include/exclude 过滤逻辑，预览结果即打包结果。

### `pydeploy runtime-build` —— 构建运行时安装器

| 参数 | 默认值 | 含义 |
| --- | --- | --- |
| `--project <目录>` | `.` | 项目目录 |
| `--from <来源>` | 配置的 `source` | `local`=复制本机 Python；`embed`=从 python.org 下载嵌入式版（更小但需联网） |
| `--python <版本>` | 配置的 `python` | 覆盖目标 Python 版本，如 `3.11` |
| `--refresh` | 否 | 忽略缓存，强制重新打包运行时 |
| `--output <目录>` | 配置的 `output` | 产物输出目录 |

产物有缓存（`.pydeploy-cache/runtime/<rid>/`）：同一版本、同一来源、配置未变化时
直接复用，第二次构建秒级完成。

### `pydeploy build` —— 构建应用安装器

| 参数 | 含义 |
| --- | --- |
| `--project <目录>` | 项目目录 |
| `--output <目录>` | 产物输出目录（默认配置的 `output`，即 `dist`） |
| `--compile` / `--no-compile` | 覆盖配置：编译为 `.pyc` / 保留源码 |
| `--native` / `--no-native` | 覆盖配置：原生 `.pyd` 编译 / 关闭 |
| `--version <版本>` | 覆盖应用版本（影响产物名与 manifest） |
| `--dry-run` | 只预览打包文件列表，不实际构建（等价于 `pydeploy files`） |
| `--smoke` | 构建后自动把 runtime + app 安装器装进临时目录、启动入口验证；缺运行时安装器时自动先构建 |

## pydeploy.toml 参数参考

用 `pydeploy init` 生成后按需修改。完整示例：

```toml
[app]
name = "TRV Calculator"        # 显示名称
id = ""                        # 安装目录 id（默认由 name 生成；中文名建议显式指定）
version = "1.0.0"              # 应用版本
entry = "trv_calculator.py"    # 入口脚本，相对项目根
gui = false                    # true=GUI 应用（用 pythonw，无黑窗）
description = ""               # 应用描述
icon = "icon.ico"              # 图标 .ico（缺失会构建报错）

[files]
include = ["trv_calculator.py", "data"]   # 要打包的文件/目录；"."=整个项目
exclude = ["__pycache__", "*.pyc", ".git", "results"]  # 排除项，支持通配符

[deps]
requirements = "requirements.txt"  # 依赖文件（可选）
packages = ["requests==2.31.0"]    # 直接写的依赖（可选）
wheels_dir = ""                    # 本地 wheel 目录（离线构建，需含全部传递依赖）

[runtime]
python = "3.13"              # 目标 Python 版本；compile 模式必须与构建机一致
arch = "x64"                 # 架构：x64 / win32
source = "local"             # local=复制本机 Python；embed=下载 python.org 嵌入式版
python_dir = ""              # source=local 时的 Python 安装目录；留空用当前 Python
slim = true                  # true=裁剪 pip/setuptools/wheel，运行时更小（默认）
common_deps = []             # 公共依赖：装入运行时，所有项目共享

[build]
output = "dist"              # 产物输出目录（相对项目根）
compile = false              # true=编译为 .pyc 并删除源码
native = false               # true=用 Cython+MSVC 编译为原生 .pyd
```

### `[app]` 字段

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `name` | string | `myapp` | 显示名称，用于快捷方式、开始菜单、安装器文件属性 |
| `id` | string | 由 name 生成 | 安装目录 id（小写，非字母数字替换为 `-`）；**中文名建议显式指定 ASCII** |
| `version` | string | `1.0.0` | 应用版本，参与产物名 |
| `entry` | string | `main.py` | 入口脚本，相对项目根，必须被 include 覆盖 |
| `gui` | bool | `false` | GUI 应用用 `pythonw.exe` 启动，无黑色控制台窗口 |
| `description` | string | `""` | 应用描述 |
| `icon` | string | `""` | `.ico` 图标路径；缺失会构建报错 |

### `[files]` 字段

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `include` | list | `["."]` | 要打包的文件/目录；`"."` = 整个项目内容；目录会保留其名字 |
| `exclude` | list | 常见项 | 排除项，支持 `fnmatch` 通配符（`*.pyc`、`data*` 等）；默认已含 `__pycache__`、`*.pyc`、`.git`、`.venv`、`dist`、`build`、`.idea`、`.vscode`、`.pydeploy-build`、`*.log` 等 |

### `[deps]` 字段

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `requirements` | string | `""` | 依赖文件路径（相对项目根） |
| `packages` | list | `[]` | 直接写的依赖，如 `["requests==2.31.0"]` |
| `wheels_dir` | string | `""` | 本地 wheel 目录；设置后改为离线构建（`pip --no-index --find-links`），**需包含全部传递依赖**，且必须是 Windows 平台 wheel |

### `[runtime]` 字段

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `python` | string | 构建机版本 | 目标 Python 版本（如 `3.13`）；**compile 模式必须与构建机一致**，否则 `.pyc` 无法运行 |
| `arch` | string | `x64` | 架构：`x64` / `win32` |
| `source` | string | `local` | `local`=复制本机 Python；`embed`=从 python.org 下载嵌入式版（更小、需联网） |
| `python_dir` | string | `""` | `source=local` 时指定 Python 安装目录；留空自动使用运行 pydeploy 的 Python |
| `slim` | bool | `true` | 裁剪 pip/setuptools/wheel（约省 3 MB 压缩体积）；极少数依赖 `pkg_resources` 的应用可设 `false` |
| `common_deps` | list | `[]` | 公共依赖：构建时装进运行时，所有项目共享 |

### `[build]` 字段

| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `output` | string | `dist` | 产物输出目录（相对项目根） |
| `compile` | bool | `false` | 编译为 `.pyc` 并删除源码 |
| `native` | bool | `false` | 用 Cython + MSVC 编译为原生 `.pyd`（需构建机安装 Cython 与 VS Build Tools） |

## 构建产物

```text
dist\
  runtime-setup-3.13-x64.exe        运行时安装器（每台目标机装一次）
  runtime-setup-3.13-x64.exe.sha256 安装器 SHA-256 校验和
  runtime-3.13-x64.zip              运行时原始包（备用）
  runtime-3.13-x64.zip.sha256       校验和
  trv-calculator-1.0.0-setup.exe    应用安装器
  trv-calculator-1.0.0-setup.exe.sha256  校验和
```

安装器 exe 自带应用名称、版本与图标（配置了 `icon` 时），可在资源管理器
「属性 → 详细信息」中查看；`.sha256` 文件用于校验下载完整性。

## 目标机安装与卸载

目标机要求：**Windows 7+**、.NET Framework 4.x（Win10/11 自带）、无需 Python。
解压优先用系统自带 `tar`，不可用时自动回退 PowerShell `Expand-Archive`。

1. 把 `runtime-setup-<版本>.exe` 拷贝到目标机，双击运行（每台机器只做一次）。
2. 把 `<应用>-<版本>-setup.exe` 拷贝到目标机，双击运行。
   - 若未安装运行时：把 `runtime-setup-*.exe` 放在它同目录下，会自动先装运行时；
   - 安装器会校验目标机运行时的版本与所需一致，不匹配会明确报错并提示安装对应版本。
3. 安装完成自动创建桌面快捷方式和开始菜单快捷方式（含「卸载」）。

安装位置（默认）：

```text
%LOCALAPPDATA%\PyDeploy\
  runtimes\3.13-x64\          Python 运行时（所有项目共用）
  apps\<应用id>\              项目代码 + 项目依赖 + 运行数据
  uninstallers\<应用id>.cmd   卸载脚本
```

卸载：开始菜单 → 「\<应用名> 卸载」，或运行 `uninstallers\<应用id>.cmd`。
卸载会删除应用目录（含其数据）与快捷方式，不影响其他应用共用的运行时。

## 环境变量

| 变量 | 作用 |
| --- | --- |
| `PYDEPLOY_ROOT` | 自定义安装根目录（默认 `%LOCALAPPDATA%\PyDeploy`），可用于共享盘批量部署 |
| `PYDEPLOY_NO_PAUSE=1` | 安装/卸载结束不等待按键（脚本化安装） |
| `PYDEPLOY_SKIP_SHORTCUTS=1` | 不创建桌面/开始菜单快捷方式 |

```bat
set PYDEPLOY_ROOT=D:\PyDeploy
set PYDEPLOY_NO_PAUSE=1
set PYDEPLOY_SKIP_SHORTCUTS=1
```

## 常见使用场景

- **GUI 应用**：`init --gui`（或 `gui = true`），快捷方式用 `pythonw.exe`，无黑色控制台窗口。
- **保护源码**：`init --compile`（或 `compile = true`），打包后只有 `.pyc`，无明文源码。
- **更强保护**：`native = true`，用 Cython + MSVC 编译为原生 `.pyd`（构建机需装
  `python -m pip install cython setuptools` 与 VS Build Tools）。
- **离线构建**：把全部 wheel（含传递依赖）放进目录，配置 `[deps] wheels_dir`。
- **批量部署**：把 `runtime-setup` 拷到共享目录执行一次，再批量分发应用安装器；
  或设置 `PYDEPLOY_ROOT` 指向共享盘，所有应用共用同一运行时。
- **构建自检**：`build --smoke` 自动装到临时目录并启动入口验证；`files` 先预览打包内容。

## 开发与测试

```bash
python -m pip install -e ".[dev]"
python -m pytest -q          # 单元测试 + 端到端构建测试（Windows + csc.exe）
```

GitHub Actions 已配置 Windows CI：安装依赖后运行测试与 `pydeploy doctor`。

## 原理简介

1. **依赖解析**：开发机上用
   `pip download --only-binary=:all: --platform win_amd64 --python-version <版本>`
   下载目标平台 wheel，安装进应用的 `site-packages`；目标机安装时只解压拷贝，不调用 pip。
2. **运行时**：复制本机 Python 并裁剪（默认去掉 pip/setuptools/wheel，约 23 MB），
   或从 python.org 下载嵌入式发行版；首次运行时安装到 `%LOCALAPPDATA%\PyDeploy\runtimes\`。
3. **自解压安装器**：一段编译好的小型 C# stub（约 5 KB）+ payload zip 拼接而成，
   双击后在临时目录解压并执行 `install.cmd`；不依赖 Python、IExpress 等外部程序。
4. **启动器**：安装目录里生成 `launcher.py`，自动把应用根目录和 `site-packages`
   加入 `sys.path` 后运行入口脚本；快捷方式直接指向运行时里的 `python.exe` / `pythonw.exe`。

## 目录结构

```text
package-py\
  pydeploy\              工具源码（CLI、配置、运行时/应用打包、SFX 生成、smoke 验证）
  pydeploy\bin\          sfx-stub 缓存（自动生成，不入库）
  pydeploy.cmd           命令行包装器
  examples\demo-app\     示例项目
  tests\                 pytest 测试套件
```
