From 966c8f9b5dd29672067676bd5ca59b9ef8981a16 Mon Sep 17 00:00:00 2001 From: LoveChengke Date: Sun, 11 Oct 2026 14:14:59 +0800 Subject: [PATCH] =?UTF-8?q?fix(dist):=20Linux=20=E5=8C=85=E6=89=93?= =?UTF-8?q?=E4=B8=8D=E5=87=BA=20tar.gz=20=E2=80=94=E2=80=94=20=E4=BA=A4?= =?UTF-8?q?=E4=BB=98=E7=9B=AE=E5=BD=95=E4=B8=8D=E5=86=8D=E7=94=B1=20stagin?= =?UTF-8?q?g=20=E9=A1=BA=E5=B8=A6=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.3.0 把服务端组装中间物从 `releases/server/<版本>/linux-x64/classhelper-server-linux-x64/` 挪进 `.cache/server-staging/` 之后,`releases/server/<版本>/linux-x64/` 就再没有谁创建它了 —— `tar -czf <那里>/classhelper-server-linux-x64-<版本>.tar.gz` 直接以 `tar (child): ...tar.gz: Cannot open: No such file or directory` 退出码 2 失败。 Windows 侧不受影响(`buildInstaller()` 里有 `mkdirSync(INSTALLER_DIR)`), 所以本地 `pnpm dist:server` 永远踩不到;`release-linux-server.yml` 在 v1.3.0 的 tag 上一跑就红 (run 38109984623 挂在「构建 Linux 安装包」)。补救是幂等的:目录已存在就什么也不做。 `packLinuxTarball()` 的 tar 调用与 1.2.0 逐字节相同,而 1.2.0 的 CI(run 37458412997)是绿的 —— 唯一的差异就是那句隐式创建没了。 --- AGENTS.md | 8 ++++++++ scripts/dist-server.mjs | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index b6fa448..6b4f3a0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1043,6 +1043,14 @@ term / dashboard / database / update / permissions / clients / system`。 并加 `--force-local`。该选项在 Linux 上无害(本地路径本来就该走本地分支),因此无条件加上、 不做平台分支 —— **Linux 上路径没有盘符,这个坑在 CI 与真机上永远复现不了**,只在交叉构建时现形。 + 还有一条**两边都会踩**的:**交付目录必须自己 `mkdir`,别指望谁来顺带创建它。** + `releases/server/<版本>/linux-x64/` 曾经是 staging(`linux-x64/classhelper-server-linux-x64/`)的父目录, + 2026-10-11 把 staging 挪进 `.cache/server-staging/` 之后它就没有创建者了,`tar -czf <那里>/…` + 直接报 `tar (child): …tar.gz: Cannot open: No such file or directory`、退出码 2 —— + **Windows 侧踩不到**(`buildInstaller()` 里有 `mkdirSync(INSTALLER_DIR)`),本地 `pnpm dist:server` + 永远绿的,只有 CI 上那一次 `pnpm dist:server:linux` 才会红(v1.3.0 实测,run 38109984623)。 + 现在 `packLinuxTarball()` 开头显式建目录,别再把这句删掉。 + ⑤ **密码永远走 stdin,命令行一律不接受密码;调用服务端模块的工具必须压掉它的 stdout 噪声。** `classhelper password` 用 `read -s` 优先读 `/dev/tty`、无 tty 回退 stdin(这样既能交互, 也能被验收脚本用管道喂 —— 都不进 history/ps)。输入循环**必须有界**:stdin 结束时 `read` diff --git a/scripts/dist-server.mjs b/scripts/dist-server.mjs index ca3cc87..d1a4672 100644 --- a/scripts/dist-server.mjs +++ b/scripts/dist-server.mjs @@ -797,6 +797,11 @@ function packLinuxTarball() { fs.rmSync(LINUX_TARBALL, { force: true }); const topDir = path.basename(staging); // tar 里套一层目录,安装器用 --strip-components=1 展开 log(`打包 ${path.relative(root, LINUX_TARBALL)} ...`); + // 交付目录**必须自己建**:staging 挪到 .cache/ 之后,`releases/server/<版本>/linux-x64/` + // 不再是谁的父目录,没有这一句 tar 会以 + // `tar (child): ...tar.gz: Cannot open: No such file or directory` 退出码 2 直接失败 + // (Windows 侧有 buildInstaller() 里的 mkdirSync(INSTALLER_DIR),Linux 侧原先靠 staging 顺带创建)。 + fs.mkdirSync(path.dirname(LINUX_TARBALL), { recursive: true }); // GNU tar 在 Windows 路径上有两个坑(Linux 上路径没有盘符、没有反斜杠,永远踩不到, // 只有交叉构建会碰到): // ① `-f F:\...tar.gz` 里的**盘符冒号**会被当成 `主机:路径` 的远程归档写法,