Isolate modern and Win7 workspaces (T-604)
This commit is contained in:
+10
-10
@@ -45,21 +45,21 @@ SoftBox 软件盒子是一个使用 Go + Gio 开发的 Windows 桌面客户端,
|
||||
|
||||
## 当前阶段
|
||||
|
||||
当前项目处于:**M2 已完成(清单验签、ZIP 安全解压、原子切换/回滚三项高风险原型已验证),准备进入 Phase 2 清单与软件列表**。
|
||||
当前项目已完成 Phase 0~2、T-301 与首个交叉审核整改 `T-604`。下一步按审核定稿落成状态模型收口任务,随后处理依赖可复现性和 Runtime 并发契约,再恢复 T-302。
|
||||
|
||||
优先路径:
|
||||
|
||||
1. 已完成 Phase 0:monorepo 骨架 + 双目标编译 + 空 Gio 窗口。
|
||||
2. 已完成 Phase 1:清单验签、ZIP 安全解压、原子切换回滚原型。
|
||||
3. 下一步 Phase 2-3:清单/列表 → 下载/安装。
|
||||
4. Phase 4-5:启动/更新/自更新 → 授权。
|
||||
5. Phase 6:Win7 加固与双通道发布。
|
||||
3. 已完成 Phase 2 与 T-301:清单/列表/详情/图标缓存 + 可恢复下载队列。
|
||||
4. 已完成 T-604:modern/Win7 workspace 与 Gio 版本解析彻底隔离。
|
||||
5. 继续串行完成其余审核整改,再恢复 T-302/T-303 和 Phase 4-6。
|
||||
|
||||
## 领取任务规则
|
||||
|
||||
任务以「一任务一文件」存放在 `docs/tasks/`(约定见 [`tasks/README.md`](tasks/README.md)):
|
||||
|
||||
- 每个 agent 只领取一个 frontmatter `status: TODO` 且依赖均 `DONE` 的任务文件,取编号最靠前的;项目可并行多个 `write_paths` 互不重叠的任务。
|
||||
- 单 Agent 只领取一个 frontmatter `status: TODO` 且依赖均 `DONE` 的任务文件,取编号最靠前的;项目同一时间只保留一个活跃任务。
|
||||
- 若 `docs/tasks/` 暂无可领任务,先按 [`06-tasks.md`](06-tasks.md) 路线图把下一个建议任务落成任务文件,再领取。
|
||||
- 开始前在独立分支 / worktree 把该文件 frontmatter 的 `status` 改为 `DOING`。
|
||||
- 本轮只完成这一个任务;验收通过后改为 `DONE`。
|
||||
@@ -133,17 +133,17 @@ MVP 不做:
|
||||
|
||||
## 验证命令
|
||||
|
||||
统一启动与验证入口收敛到根目录 `./init.sh` / `./init.ps1`;脚本会同步工作区依赖并运行完整 Phase 0 闸门。也可直接运行 `bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1`。标准分项命令:
|
||||
统一启动与验证入口收敛到根目录 `./init.sh` / `./init.ps1`;脚本会分别同步根 modern/core workspace 与嵌套 win7/core workspace,再运行完整 Phase 0 闸门。也可直接运行 `bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1`。标准分项命令:
|
||||
|
||||
```bash
|
||||
# core 测试(Linux 无头可跑)
|
||||
cd core && go vet ./... && go test -count=1 ./...
|
||||
|
||||
# 现代版构建
|
||||
cd app-modern && GOTOOLCHAIN=go1.25.0 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" ./cmd/softbox
|
||||
# 现代版构建(从仓库根执行;GOWORK 必须是绝对路径)
|
||||
GOTOOLCHAIN=go1.25.0 GOWORK="$(pwd)/go.work" CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-modern build -trimpath -ldflags="-H=windowsgui" ./cmd/softbox
|
||||
|
||||
# Win7 版构建(强制 Go 1.20)
|
||||
cd app-win7 && GOTOOLCHAIN=go1.20.14 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" ./cmd/softbox
|
||||
# Win7 版构建(从仓库根执行;强制 Go 1.20)
|
||||
GOTOOLCHAIN=go1.20.14 GOWORK="$(pwd)/app-win7/go.work" CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-win7 build -trimpath -ldflags="-H=windowsgui" ./cmd/softbox
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
| UI 框架 | Gio(纯 Go 立即模式 GUI) | 已定 | 无 CGO、单 EXE、跨版本可锁定;仅限 UI 层 |
|
||||
| 现代版工具链 | Go 1.25(锁定已验证版本) + Gio v0.10.1 | 已定 | 当前受支持工具链;支持 Win10/Win11 x64 |
|
||||
| Win7 版工具链 | Go 1.20.14(最终补丁) + Gio v0.6.0 | 已定 | Go 1.20 是最后支持 Win7 的版本;Gio v0.6.0 可由 Go 1.20 构建 |
|
||||
| 模块结构 | go.work + 三个 go.mod(core / app-modern / app-win7) | 已定 | 共享核心,双构建互不污染工具链要求 |
|
||||
| 模块结构 | 两个 go.work + 三个 go.mod(core / app-modern / app-win7) | 已定 | 根 workspace 只含 modern/core;嵌套 Win7 workspace 只含 win7/core |
|
||||
| 依赖管理 | 版本锁定 + vendor(Gio 及相关依赖) | 已定 | 防止 Win7 构建被隐式升级到要求 Go 1.21+ 的依赖 |
|
||||
| 存储 | JSON 文件 + 临时文件原子替换 | 已定 | 数百款软件规模足够;SQLite 仅在历史/搜索/事务需求出现后评估 |
|
||||
| 软件包格式 | ZIP(标准软件包协议 v1) | 已定 | 避免 UnRAR.dll;协议见 [api.md](api.md) |
|
||||
@@ -41,14 +41,17 @@
|
||||
| --- | --- |
|
||||
| Phase 0 完整闸门(Unix) | `bash scripts/verify_phase0.sh` |
|
||||
| Phase 0 完整闸门(Windows) | `./scripts/verify_phase0.ps1` |
|
||||
| 同步工作区依赖 | `go work sync` |
|
||||
| 同步根 workspace | `GOTOOLCHAIN=go1.25.0 GOWORK=<repo>/go.work go work sync` |
|
||||
| 同步 Win7 workspace | `GOTOOLCHAIN=go1.25.0 GOWORK=<repo>/app-win7/go.work go work sync`(同步元数据后仍由 Go 1.20.14 校验/构建) |
|
||||
| core 测试 | `cd core && go test -count=1 ./...` |
|
||||
| core 静态检查 | `cd core && go vet ./...` |
|
||||
| 现代版构建 | `cd app-modern && GOTOOLCHAIN=go1.25.0 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox` |
|
||||
| Win7 版构建 | `cd app-win7 && GOTOOLCHAIN=go1.20.14 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox` |
|
||||
| 现代版构建 | `GOTOOLCHAIN=go1.25.0 GOWORK=<repo>/go.work CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-modern build -trimpath -ldflags="-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox` |
|
||||
| Win7 版构建 | `GOTOOLCHAIN=go1.20.14 GOWORK=<repo>/app-win7/go.work CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-win7 build -trimpath -ldflags="-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox` |
|
||||
| 本地运行(开发) | Windows 下直接 `go run ./cmd/softbox`(WSL 中构建 EXE 后到 Windows 侧运行) |
|
||||
|
||||
根 `go.work` 纳入三个模块并使用 modern 所需的 Go 1.25 workspace 版本;`app-win7/go.work` 是就近的 Go 1.20 workspace,只纳入 `app-win7` 与 `core`,确保 Go 1.20.14 不需要解析 modern 模块。
|
||||
根 `go.work` 使用 Go 1.25.0,只纳入 `app-modern` 与 `core`;`app-win7/go.work` 使用 Go 1.20,只纳入 `app-win7` 与 `core`。同步、测试和构建始终显式指定对应 `GOWORK`,任何 workspace 都不会同时解析 Gio v0.10.1 与 v0.6.0。
|
||||
|
||||
两个 workspace 的元数据同步统一使用 Go 1.25.0。原因是 Go 1.20.14 的 `go work sync` 会忽略 workspace 级本地 replace 并尝试联网解析占位模块 `softbox.local/core@v0.0.0`;不为规避该工具缺陷把本机相对路径写进 go.mod。Win7 的依赖图、测试和构建仍全部强制使用 Go 1.20.14,并由版本检查拒绝 Go 1.21+ 依赖。
|
||||
|
||||
工具链矩阵:
|
||||
|
||||
|
||||
@@ -13,22 +13,22 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-16
|
||||
- 阶段:Phase 2 已完成(T-201~T-204);Phase 3 的 T-301 可恢复下载队列已完成;Phase 0 交叉审核整改从 T-604 开始,T-302 暂后置
|
||||
- 技术栈:根 Go workspace 纳入 core/app-modern/app-win7 三模块;`app-win7/go.work` 隔离 Go 1.20.14 构建;modern Gio v0.10.1 与 win7 Gio v0.6.0 已实际接入
|
||||
- 阶段:Phase 2 已完成(T-201~T-204);Phase 3 的 T-301 可恢复下载队列已完成;Phase 0 首个交叉审核整改 T-604 已完成,T-302 继续暂后置
|
||||
- 技术栈:根 Go 1.25 workspace 只纳入 core/app-modern,`app-win7/go.work` 独立纳入 core/app-win7;版本闸门证明 modern Gio v0.10.1 与 win7 Gio v0.6.0 不交叉解析
|
||||
- 生产代码:core 已有 Catalog/本地状态/存储、无 IO 软件列表模型、可信图标缓存和默认并发 2 的持久可恢复下载队列;modern/win7 AppShell 已实现搜索/分类/视图、惰性列表、详情右栏与内存图标
|
||||
- 测试:core 覆盖 Catalog、SemVer/12 状态、本地安装记录、列表/图标、下载并发/暂停/取消/重试/Range/断连/恢复/事件失败与文件身份替换;两个 app 覆盖 500 项虚拟列表、ID 控件稳定性、详情/ApplyIcon 与平台 stub;ZIP/安装恢复矩阵保持通过
|
||||
- 数据:`schemas/` 已有 manifest/app.json/installed-app.json/download-task.json v1 Schema;`testdata/catalog/` 有公开虚构清单样例;`testdata/zip/` 与 `testdata/download/` 记录运行时生成的攻击/传输矩阵
|
||||
- 标准启动路径:`./init.sh` / `./init.ps1`(同步依赖、执行完整 Phase 0 闸门、打印双目标构建命令)
|
||||
- 标准验证路径:`bash scripts/verify_phase0.sh` / `./scripts/verify_phase0.ps1`
|
||||
- 版本管理:git 已初始化,main 分支,远端 origin 为 Gitea `opc/soft_quay`;harness 文档已提交
|
||||
- 当前 blocker:无;下一个任务是 T-604 workspace 隔离加固,完成审核整改后再恢复 T-302 安装流程整合
|
||||
- 当前 blocker:无;下一步按审核定稿落成状态模型收口任务,其余审核整改完成后再恢复 T-302 安装流程整合
|
||||
|
||||
## 当前目录要点
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `docs/` | 已有 | harness coding 文档集(本次初始化完成) |
|
||||
| `docs/tasks/` | 已有 | Phase 0~2 与 T-301 已完成;T-604 审核整改已落成并待领取;T-302 暂后置 |
|
||||
| `docs/tasks/` | 已有 | Phase 0~2、T-301 与 T-604 已完成;下一审核整改任务尚未落成;T-302 暂后置 |
|
||||
| `scripts/` | 已有 | harness 治理、core 边界、Go 版本检查与 Phase 0 双平台验证入口 |
|
||||
| `core/` | 已建 | Go 1.20 兼容;已有正式 Catalog、本地状态/存储、列表模型、图标缓存、可恢复下载队列与 Phase 1 安装安全原型 |
|
||||
| `app-modern/` | 已建 | Go 1.25.0 + Gio v0.10.1;Modern AppShell 已接入虚拟列表、详情和内存图标 |
|
||||
@@ -40,9 +40,9 @@
|
||||
|
||||
任务状态以 `docs/tasks/` 各任务文件 frontmatter 的 `status` 为准。本节只写项目级摘要:
|
||||
|
||||
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`~`T-204`;Phase 3 的 `T-301`。
|
||||
- 已完成:Phase 0 的 `T-001`~`T-004`;Phase 1 的 `T-101`、`T-102`、`T-103`;Phase 2 的 `T-201`~`T-204`;Phase 3 的 `T-301`;审核整改 `T-604`。
|
||||
- 正在进行:无。
|
||||
- 下一个可领取任务:`T-604 隔离 modern 与 Win7 workspace`;完成并提交后继续按审核定稿拆分下一整改任务。
|
||||
- 下一个可领取任务:无;先按 `docs/review/phase0-skeleton-review.md` 落成下一状态模型收口任务。
|
||||
|
||||
## 当前可运行内容
|
||||
|
||||
|
||||
+10
-5
@@ -3,12 +3,12 @@ id: T-604
|
||||
title: 隔离 modern 与 Win7 workspace
|
||||
phase: 0
|
||||
deps: [T-004]
|
||||
status: TODO
|
||||
status: DONE
|
||||
created: 2026-07-16
|
||||
issue: null
|
||||
context_ref: null
|
||||
context_ref: e4a9295cbf94d645370d2583866b7ca91c0c5271
|
||||
claim_branch: null
|
||||
work_branch: null
|
||||
work_branch: agent/codex/T-604
|
||||
write_paths:
|
||||
- docs/tasks/T-604.md
|
||||
- go.work
|
||||
@@ -36,7 +36,7 @@ Phase 0 交叉审核确认根 `go.work` 同时纳入 `app-modern`、`app-win7`
|
||||
1. 根 `go.work` 只纳入 `app-modern` 与 `core`;`app-win7` 只由 `app-win7/go.work` 纳入并继续与 `core` 共享本地替换。
|
||||
2. `init.sh`、`init.ps1`、`verify_phase0.sh` 与 `verify_phase0.ps1` 分别同步两个 workspace:
|
||||
- Go 1.25.0 同步根 workspace。
|
||||
- Go 1.20.14 + 显式 `GOWORK=app-win7/go.work` 同步 Win7 workspace。
|
||||
- Go 1.25.0 + 显式 `GOWORK=app-win7/go.work` 同步 Win7 workspace 元数据;随后必须用 Go 1.20.14 校验实际依赖图、测试和构建。
|
||||
3. 加固 `scripts/check_go_versions.py`:
|
||||
- 校验根 workspace 只包含 modern/core。
|
||||
- 校验 Win7 workspace 只包含 win7/core。
|
||||
@@ -50,7 +50,7 @@ Phase 0 交叉审核确认根 `go.work` 同时纳入 `app-modern`、`app-win7`
|
||||
- `go work edit -json` 显示根 workspace 只有 `./app-modern`、`./core`;`app-win7/go.work` 只有 `.`、`../core`。
|
||||
- 根 workspace 执行 `go list -m gioui.org` 得到 v0.10.1;Win7 workspace 使用 Go 1.20.14 执行同命令得到 v0.6.0。
|
||||
- 根 workspace 不再把 `./app-win7/...` 当作自身 package pattern 构建;Win7 test/build 必须显式使用嵌套 workspace。
|
||||
- 两个 workspace 的 sync 都由 `init` 与 `verify_phase0` 执行;sync 后 `core/go.mod`、`app-modern/go.mod`、`app-win7/go.mod` 无意外漂移。
|
||||
- 两个 workspace 的 sync 都由 `init` 与 `verify_phase0` 执行;Win7 sync 使用 Go 1.25.0 规避 Go 1.20.14 对 workspace replace 的已验证限制,但 Win7 依赖图/test/build 仍强制 Go 1.20.14;sync 后三个 go.mod 无意外漂移。
|
||||
- `python scripts/check_go_versions.py` 能在 workspace 成员或 Gio 解析版本错误时失败。
|
||||
- gopls/IDE 打开仓库后,Win7 文件使用 Gio v0.6.0 语义;若当前环境没有 gopls,执行记录必须写明限制并至少提供嵌套 workspace 的 `go list/test` 证据。
|
||||
- `./scripts/verify_phase0.ps1` 与 `bash scripts/verify_phase0.sh` 全绿,modern/Win7 EXE 均重新产出。
|
||||
@@ -74,3 +74,8 @@ Phase 0 交叉审核确认根 `go.work` 同时纳入 `app-modern`、`app-win7`
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-16:根据 `docs/review/phase0-skeleton-review.md` 的交叉复核定稿落成首个整改任务;编号按路线图与现有任务最大编号 `T-603 + 1` 取 `T-604`。
|
||||
- 2026-07-16:在 `agent/codex/T-604` 分支领取任务;基线为 `e4a9295cbf94d645370d2583866b7ca91c0c5271`。当前环境未安装 gopls,后续以嵌套 workspace 的实际 `go list/test/build` 作为自动化证据,并在收尾记录该环境限制。
|
||||
- 2026-07-16:真实执行发现 Go 1.20.14 `go work sync` 虽能用 workspace replace 完成 `go list`,却会在 sync 时联网解析 `softbox.local/core@v0.0.0` 并失败;Go 1.25.0 对同一 Win7 workspace sync 成功且三个 go.mod 哈希不变。决定用 Go 1.25.0 同步两套 workspace 元数据,继续用 Go 1.20.14 强制验证和构建 Win7,不向 go.mod 写本地 replace。
|
||||
- 2026-07-16:根 `go.work` 移除 `app-win7`,清理根 `go.work.sum` 中 Win7 专属旧校验和;`init`/`verify_phase0` 分别同步两套 workspace并显式传递绝对 `GOWORK`。`check_go_versions.py` 现校验 workspace 成员、实际 Gio 解析版本、Go 1.20.14 工具链与 core/win7 完整模块图,并带错误分支 self-check。
|
||||
- 2026-07-16:隔离证据通过:根 `go work edit -json` 仅含 `app-modern/core`,Gio 为 v0.10.1;Win7 workspace 仅含 `app-win7/core`,Go 1.20.14 解析 Gio v0.6.0;根 workspace 的 `go list ./app-win7/...` 按预期拒绝;三个 go.mod 前后哈希完全一致。当前环境未安装 gopls,已按验收规则记录限制并用实际 list/test/build 替代自动化证据。
|
||||
- 2026-07-16:验证通过:`python scripts/check_go_versions.py`;`./scripts/verify_phase0.ps1`;`C:\Program Files\Git\bin\bash.exe scripts/verify_phase0.sh`;`./init.ps1`(含 `RUN_START_COMMAND=1` 的显式双 workspace build);`C:\Program Files\Git\bin\bash.exe ./init.sh`;治理/边界检查、core Go 1.20.14 vet/test、modern Go 1.25.0 与 Win7 Go 1.20.14 adapter test/GUI build 全绿。
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
|
||||
gioui.org v0.6.0/go.mod h1:eUvGo6FAzA7jUqeSu5a+M1W03yc9r1nanIBS8A5+Nng=
|
||||
gioui.org v0.10.1 h1:Dvp6iDk9RKuZk19jxhOmb4p673CLVvb656LyMxQ+uO0=
|
||||
gioui.org v0.10.1/go.mod h1:MZJZsdEPkTBzChdqeE8CiiQhreUQBj43qusDxQNDf7k=
|
||||
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
||||
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
|
||||
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
||||
github.com/go-text/typesetting v0.3.4 h1:YYurUOtEb9kGSOz4uE3k4OpBGsp1dDL8+fjCeaFamAU=
|
||||
|
||||
@@ -12,17 +12,23 @@ $Utf8 = [System.Text.UTF8Encoding]::new($false)
|
||||
$OutputEncoding = $Utf8
|
||||
Set-Location -Path $PSScriptRoot
|
||||
|
||||
$InstallCmd = "go work sync"
|
||||
$InstallCmd = '$env:GOTOOLCHAIN="go1.25.0"; $env:GOWORK=(Resolve-Path "go.work").Path; go work sync; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $env:GOWORK=(Resolve-Path "app-win7/go.work").Path; go work sync'
|
||||
$VerifyCmd = "./scripts/verify_phase0.ps1"
|
||||
$StartCmd = '$env:CGO_ENABLED="0"; $env:GOOS="windows"; $env:GOARCH="amd64"; $env:GOTOOLCHAIN="go1.25.0"; go build -C app-modern -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $env:GOTOOLCHAIN="go1.20.14"; go build -C app-win7 -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox'
|
||||
$StartCmd = '$env:CGO_ENABLED="0"; $env:GOOS="windows"; $env:GOARCH="amd64"; $env:GOTOOLCHAIN="go1.25.0"; $env:GOWORK=(Resolve-Path "go.work").Path; go build -C app-modern -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox.exe ./cmd/softbox; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }; $env:GOTOOLCHAIN="go1.20.14"; $env:GOWORK=(Resolve-Path "app-win7/go.work").Path; go build -C app-win7 -trimpath "-ldflags=-H=windowsgui" -o ../dist/SoftBox-win7.exe ./cmd/softbox'
|
||||
|
||||
Write-Host "==> 当前目录: $($PWD.Path)"
|
||||
|
||||
Write-Host "==> 同步依赖"
|
||||
Invoke-Expression $InstallCmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "==> 运行基础验证"
|
||||
Invoke-Expression $VerifyCmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "==> 启动命令"
|
||||
Write-Host " $StartCmd"
|
||||
@@ -30,6 +36,9 @@ Write-Host " $StartCmd"
|
||||
if ($env:RUN_START_COMMAND -eq "1") {
|
||||
Write-Host "==> 启动应用"
|
||||
Invoke-Expression $StartCmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
} else {
|
||||
Write-Host "如果希望 init.ps1 直接启动应用,请设置环境变量 RUN_START_COMMAND=1。"
|
||||
Write-Host "如果基础验证失败,先修复基线状态,不要在坏的起点上继续叠新功能。"
|
||||
|
||||
@@ -11,9 +11,9 @@ set -euo pipefail
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
INSTALL_CMD="go work sync"
|
||||
INSTALL_CMD="GOTOOLCHAIN=go1.25.0 GOWORK=\"$ROOT_DIR/go.work\" go work sync && GOTOOLCHAIN=go1.25.0 GOWORK=\"$ROOT_DIR/app-win7/go.work\" go work sync"
|
||||
VERIFY_CMD="bash scripts/verify_phase0.sh"
|
||||
START_CMD="GOTOOLCHAIN=go1.25.0 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-modern build -trimpath -ldflags=-H=windowsgui -o ../dist/SoftBox.exe ./cmd/softbox && GOTOOLCHAIN=go1.20.14 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-win7 build -trimpath -ldflags=-H=windowsgui -o ../dist/SoftBox-win7.exe ./cmd/softbox"
|
||||
START_CMD="GOTOOLCHAIN=go1.25.0 GOWORK=\"$ROOT_DIR/go.work\" CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-modern build -trimpath -ldflags=-H=windowsgui -o ../dist/SoftBox.exe ./cmd/softbox && GOTOOLCHAIN=go1.20.14 GOWORK=\"$ROOT_DIR/app-win7/go.work\" CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go -C app-win7 build -trimpath -ldflags=-H=windowsgui -o ../dist/SoftBox-win7.exe ./cmd/softbox"
|
||||
|
||||
echo "==> 当前目录: $PWD"
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import sys
|
||||
|
||||
|
||||
MAX_LEGACY_GO_VERSION = (1, 20)
|
||||
MODERN_TOOLCHAIN = "go1.25.0"
|
||||
LEGACY_TOOLCHAIN = "go1.20.14"
|
||||
|
||||
|
||||
def version_tuple(value):
|
||||
@@ -52,9 +54,10 @@ def required_version(path, module_path):
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def run_go(repo_root, cwd, arguments, go_work):
|
||||
def run_go(cwd, arguments, go_work, toolchain):
|
||||
environment = os.environ.copy()
|
||||
environment["GOWORK"] = str(go_work) if go_work else "off"
|
||||
environment["GOTOOLCHAIN"] = toolchain
|
||||
result = subprocess.run(
|
||||
["go"] + arguments,
|
||||
cwd=str(cwd),
|
||||
@@ -70,6 +73,130 @@ def run_go(repo_root, cwd, arguments, go_work):
|
||||
return result.stdout
|
||||
|
||||
|
||||
def workspace_modules(workspace, toolchain):
|
||||
document = json.loads(
|
||||
run_go(
|
||||
workspace.parent,
|
||||
["work", "edit", "-json"],
|
||||
workspace,
|
||||
toolchain,
|
||||
)
|
||||
)
|
||||
return {
|
||||
(workspace.parent / entry["DiskPath"]).resolve()
|
||||
for entry in document.get("Use", [])
|
||||
}
|
||||
|
||||
|
||||
def display_path(path, repo_root):
|
||||
try:
|
||||
return str(path.relative_to(repo_root))
|
||||
except ValueError:
|
||||
return str(path)
|
||||
|
||||
|
||||
def workspace_layout_violation(workspace, actual, expected, repo_root):
|
||||
if actual == expected:
|
||||
return None
|
||||
actual_names = sorted(display_path(path, repo_root) for path in actual)
|
||||
expected_names = sorted(display_path(path, repo_root) for path in expected)
|
||||
return "{} contains {}, want {}".format(
|
||||
display_path(workspace, repo_root),
|
||||
actual_names,
|
||||
expected_names,
|
||||
)
|
||||
|
||||
|
||||
def validate_workspace_layout(repo_root):
|
||||
root_workspace = repo_root / "go.work"
|
||||
win7_workspace = repo_root / "app-win7" / "go.work"
|
||||
expected = {
|
||||
root_workspace: {
|
||||
(repo_root / "app-modern").resolve(),
|
||||
(repo_root / "core").resolve(),
|
||||
},
|
||||
win7_workspace: {
|
||||
(repo_root / "app-win7").resolve(),
|
||||
(repo_root / "core").resolve(),
|
||||
},
|
||||
}
|
||||
toolchains = {
|
||||
root_workspace: MODERN_TOOLCHAIN,
|
||||
win7_workspace: LEGACY_TOOLCHAIN,
|
||||
}
|
||||
violations = []
|
||||
for workspace, expected_modules in expected.items():
|
||||
actual_modules = workspace_modules(workspace, toolchains[workspace])
|
||||
violation = workspace_layout_violation(
|
||||
workspace,
|
||||
actual_modules,
|
||||
expected_modules,
|
||||
repo_root,
|
||||
)
|
||||
if violation:
|
||||
violations.append(violation)
|
||||
return violations
|
||||
|
||||
|
||||
def resolved_module_version(cwd, workspace, toolchain, module_path):
|
||||
document = json.loads(
|
||||
run_go(
|
||||
cwd,
|
||||
["list", "-m", "-json", module_path],
|
||||
workspace,
|
||||
toolchain,
|
||||
)
|
||||
)
|
||||
return document.get("Version", "")
|
||||
|
||||
|
||||
def module_version_violation(label, module_path, actual, expected):
|
||||
if actual == expected:
|
||||
return None
|
||||
return "{} workspace resolves {} {}, want {}".format(
|
||||
label,
|
||||
module_path,
|
||||
actual,
|
||||
expected,
|
||||
)
|
||||
|
||||
|
||||
def validate_workspace_gio_versions(repo_root):
|
||||
checks = (
|
||||
(
|
||||
"modern",
|
||||
repo_root / "app-modern",
|
||||
repo_root / "go.work",
|
||||
MODERN_TOOLCHAIN,
|
||||
"v0.10.1",
|
||||
),
|
||||
(
|
||||
"win7",
|
||||
repo_root / "app-win7",
|
||||
repo_root / "app-win7" / "go.work",
|
||||
LEGACY_TOOLCHAIN,
|
||||
"v0.6.0",
|
||||
),
|
||||
)
|
||||
violations = []
|
||||
for label, cwd, workspace, toolchain, expected in checks:
|
||||
actual = resolved_module_version(
|
||||
cwd,
|
||||
workspace,
|
||||
toolchain,
|
||||
"gioui.org",
|
||||
)
|
||||
violation = module_version_violation(
|
||||
label,
|
||||
"gioui.org",
|
||||
actual,
|
||||
expected,
|
||||
)
|
||||
if violation:
|
||||
violations.append(violation)
|
||||
return violations
|
||||
|
||||
|
||||
def validate_pins(repo_root):
|
||||
expected_go_directives = {
|
||||
repo_root / "go.work": "1.25.0",
|
||||
@@ -106,7 +233,12 @@ def validate_pins(repo_root):
|
||||
|
||||
|
||||
def validate_go20_toolchain(repo_root):
|
||||
output = run_go(repo_root, repo_root, ["version"], None).strip()
|
||||
output = run_go(
|
||||
repo_root,
|
||||
["version"],
|
||||
None,
|
||||
LEGACY_TOOLCHAIN,
|
||||
).strip()
|
||||
if "go1.20.14" not in output:
|
||||
return ["compatibility scan uses {!r}, want go1.20.14".format(output)]
|
||||
return []
|
||||
@@ -114,22 +246,23 @@ def validate_go20_toolchain(repo_root):
|
||||
|
||||
def validate_module_versions(repo_root):
|
||||
module_sets = (
|
||||
("core", repo_root / "core", None),
|
||||
("core", repo_root / "core", None, LEGACY_TOOLCHAIN),
|
||||
(
|
||||
"win7",
|
||||
repo_root / "app-win7",
|
||||
repo_root / "app-win7" / "go.work",
|
||||
LEGACY_TOOLCHAIN,
|
||||
),
|
||||
)
|
||||
violations = []
|
||||
checked = 0
|
||||
|
||||
for label, cwd, go_work in module_sets:
|
||||
for label, cwd, go_work, toolchain in module_sets:
|
||||
output = run_go(
|
||||
repo_root,
|
||||
cwd,
|
||||
["list", "-m", "-json", "all"],
|
||||
go_work,
|
||||
toolchain,
|
||||
)
|
||||
for module in decode_json_stream(output):
|
||||
checked += 1
|
||||
@@ -153,12 +286,45 @@ def self_check():
|
||||
raise AssertionError("Go 1.20.14 should be accepted")
|
||||
if not version_tuple("1.21")[:2] > MAX_LEGACY_GO_VERSION:
|
||||
raise AssertionError("Go 1.21 should be rejected")
|
||||
fake_root = pathlib.Path("/repo")
|
||||
fake_workspace = fake_root / "go.work"
|
||||
fake_expected = {fake_root / "core", fake_root / "app-modern"}
|
||||
if workspace_layout_violation(
|
||||
fake_workspace,
|
||||
fake_expected,
|
||||
fake_expected,
|
||||
fake_root,
|
||||
):
|
||||
raise AssertionError("matching workspace layout should be accepted")
|
||||
if not workspace_layout_violation(
|
||||
fake_workspace,
|
||||
fake_expected | {fake_root / "app-win7"},
|
||||
fake_expected,
|
||||
fake_root,
|
||||
):
|
||||
raise AssertionError("unexpected workspace module should be rejected")
|
||||
if module_version_violation(
|
||||
"win7",
|
||||
"gioui.org",
|
||||
"v0.6.0",
|
||||
"v0.6.0",
|
||||
):
|
||||
raise AssertionError("matching Gio version should be accepted")
|
||||
if not module_version_violation(
|
||||
"win7",
|
||||
"gioui.org",
|
||||
"v0.10.1",
|
||||
"v0.6.0",
|
||||
):
|
||||
raise AssertionError("mismatched Gio version should be rejected")
|
||||
|
||||
|
||||
def main():
|
||||
self_check()
|
||||
repo_root = pathlib.Path(__file__).resolve().parents[1]
|
||||
violations = validate_pins(repo_root)
|
||||
violations.extend(validate_workspace_layout(repo_root))
|
||||
violations.extend(validate_workspace_gio_versions(repo_root))
|
||||
violations.extend(validate_go20_toolchain(repo_root))
|
||||
module_violations, checked = validate_module_versions(repo_root)
|
||||
violations.extend(module_violations)
|
||||
@@ -169,7 +335,8 @@ def main():
|
||||
raise SystemExit(1)
|
||||
|
||||
print(
|
||||
"Go version check passed: pins valid; {} module records are Go 1.20-compatible.".format(
|
||||
"Go version check passed: workspace isolation and pins valid; "
|
||||
"{} module records are Go 1.20-compatible.".format(
|
||||
checked
|
||||
)
|
||||
)
|
||||
|
||||
@@ -35,7 +35,13 @@ New-Item -ItemType Directory -Force -Path (Join-Path $Root "dist") | Out-Null
|
||||
|
||||
Invoke-Step "Sync root workspace" {
|
||||
$env:GOTOOLCHAIN = "go1.25.0"
|
||||
Remove-Item Env:GOWORK -ErrorAction SilentlyContinue
|
||||
$env:GOWORK = (Resolve-Path "go.work").Path
|
||||
go work sync
|
||||
}
|
||||
|
||||
Invoke-Step "Sync Win7 workspace" {
|
||||
$env:GOTOOLCHAIN = "go1.25.0"
|
||||
$env:GOWORK = (Resolve-Path "app-win7/go.work").Path
|
||||
go work sync
|
||||
}
|
||||
|
||||
@@ -54,7 +60,8 @@ Invoke-Step "Validate core architecture boundary" {
|
||||
}
|
||||
|
||||
Invoke-Step "Validate Go and dependency pins" {
|
||||
$env:GOTOOLCHAIN = "go1.20.14"
|
||||
Remove-Item Env:GOTOOLCHAIN -ErrorAction SilentlyContinue
|
||||
Remove-Item Env:GOWORK -ErrorAction SilentlyContinue
|
||||
python scripts/check_go_versions.py
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ fi
|
||||
mkdir -p dist
|
||||
|
||||
echo "==> Sync root workspace"
|
||||
GOTOOLCHAIN=go1.25.0 go work sync
|
||||
GOTOOLCHAIN=go1.25.0 GOWORK="$ROOT_DIR/go.work" go work sync
|
||||
|
||||
echo "==> Sync Win7 workspace"
|
||||
GOTOOLCHAIN=go1.25.0 GOWORK="$ROOT_DIR/app-win7/go.work" go work sync
|
||||
|
||||
echo "==> Validate harness governance"
|
||||
"$PYTHON" scripts/validate_agent_context.py
|
||||
@@ -38,7 +41,7 @@ echo "==> Validate core architecture boundary"
|
||||
"$PYTHON" scripts/check_core_boundaries.py
|
||||
|
||||
echo "==> Validate Go and dependency pins"
|
||||
GOTOOLCHAIN=go1.20.14 "$PYTHON" scripts/check_go_versions.py
|
||||
"$PYTHON" scripts/check_go_versions.py
|
||||
|
||||
echo "==> Vet and test core with Go 1.20.14"
|
||||
GOTOOLCHAIN=go1.20.14 GOWORK=off go -C core vet ./...
|
||||
|
||||
Reference in New Issue
Block a user