Metadata-Version: 2.4
Name: hcpip
Version: 0.0.2
Summary: 通用Python项目打包，支持：离线安装、源码wheel安装、源码加密打包。
Author-email: Bo Fang <1163646804@qq.com>
License-Expression: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: setuptools>=61.0
Requires-Dist: wheel>=0.40
Requires-Dist: build>=1.0
Requires-Dist: packaging>=23.0
Requires-Dist: pyarmor>=9.2.7
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Provides-Extra: publish
Requires-Dist: twine>=7.0.0; extra == "publish"
Provides-Extra: encrypt
Requires-Dist: pyarmor>=9.2; extra == "encrypt"
Dynamic: license-file

# hcpip 使用指南

通用 Python 项目打包 / 离线安装工具（HCAC soft department）。

> 使用 hcpip 看本文。改 hcpip 本身，见 [DEVELOPMENT.md](docs/DEVELOPMENT.md)；
> 把 hcpip 发到 PyPI，见 [docs/本地打包发布到PyPI教程.md](docs/本地打包发布到PyPI教程.md)。

在业务项目根目录下执行 `hcpip`，可产出两类制品：

| 命令 | 产物 | 适用场景 |
|---|---|---|
| `hcpip build --wheel` | 源码 wheel（跨平台 `py3-none-any`）+ 安装脚本 `install_bundle.py` | 有外网：目标机 `python install_bundle.py <whl>` 或 `pip install` 即装 |
| `hcpip build --bundle` | 项目 wheel + 全部依赖 wheel 的离线 zip + 安装脚本 `install_bundle.py` | 无外网：一次拉齐依赖，目标机离线安装 |
| `hcpip install <制品>` | — | 安装项目 .whl 或离线 bundle .zip |
| `hcpip self-pack` | hcpip 自身 wheel | 把 hcpip 装进目标项目 venv |
| `hcpip doctor` | 环境诊断 | 检查打包环境 |
| `hcpip init` | 生成最小 pyproject.toml | 老项目起步 |
| `hcpip sync-version` | — | 项目根 `version` 文件 → `pyproject.toml [project].version`（PEP 440 去 v） |
| `hcpip pip <参数...>` | — | 透传任意 pip 命令 |

## 三种使用环境

| 环境 | 是否安装 hcpip | 作用 |
|---|---|---|
| 项目开发环境 | hcpip 源码（本仓库） | 开发 / 修改 hcpip 本身（见 DEVELOPMENT.md） |
| 编译打包环境 | 是：`pip install hcpip`（hcpip wheel） | 在业务项目根跑 `hcpip build --wheel` / `--bundle`，产出 wheel / zip 并附 `install_bundle.py` |
| 目标部署环境 | 否：不装 hcpip | 只拿产物（.whl / .zip）与其附带的 `install_bundle.py`，`python install_bundle.py <制品>` 直接安装 |

> 两类构建产物（wheel / bundle zip）都会在产物目录附带独立安装脚本 `install_bundle.py`
> （仅标准库，随产物拷到目标机即可，不依赖 hcpip）。

## 安装

```bash
pip install hcpip          # 有网环境直接装
pip install hcpip-0.0.1-py3-none-any.whl   # 离线：hcpip self-pack 产出的 wheel 拷到目标机装
```

hcpip 只做源码打包，不编译也不加密源码；依赖打包工具链 `setuptools` / `wheel` / `build` / `packaging`，
安装时自动带上。构建 `--bundle` 拉取依赖需要网络（一次），之后产物可离线部署。

## 业务项目要求

- 项目需有 `pyproject.toml`（含 `[project]` 的 `name` / `version`）。没有时 `hcpip build` 会报错退出，
  并提示先运行 `hcpip init`（自动探测包 / 模块生成最小模板），不会静默自动生成；
- 版本号可选约定：项目根放 `version` 文件（内容 `VERSION = v1.2.3`）作为发版源，`hcpip build`
  打包前会把它同步到 `[project].version`；文件缺失时按 pyproject 现值创建（不会把老项目版本
  冲成兜底值），不需要这个行为时加 `--no-sync-version`；
- `hcpip build` 打包前先做预检：`packages.find` 的 `include` / `packages` 声明的包、`py-modules`
  声明的顶层模块必须真实存在于磁盘，缺失即报错并提示 `hcpip init` 修正；
- 磁盘上存在但未声明的顶层源码会打印警告，这类文件不会进 wheel；
- 源码布局 `src/` 或平铺均可，包/模块由 setuptools 自动发现（`python -m build` / `pip wheel` 自行读取配置）；
- 第三方依赖在 `[project].dependencies` 声明，打包 / 安装时自动处理。

## 命令参考

### hcpip build --wheel（源码 wheel，有外网部署）

