fix(dist): 交叉构建 Linux 包时 tar 的盘符冒号坑(转正斜杠 + --force-local)
在 Windows 上跑 pnpm dist:server:linux 时,packLinuxTarball 传给 tar 的归档路径带盘符,GNU tar 会把 F: 当成主机名去解析远程归档,报 resolve failed 并以退出码 2 失败。现象很误导:包已经整套铺好,只差最后一步打 tar。反斜杠还会被当转义符。 改成路径统一转正斜杠并加 --force-local。该选项在 Linux 上无害(本地路径本来就该走本地分支),因此无条件加上、不做平台分支 —— Linux 上路径没有盘符,这个坑在 CI 与真机上永远复现不了,只在交叉构建时现形。已记入 AGENTS.md 第 5 节第 59 条与 README 的交付验收表。
This commit is contained in:
1 parent
ce9bed73f4
commit
ffde602fb5
3 files changed
+16
-3
No files matched your search
@@ -779,7 +779,12 @@ database / update`。
|
|||||||
schema engine,CLI 运行期按平台扫 `@prisma/engines/schema-engine-debian-openssl-3.0.x` 这类路径,
|
schema engine,CLI 运行期按平台扫 `@prisma/engines/schema-engine-debian-openssl-3.0.x` 这类路径,
|
||||||
而交叉包里只有 `schema-engine-windows.exe`。交叉构建会写入 `.cross-built` 标记,
|
而交叉包里只有 `schema-engine-windows.exe`。交叉构建会写入 `.cross-built` 标记,
|
||||||
`classhelper doctor` 据此提示(别改成静默),`upgrade` 替换程序文件时会按新包有无该标记来增删。
|
`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 噪声。**
|
⑤ **密码永远走 stdin,命令行一律不接受密码;调用服务端模块的工具必须压掉它的 stdout 噪声。**
|
||||||
`classhelper password` 用 `read -s` 优先读 `/dev/tty`、无 tty 回退 stdin(这样既能交互,
|
`classhelper password` 用 `read -s` 优先读 `/dev/tty`、无 tty 回退 stdin(这样既能交互,
|
||||||
|
|||||||
@@ -1251,7 +1251,7 @@ pnpm db:generate && pnpm --filter @classhelper/server db:deploy && pnpm db:seed
|
|||||||
| 安装程序完整生命周期(静默安装 → 启动 → 卸载) | 通过 ✅(安装到 `%LOCALAPPDATA%\Programs`,卸载干净) |
|
| 安装程序完整生命周期(静默安装 → 启动 → 卸载) | 通过 ✅(安装到 `%LOCALAPPDATA%\Programs`,卸载干净) |
|
||||||
| 便捷版(单文件)解包启动 | 通过 ✅(wrapper + 多个进程,主窗口正常) |
|
| 便捷版(单文件)解包启动 | 通过 ✅(wrapper + 多个进程,主窗口正常) |
|
||||||
| Docker / Nginx 部署样例 | 文件已提供;本机无 Docker 未实测 ⚠️ |
|
| 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 已知的时序 / 环境相关用例
|
### 6.3 已知的时序 / 环境相关用例
|
||||||
|
|
||||||
|
|||||||
@@ -787,7 +787,15 @@ function packLinuxTarball() {
|
|||||||
fs.rmSync(LINUX_TARBALL, { force: true });
|
fs.rmSync(LINUX_TARBALL, { force: true });
|
||||||
const topDir = path.basename(staging); // tar 里套一层目录,安装器用 --strip-components=1 展开
|
const topDir = path.basename(staging); // tar 里套一层目录,安装器用 --strip-components=1 展开
|
||||||
log(`打包 ${path.relative(root, LINUX_TARBALL)} ...`);
|
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 digest = crypto.createHash('sha256').update(fs.readFileSync(LINUX_TARBALL)).digest('hex');
|
||||||
const shaFile = `${LINUX_TARBALL}.sha256`;
|
const shaFile = `${LINUX_TARBALL}.sha256`;
|
||||||
|
|||||||
Reference in new issue
Block a user