修复: go vet 的环境失败不许冒充代码缺陷——env-defaults 补 GOCACHE 预检(缺项)+ 安装脚本按输出分类,命中缓存/权限/空间走退出码 2
pi 2026-09-15 指出的是**报文**的问题,而规矩本来就在 `lib/env-defaults.sh:25`:
"失败要**说清是环境问题**并按仓库约定用退出码 2(环境),**不要让它冒充代码缺陷**"。
## 一、缺项:③ 预检了**模块**缓存,没预检 **build** 缓存
```
$ go vet ./... ⇒ internal/middleware/auth.go:9:2: open /root/.cache/go-build/55/…-d: permission denied
[FAIL] go vet / go test 不过 —— **先修好再安装**
```
报错**指着源码文件**说 permission denied,跟着那句话把人送去改代码 —— 而一行 `.go` 都没问题。
**处置(两道)**:
1. `env-defaults.sh` 新增 ③c:**GOCACHE 实测可写**(写一个探针文件,不只看权限位 ——
root 无视权限位,`-w` 会骗人),不可用 ⇒ 人话 + **exit 2**;
2. `install.sh` 那一步按**输出分类**:命中 `permission denied` / `module cache not found` /
`no space left` / `GOCACHE` ⇒ **退出码 2(环境)**、并且**不再说"先修好"**;
没命中 ⇒ 仍按代码缺陷(退出码 1),报文里**明说**是哪种。
**实测(分类逻辑逐字节抽出、只替换"怎么产生输出")**:
| 喂进的输出 | 退出码 |
|---|---|
| `… open /root/.cache/go-build/55/x-d: permission denied` | **2** |
| `go: module cache not found: neither GOMODCACHE nor GOPATH is set` | **2** |
| `./internal/repo/x.go:12:2: undefined: Foo` | **1** |
| `--- FAIL: TestBar` | **1** |
## 二、★ 实现过程中两次把自己的判据写成"永远不会响",都是**实测**抓到的
这两条我记下来,因为它们是同一个形状、而且**都在我手上当天发生**:
**① 先 `rm` 再 `grep`** —— 第一版我写成
```
cat "$GOOUT" >&2
rm -f "$GOOUT" # ← 先删
if grep -qE 'permission denied|…' "$GOOUT"; then # ← 再读,永远读不到
```
⇒ 分类**永远不触发**,所有失败都会被报成代码缺陷(**恰好是 pi 报的那个问题原样保留**)。
改成"先分类、再删"。
**② `set -e` 在 `if ! ( … )` 里被**抑制** —— 探针**恒绿**:
```
if ! ( set -e; : > "$GOCACHE/.agentmail-probe"; rm -f … ); then …
```
实测 `GOCACHE=/proc/self/nonexistent-gc` 时 `mkdir` 与重定向**都报 No such file or directory**,
而探针 **rc=0** ⇒ 判据说"能写"。真因:bash 在**条件上下文**里抑制 `errexit`,
于是子壳不中止、最后一条命令(`rm -f`)返回 0。
⇒ 改成**显式** `|| exit 1`,不依赖 shell 选项在特定上下文里的语义。
**③ 附带:我的预检自己造了一个目录** —— 第一版直接 `mkdir -p "$_am_gocache"`,
而 `go env GOCACHE` 在本沙箱里返回字面量 `off` ⇒ **在当前目录里创建了 `./off`**,
探针写相对路径必然"成功" ⇒ **假绿 + 副作用**("预检"改了工作树,正是刚从 `dist`/`gen:bg` 上
修掉的那一类)。已清掉(`rmdir`),并加了"**必须是绝对路径**,否则 exit 2"。
口径也改成**不依赖 `go env GOCACHE`**:`${GOCACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/go-build}`
(与本文件"只设未设的"一致),`go env` 只作为旁证。
## 三、实测:本机这个缺项是**真的在响**
```
GOCACHE=(未设) ⇒ rc=2
GOCACHE=off ⇒ rc=2
GOCACHE=./rel ⇒ rc=2
GOCACHE=/proc/self/nope ⇒ rc=2
GOCACHE=/tmp/gc-ok ⇒ rc=0
```
而且它**不是**误报 —— 直接问 go 是最权威的:
```
$ GOCACHE=/root/.cache/go-build go build ./internal/repo/
open /root/.cache/go-build/a4/…-d: permission denied
```
⇒ 本机 go 确实写不了 build 缓存 ⇒ precheck 判环境、**exit 2** 是对的。
(`HOME` 未设时 env-defaults 会兜成 `/root`,所以推导出的正是 go 自己会用的那个路径。)
## 四、端到端(`--check` + 可写 GOCACHE)
```
$ GOCACHE=/tmp/gc-ok bash deploy/install.sh --check → 退出码 1
[FAIL] 前端门禁没过(退出码 1)—— 上面标了 [FAIL] 的那一处就是
[ OK ] go vet + go test 通过
+ exit 1 ← bash -x 追到终点那一行
```
- `go vet` 变绿(缓存可写)⇒ 说明 ③c **不是**无条件拦人,只在真不可用时拦;
- 退出码 1 来自**前端门禁那 3 条真红**,不是环境;
- 干跑仍然零副作用:`git status` + `dist` 全量 sha 的指纹**前后一致** ✓。
★ 照实写的取舍:`--check` 现在在 GOCACHE 不可用时会**提前 exit 2**,
于是"诊断全部跑完"那段不会执行。这是**有意的** —— 按仓库约定环境问题用 2 且要早说,
而"跑不完的诊断"本身是环境问题的症状。不是"第一道红吃掉诊断"那个老毛病(那条已修)。
This commit is contained in:
@ -424,10 +424,37 @@ if [[ $CHECK_ONLY -eq 1 ]]; then
|
||||
fi
|
||||
# 环境不再在这里逐个预检 —— 开头 source 的 env-defaults.sh 已经保证
|
||||
# HOME/TMPDIR/GOMODCACHE/PATH 齐备(那道预检是"第四次"的补丁,已被一处取代)。
|
||||
if ! ( cd "$REPO/server" && go vet ./... && go test ./... ); then
|
||||
# ★★ 环境失败**不许冒充代码缺陷**(pi 2026-09-15;规矩本来就在 `lib/env-defaults.sh:25`:
|
||||
# "失败要说清是环境问题…不要让它冒充代码缺陷")。
|
||||
#
|
||||
# 实测过的形状:`go vet ./...` 报
|
||||
# internal/middleware/auth.go:9:2: open /root/.cache/go-build/55/…-d: permission denied
|
||||
# —— 它**指着源码文件**说 permission denied,而一行 .go 都没问题;跟着本步原来那句
|
||||
# "不过 —— 先修好再安装" 就把人送去改代码。pi 用 `go vet ./internal/repo/`(通过)
|
||||
# vs `go vet ./...`(死在缓存条目)两条命令就分开了 ⇒ 真因是 build 缓存不可用。
|
||||
#
|
||||
# 现在**两道**:① `env-defaults.sh` 的 ③c 预检 GOCACHE(可写、探针实测);
|
||||
# ② 这里按**输出分类**兜住剩下的(预检过不了的在 ① 就 exit 2 了,这里是二手保险)。
|
||||
# 分类命中 ⇒ 退出码 **2(环境)**,并且**不再说"先修好"**。
|
||||
GOOUT="$(mktemp -t agentmail-govet-XXXXXX)"
|
||||
if ! ( cd "$REPO/server" && go vet ./... && go test ./... ) >"$GOOUT" 2>&1; then
|
||||
cat "$GOOUT" >&2
|
||||
# ⚠️ 分类必须在 `rm` **之前**读那个文件 —— 先删再 grep 会让这条分类**永远不触发**
|
||||
# (那正是本仓反复出现的形状:判据存在但永远不会响)。
|
||||
if grep -qE 'permission denied|cannot find (package|module)|no space left on device|module cache not found|build cache is required|GOCACHE' "$GOOUT"; then
|
||||
rm -f "$GOOUT"
|
||||
echo " [FAIL] go vet / go test **跑不起来**(环境问题,不是代码缺陷)" >&2
|
||||
echo " 上面报错里出现了缓存/权限/空间类的字样 —— 它常常**指着源码文件**报错," >&2
|
||||
echo " 但一行 .go 都没问题(实测形状:open <GOCACHE>/…-d: permission denied)。" >&2
|
||||
echo " 药方:GOCACHE=<可写目录> 重跑。按仓库约定这算**环境**(退出码 2)。" >&2
|
||||
exit 2
|
||||
fi
|
||||
rm -f "$GOOUT"
|
||||
echo " [FAIL] go vet / go test 不过 —— 先修好再安装" >&2
|
||||
echo " (本次输出里**没有**缓存/权限/空间类字样 ⇒ 按**代码缺陷**处理。)" >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$GOOUT"
|
||||
echo " [ OK ] go vet + go test 通过"
|
||||
cat <<'EOF'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user