```bash
hcpip build --wheel                    # 当前目录项目
hcpip build --wheel -p /path/to/proj   # 指定项目
hcpip build --wheel -o dist/           # 指定产物目录
```

产物：`dist/<name>-<ver>-py3-none-any.whl`（跨平台）+ `dist/install_bundle.py`（安装脚本，仅标准库）。

> 构建前会自动同步版本号（详见下文 `hcpip sync-version`）：把项目根 `version` 文件同步到
> `[project].version`，文件缺失则按 pyproject 现值创建；不需要时加 `--no-sync-version`。

目标机部署（有外网、无需安装 hcpip）：

```bash
python install_bundle.py dist/<name>-<ver>-py3-none-any.whl    # 用附带的脚本安装
pip install dist/<name>-<ver>-*.whl                            # 或直接 pip 安装
```

脚本按后缀自动判别：`.whl` 走在线 `pip install`，支持 `-i <pip 源>` 与透传 pip 参数
（`--upgrade` / `--target` 等）；`.zip` 走 `--no-index` 离线安装。依赖由 pip 从源解析。

### hcpip build --bundle（离线 bundle zip，无外网部署）

```bash
hcpip build --bundle                   # 当前目录项目
hcpip build --bundle --index-url https://mirrors.cloud.tencent.com/pypi/simple/   # 指定 pip 源
hcpip build --bundle --allow-sdist     # 直接允许源码包，跳过"先只收 wheel"的第一遍
```

- 构建机需联网一次：`pip wheel` 拉取项目自身 wheel + 全部第三方依赖 wheel；
- 依赖默认只收预编译 wheel；个别依赖没有发布 wheel（如 `crcmod`）时会自动改为允许源码包，
  在构建机上把 sdist 编成 wheel。这一步要本机有编译工具链：Linux 装 `gcc` + `python3-dev`
  （或 `build-essential`），Windows 装 MSVC 生成工具；
- 同样会先做版本同步（`version` 文件 → `[project].version`），可用 `--no-sync-version` 关闭；
- 产物：`dist/<name>-wheels-<ver>-<platform>.zip` + `dist/install_bundle.py`（离线部署脚本，仅标准库）+ `dist/SHA256SUMS`；
- 目标机（离线）解压 zip 后 `pip install --no-index --find-links=<解压目录> <全部wheel>`，或直接用随 zip 交付的 `install_bundle.py`。

### hcpip build --encryption（代码保护，可选）

在 `--wheel` / `--bundle` 上开启，对**项目自身源码**（顶层包/模块）用 PyArmor 加密后再打
wheel / zip。第三方依赖不加密；部署链路与普通产物一致（附带的 `install_bundle.py` 照用）。

```bash
pip install "hcpip[encrypt]"            # 编译打包环境安装 pyarmor（并完成 pyarmor reg 授权）
hcpip build --wheel --encryption        # 加密源码 wheel
hcpip build --bundle --encryption       # 加密项目 wheel + 明文依赖的离线 zip
hcpip build --bundle --encryption -- --mix-str --restrict   # -- 后参数原样透传 pyarmor gen
```

约束与说明：
- 加密产物绑定**构建机平台与 Python 小版本**：wheel 标签为 `cp3x-none-<平台>`（不匹配
  环境 pip 直接拒绝安装），bundle zip 名含 `-encrypted-<平台>`；须与目标机同平台构建；
- 目标部署环境**无需安装 pyarmor**（runtime 随产物分发）；
- 打包前会校验 pyarmor 确实产出了 runtime 包（缺了目标机 import 会失败，故提前报错终止）；
  找不到 pyarmor 时依次查 PATH 与当前解释器同目录的 `Scripts/bin`（未 activate venv 也能用）；
- 加密强度由透传参数自行控制（hcpip 不预设）。加密是提高读取门槛，**非绝对安全**。

### hcpip install（安装 wheel / 离线 zip）

```bash
hcpip install dist/<name>-<ver>-py3-none-any.whl     # 在线安装（拉依赖）
hcpip install dist/<name>-wheels-<ver>-win_amd64.zip  # 离线安装（--no-index）
hcpip install <whl> -i https://mirrors.cloud.tencent.com/pypi/simple/   # 在线安装指定源
hcpip install <whl> --upgrade                        # 其余参数原样透传 pip
```

按后缀自动判别：`.whl` 走在线 `pip install`；`.zip` 解压后 `pip install --no-index --find-links` 离线安装。制品之外的参数原样透传给 pip（`--upgrade` / `--target` / `--user` / `--no-deps` 等都能直接用）。

> 产物目录里附带的 `install_bundle.py` 与 `hcpip install` 是同一套安装逻辑——目标部署环境
> 不装 hcpip 时，把产物与脚本一起拷过去，`python install_bundle.py <whl|zip>` 即可完成同样安装。

### hcpip self-pack（hcpip 自身打包成 wheel）

