diff --git a/AGENTS.md b/AGENTS.md index 4f6ce20..b2f63dc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -779,7 +779,12 @@ database / update`。 schema engine,CLI 运行期按平台扫 `@prisma/engines/schema-engine-debian-openssl-3.0.x` 这类路径, 而交叉包里只有 `schema-engine-windows.exe`。交叉构建会写入 `.cross-built` 标记, `classhelper doctor` 据此提示(别改成静默),`upgrade` 替换程序文件时会按新包有无该标记来增删。 - 正式产物仍走 CI。 + 正式产物仍走 CI。**交叉构建时 `tar` 还有两个 Windows 专有坑**(`packLinuxTarball()`): + `-f F:\...tar.gz` 里的**盘符冒号**会被 GNU tar 当成 `主机:路径` 的远程归档写法,报 + `tar (child): Cannot connect to F: resolve failed`、退出码 2 —— 现象很误导:包已经整套铺好、 + 就差最后打 tar 那一步失败。反斜杠还会被当成转义符。所以那一步把路径统一转成**正斜杠** + 并加 `--force-local`。该选项在 Linux 上无害(本地路径本来就该走本地分支),因此无条件加上、 + 不做平台分支 —— **Linux 上路径没有盘符,这个坑在 CI 与真机上永远复现不了**,只在交叉构建时现形。 ⑤ **密码永远走 stdin,命令行一律不接受密码;调用服务端模块的工具必须压掉它的 stdout 噪声。** `classhelper password` 用 `read -s` 优先读 `/dev/tty`、无 tty 回退 stdin(这样既能交互, diff --git a/README.md b/README.md index 2e77e77..deff4c0 100644 --- a/README.md +++ b/README.md @@ -1251,7 +1251,7 @@ pnpm db:generate && pnpm --filter @classhelper/server db:deploy && pnpm db:seed | 安装程序完整生命周期(静默安装 → 启动 → 卸载) | 通过 ✅(安装到 `%LOCALAPPDATA%\Programs`,卸载干净) | | 便捷版(单文件)解包启动 | 通过 ✅(wrapper + 多个进程,主窗口正常) | | Docker / Nginx 部署样例 | 文件已提供;本机无 Docker 未实测 ⚠️ | -| Linux 一键安装 + `classhelper` 运维命令(`deploy/install.sh` / `deploy/classhelper` / `pnpm dist:server:linux`) | 脚本与文档已交付,本地静态检查通过(`bash -n`、ESLint 0 error);**Linux 实机验收待做** ⚠️(清单见 [linux-deploy.md](docs/linux-deploy.md) §10,`deploy/verify-linux.sh` 可自动跑) | +| Linux 一键安装 + `classhelper` 运维命令(`deploy/install.sh` / `deploy/classhelper` / `pnpm dist:server:linux`) | 脚本与文档已交付,本地静态检查通过(`bash -n`、ESLint 0 error);**Linux 实机验收待做** ⚠️(清单见 [linux-deploy.md](docs/linux-deploy.md) §10,`deploy/verify-linux.sh` 可自动跑)。2026-10-06 用交叉构建出了 1.1.2 的包并核对过内容(sha256 自洽、顶层目录与 `--strip-components=1` 对得上、`.cross-built` 标记在位、包内是新图标),但**没在 Linux 上跑过** —— 正式发布仍走 CI | ### 6.3 已知的时序 / 环境相关用例 diff --git a/scripts/dist-server.mjs b/scripts/dist-server.mjs index 4515843..eaf2236 100644 --- a/scripts/dist-server.mjs +++ b/scripts/dist-server.mjs @@ -787,7 +787,15 @@ function packLinuxTarball() { fs.rmSync(LINUX_TARBALL, { force: true }); const topDir = path.basename(staging); // tar 里套一层目录,安装器用 --strip-components=1 展开 log(`打包 ${path.relative(root, LINUX_TARBALL)} ...`); - run('tar', ['-czf', LINUX_TARBALL, '-C', path.dirname(staging), topDir]); + // GNU tar 在 Windows 路径上有两个坑(Linux 上路径没有盘符、没有反斜杠,永远踩不到, + // 只有交叉构建会碰到): + // ① `-f F:\...tar.gz` 里的**盘符冒号**会被当成 `主机:路径` 的远程归档写法, + // 报 `tar (child): Cannot connect to F: resolve failed` 并以退出码 2 失败; + // ② 反斜杠会被当成转义符。 + // 因此统一转成正斜杠,并加 `--force-local` 明确"这是本地文件"。 + // 该选项在 Linux 上无害(本地路径本来就该走本地分支),所以无条件加上,不做平台分支。 + const toPosix = (target) => target.replace(/\\/g, '/'); + run('tar', ['--force-local', '-czf', toPosix(LINUX_TARBALL), '-C', toPosix(path.dirname(staging)), topDir]); const digest = crypto.createHash('sha256').update(fs.readFileSync(LINUX_TARBALL)).digest('hex'); const shaFile = `${LINUX_TARBALL}.sha256`;