另一架构切片不得借用宿主 npm
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 3m55s
Project CI / Backend tests (pull_request) Failing after 16s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m17s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 6m48s
Project CI / Repository checks (pull_request) Failing after 15s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 7m43s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m28s
Project CI / Frontend tests (pull_request) Successful in 8m34s
Project CI / Native shell tests (pull_request) Successful in 12m47s

- runtimeSourceForTarget 对非宿主架构返回 npmCli: null,明令按该发行版自己的安装目录查找 npm
- 覆盖经 npm run 触发(npm_execpath 指向宿主 npm)时两份切片仍各带自己那份 npm 的用例
This commit is contained in:
2026-09-21 12:06:39 +08:00
parent 91f1554ac7
commit 92c05428ec
2 changed files with 26 additions and 5 deletions
@@ -132,7 +132,9 @@ export function runtimeSourceForTarget(
}
return {
nodePath: configured,
npmCli: undefined,
// 明令不使用宿主 npm`npm_execpath`):另一架构的 npm 必须来自它自己那份发行版
// 安装目录,否则两份切片的 npm 来源不同源,架构与来源对不上。null 表示"按 node 目录查找"。
npmCli: null,
licensePath: env[`AGC_NODE_RUNTIME_${key}_LICENSE_PATH`]?.trim(),
};
}
@@ -372,6 +374,7 @@ export function inspectRuntimeSource(
);
}
const nodeDirectory = path.dirname(node);
// `npmCli: null` 表示显式拒绝沿用宿主 npm,只按这份 node 自己的安装目录查找。
const npmCandidates = [
npmCli,
path.join(nodeDirectory, 'node_modules/npm/bin/npm-cli.js'),
@@ -376,10 +376,20 @@ test('universal stages one runtime per architecture with architecture-correct ma
'aarch64-apple-darwin',
'x86_64-apple-darwin',
]);
const manifests = stageNodeRuntimeForTarget(
'universal-apple-darwin',
optionsFor(root, sources),
);
// 模拟经 `npm run` 触发的构建:npm 把宿主的 npm-cli.js 放进环境变量。
// 另一架构的切片必须无视它,只能使用自己发行版目录里的 npm。
const previousNpmExecPath = process.env.npm_execpath;
process.env.npm_execpath = sources.arm64.npmCli;
let manifests;
try {
manifests = stageNodeRuntimeForTarget(
'universal-apple-darwin',
optionsFor(root, sources),
);
} finally {
if (previousNpmExecPath === undefined) delete process.env.npm_execpath;
else process.env.npm_execpath = previousNpmExecPath;
}
assert.deepEqual(
manifests.map((manifest) => `${manifest.platform}-${manifest.arch}`),
['darwin-arm64', 'darwin-x64'],
@@ -400,6 +410,14 @@ test('universal stages one runtime per architecture with architecture-correct ma
assert.ok(
fs.existsSync(path.join(directory, 'node_modules/npm/LICENSE')),
);
// 每份切片必须自带对应架构发行版的 npm,不能借用宿主那一份。
assert.equal(
fs.readFileSync(
path.join(directory, 'node_modules/npm/bin/npm-cli.js'),
'utf8',
),
`// ${manifest.arch}`,
);
}
// 单架构目标仍写扁平目录(与既有发布一致),不产生分架构子目录。
const flat = stageNodeRuntimeForTarget(