```bash
hcpip self-pack                    # 在 hcpip 源码根（含 pyproject.toml）执行
hcpip self-pack -s /path/to/hcpip -o dist/   # 指定源码根 / 产物目录
```

产出 `dist/hcpip-0.0.1-py3-none-any.whl`，拷到目标机器：

```bash
python -m venv .venv
.venv\Scripts\activate          # Linux: source .venv/bin/activate
pip install hcpip-0.0.1-py3-none-any.whl     # 之后 hcpip 命令可用
```

### hcpip sync-version（版本号同步）

业务项目若用一个 `version` 文件作为发版数据源（内容形如 `VERSION = v1.2.3`），可用本命令把版本号
同步到 `pyproject.toml` 的 `[project].version`（PEP 440 不允许 v 前缀，hcpip 自动剥 v）：

```bash
hcpip sync-version                        # 同步（幂等：已一致则不改写）
hcpip sync-version --check                # 仅检查；不一致时退出码 1（不写文件，CI 用）
hcpip sync-version -p /path/to/proj       # 指定业务项目根（默认当前目录）
hcpip sync-version --version-file VERSION # 版本文件不叫 version 时指定
```

- 要求项目根存在版本文件（默认名 `version`，格式 `VERSION = v1.2.3`，允许引号 / 行内注释 / v 前缀）；
  文件缺失或版本号非法会中文报错并退出码 1；
- `hcpip build`（`--wheel` / `--bundle`）默认在打包前也会做同样的同步，可用 `--no-sync-version` 关闭。
  区别是 `sync-version` 要求版本文件已存在，而 `build` 在缺失时会按 pyproject 现值创建它（pyproject
  也没有可用版本时才写 `v0.0.1`），所以产物版本号与源码版本一致；
- 只改 `version = "..."` 行引号里的版本号：缩进、行内注释（注释中的旧版本号一并更新）与文件行尾
  风格（CRLF/LF）保持原样，其余内容与结构不动；`[project]` 段内没有 version 行时补一行；
- 写回前用 `tomllib` 解析一遍，确认 `[project].version` 已是目标值，避免提示成功但没写进去；
- 幂等：两边一致时不触碰文件；`--check` 不写文件；
- 该命令只作用于业务项目：hcpip 自身仍以 `pyproject.toml` 的 `[project].version` 为唯一版本源。

### hcpip doctor / init / pip

```bash
hcpip doctor          # 检查 Python / pip 源 / setuptools / wheel / build / packaging，并检查当前项目可打包性
hcpip doctor -p <项目> # 指定业务项目：诊断 pyproject.toml 与声明的打包目标（包/模块）是否齐全
hcpip init            # 生成最小 pyproject.toml（自动探测包/模块，--force 覆盖已有配置）
hcpip pip install requests       # 等价于 python -m pip install requests
```

> `hcpip build` 找不到 `pyproject.toml` 或预检到声明目标缺失时，会报错并提示先用 `hcpip init`
> 生成 / 修正配置，再重新执行 `hcpip build`。

## 部署流程

### 在线部署（wheel）

```bash
# 构建机
pip install hcpip
hcpip build --wheel

# 目标机（需 Python + 网络）
pip install dist/<name>-<ver>-*.whl
```

### 离线部署（bundle）

```bash
# 构建机（与目标机同平台、联网一次）
hcpip build --bundle

# 目标机（离线，已装 Python）
python install_bundle.py dist/<name>-wheels-<ver>-<platform>.zip
# 或手动：解压 zip 后 pip install --no-index --find-links=<解压目录> <全部 wheel>
```

### 升级迭代（依赖不变）

```bash
pip install --upgrade --no-deps dist/<name>-<ver>-*.whl   # 只换项目 wheel，不重装依赖
```

## 注意事项

- bundle 需与目标机同平台构建（依赖 wheel 平台绑定）；源码 wheel 跨平台通用；
- 镜像源故障：pip 报 `403 Forbidden` 时换源即可，`hcpip build --bundle --index-url <镜像>`、
  `hcpip install <whl> --index-url <镜像>`；`hcpip doctor` 可查看当前 pip 源。可用镜像：腾讯云
  `https://mirrors.cloud.tencent.com/pypi/simple/`、阿里云 `https://mirrors.aliyun.com/pypi/simple/`；
- bundle 报 `Could not find a version that satisfies`：多数是依赖没有预编译 wheel，hcpip 会自动放开
  源码包重试一遍；重试仍失败再看构建机是否缺编译工具链，或换源；
- `hcpip build` 完成后自动清理 `build/` 与 `*.egg-info` 等中间产物，仅保留 `dist/` 制品；
- `hcpip build` 打包前会检查项目可打包性（缺 pyproject / 声明目标不存在会报错），可用
  `hcpip doctor -p <项目>` 提前诊断。
