# Installer 脚本说明

本目录脚本分三类：

1. 安装包构建（NSIS）
2. R3 更新 payload 准备/签名/验签
3. 将 payload 复制到 U 盘

---

## 约定路径（默认）

- 安装包 staging：`dist/CodePlanet/`
- 更新 payload（模拟 U 盘目录）：`dist/CodePlanetrUpdate/`
- manifest 默认：`dist/CodePlanetrUpdate/manifest.json`

> 后续都不再强依赖 `G:\`。先在项目内生成 `dist/CodePlanetrUpdate/`，再按需复制到 U 盘。

## 开发机路径配置（移植必改）

- 配置文件：`config/devtools.json`
- 当前支持：`qtDir`、`gitDir`、`nsisExe`、`vs2017Dir`
- 迁移新设备后优先修改该文件，脚本会自动读取

---

## 1) `build_release_packages.ps1`

### 用途

一键完成 NSIS 打包流程（Qt Creator Release 编译后执行）：

1. 清理 `dist/CodePlanet/bin`
2. 从 `bin/` 复制三 exe（`CodePlanetr.exe` / `CodeRuntime.exe` / `CodeEditor.exe`）
3. 同步 `installer/license.txt` -> `resources/config/license.txt` + `installer/license_utf16le.txt`
4. 执行 `windeployqt`
5. 编译 NSIS（默认四类安装包，`-MainOnly` 仅主包）
6. 自动将 `resources/config/release_version.json` 的 Build 号 +1，并同步版本元数据
7. 若 `dist/CodePlanet/Download/CodeplanetrSetup-latest.exe` 已存在，先归档为 `CodeplanetrSetup-{productVersion}.exe`（保留历史全量包）

> 清理策略：  
> - `dist/CodePlanet/bin`：每次打包都会清理重建；  
> - `dist/CodePlanet/Update/*`：每次打包都会清理（不保留历史补丁包）；  
> - `dist/CodePlanet/Download`：仅保留全量包历史归档。

### Git Bash 用法

```bash
cd "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr"
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/build_release_packages.ps1"
```

只编译主安装包：

```bash
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/build_release_packages.ps1" -MainOnly
```

不自增 Build（仅调试脚本）：

```bash
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/build_release_packages.ps1" -NoIncrementBuild
```

---

## 2) `prepare_r3_udisk_payload.ps1`

### 用途

自动准备 R3 更新测试素材：

1. 打包 demo 项目 zip
2. 计算 zip 与三类补丁包 SHA256
3. 生成 manifest 模板（`signature` 为占位符）

### Git Bash 用法（默认写到 `dist/CodePlanetrUpdate`）

```bash
cd "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr"
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/prepare_r3_udisk_payload.ps1"
```

指定其它目录：

```bash
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/prepare_r3_udisk_payload.ps1" -UsbRoot "D:\tmp\CodePlanetrUpdate"
```

---

## 3) `sign_update_manifest.ps1`

### 用途

给 manifest 生成**真实 RSA 签名**（用于 T-UPD-1/T-UPD-4 正例）。

> 重要：签名 canonical 采用与 Qt `QJsonObject` 一致的字母序规则。  
> 若你更新了签名脚本，旧 `manifest.json` 需要重新签名一次，否则 Launcher 可能报 `RSA signature verification failed`。

### 前置

- 私钥与 `resources/config/update.pub` 成对
- 系统可执行 `openssl`（脚本会自动探测：`PATH` 或 Git 默认安装路径）

#### 密钥生成（Git Bash）

```bash
mkdir -p /d/keys
cd /d/keys

# 生成私钥
openssl genrsa -out update_private.pem 2048

# 导出公钥
openssl rsa -in update_private.pem -pubout -out update.pub
```

同步公钥到仓库（然后重打包安装）：

```bash
cp /d/keys/update.pub "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr/resources/config/update.pub"
```

### Git Bash 用法（默认签 `dist/CodePlanetrUpdate/manifest.json`）

```bash
cd "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr"
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/sign_update_manifest.ps1" -PrivateKeyPath "D:\keys\update_private.pem"
```

---

## 4) `verify_manifest_signature.ps1`（排障）

### 用途

启动 Launcher 前用 openssl 预验签，减少盲测。

### Git Bash 用法

```bash
cd "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr"
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/verify_manifest_signature.ps1" -PublicKeyPath "resources\config\update.pub"
```

> 脚本会输出 `canonical_sha256`，可与 `launcher.log` 中的 `canonical_sha256=` 对比。
> 说明：`zipSha256`（项目 zip 文件哈希）与 `canonical_sha256`（manifest 规范化文本哈希）本来就不同，不应互相比较。
> 运行设备说明：**CodePlanetr/Launcher 运行不依赖 OpenSSL**。OpenSSL 仅用于开发机执行签名/本地排障脚本。
> 若脚本输出的 `canonical_sha256` 与 Launcher 日志一致但仍失败，再排查公钥一致性；若不一致，优先判断是否使用了旧签名或旧 manifest。

---

## 5) `copy_codeplanetr_update_to_drive.ps1`（复制到U盘）

### 用途

将 `dist/CodePlanetrUpdate` 整目录复制到目标盘：`X:\CodePlanetrUpdate`

### Git Bash 用法

```bash
cd "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr"
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/copy_codeplanetr_update_to_drive.ps1" -DriveLetter "G"
```

---

## 6) `run_r3_update_pipeline.ps1`（串行四步 + 可选复制）

### 用途

按顺序执行你指定的四步：

1. `build_release_packages.ps1`
2. `prepare_r3_udisk_payload.ps1`
3. `sign_update_manifest.ps1`
4. `verify_manifest_signature.ps1`

并支持可选参数 `-CopyToDrive "G"` 自动复制 payload 到 U 盘。

### Git Bash 用法

```bash
cd "/e/HuaweiMoveData/Users/MateBookXPro/Desktop/CodePlanetr"
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/run_r3_update_pipeline.ps1" -PrivateKeyPath "D:\keys\update_private.pem"
```

带自动复制到 U 盘：

```bash
powershell -NoProfile -ExecutionPolicy Bypass -File "installer/run_r3_update_pipeline.ps1" -PrivateKeyPath "D:\keys\update_private.pem" -CopyToDrive "G"
```

---

## 版本号管理（统一入口）

- 维护入口：`resources/config/release_version.json`（`productVersion` 格式：`主.次.修订.Build`，例如 `1.0.0.0000`）
- 发包脚本 `installer/build_release_packages.ps1` 每执行一次自动 `Build +1`
- 自动同步产物：
  - `installer/nsis/include/version.nsh`
  - `resources/config/release_version.json`（Launcher 页面版本展示使用）

> 建议：不要手改 `installer/nsis/include/version.nsh`，该文件为脚本生成。  
> `release_version.json` 中：
> - `productVersion` / `shortVersion` / `build` 会被脚本自动更新；
> - `launcher` / `runtime` / `editor` **会保留你的手工值**（不被覆盖），可用于组件独立版本展示。
> - `launcherPackageVersion` / `runtimePackageVersion` / `editorPackageVersion` 可单独控制三类补丁安装包文件名版本（支持 `x.x.x` 或 `x.x.x.x`，后者自动截为前三段）；
> - `demoProjectVersion` 控制 `dist/CodePlanetrUpdate/projects/demo/demo-{version}.zip` 与 manifest `projects.version`。

### 安装包命名来源

- 全量包：固定输出 `CodeplanetrSetup-latest.exe`（便于运维取最新）。
- 历史全量包：每次构建前自动将旧 `latest` 归档为 `CodeplanetrSetup-{productVersion}.exe`。
- 组件补丁包：
  - `runtimePackageVersion`（缺省回退 `runtime` 前三段，再回退 `shortVersion`）
  - `launcherPackageVersion`（缺省回退 `launcher` 前三段，再回退 `shortVersion`）
  - `editorPackageVersion`（缺省回退 `editor` 前三段，再回退 `shortVersion`）

### `shortVersion` 从哪里来？

- `shortVersion` 并非独立输入源，脚本会按 `productVersion` 前三段自动同步。
- 例如 `productVersion = 1.0.0.11`，则 `shortVersion` 会被同步为 `1.0.0`。
- 若你想手动改变 `shortVersion`，应直接修改 `productVersion` 的前三段，然后执行构建脚本。

### manifest `minVersion` 来源

- `prepare_r3_udisk_payload.ps1` 会优先从 `resources/config/release_version.json` 读取：
  - `runtime` → `manifest.runtime.minVersion`
  - `launcher` → `manifest.launcher.minVersion`
  - `editor` → `manifest.editor.minVersion`
- 若配置缺失，回退到 `release_version.json.shortVersion`。

### demo 项目包版本来源

- `prepare_r3_udisk_payload.ps1` 默认从 `release_version.json.demoProjectVersion` 读取 demo zip 版本。
- 生成文件：`dist/CodePlanetrUpdate/projects/demo/demo-{demoProjectVersion}.zip`
- manifest 映射：
  - `projects[0].version = demoProjectVersion`
  - `projects[0].zipUrl = projects/demo/demo-{demoProjectVersion}.zip`
- 生成 payload 前会先清理 `dist/CodePlanetrUpdate` 旧内容，避免历史文件干扰测试。

### 插件 `minVersion` 配置

- `manifest.plugins[0].minVersion` 默认读取 `release_version.json` 的 `pluginBuiltinFunctionsMinVersion`（缺失时回退 `1.4.0`）。
- 当前 `BuiltinFunctions.dll` 未内置 Windows VERSIONINFO 时，Launcher 会跳过“无法读取版本”的警告，避免误报。

---

## License 维护约定

你只需要维护：`installer/license.txt`。

以下脚本会自动同步到 `resources/config/license.txt`（Launcher 倒计时页无日志时显示）：

- `installer/build_release_packages.ps1`
- `scripts/build_nsis_packages.ps1`

