@bobfrankston/npmglobalize 1.0.207 → 1.0.208
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib.js +61 -4
- package/package.json +1 -1
package/lib.js
CHANGED
|
@@ -4299,6 +4299,56 @@ async function waitForNpmVersionInWsl(spec, maxWaitMs = 180000) {
|
|
|
4299
4299
|
process.stdout.write(' timed out\n');
|
|
4300
4300
|
return false;
|
|
4301
4301
|
}
|
|
4302
|
+
/** After a global WSL install, confirm a NON-interactive shell actually resolves
|
|
4303
|
+
* the binaries we just installed, rather than older copies of them.
|
|
4304
|
+
*
|
|
4305
|
+
* WSL's npm prefix is per-user (~/.npm-global), and that directory reaches PATH
|
|
4306
|
+
* only via ~/.bashrc — which returns immediately when the shell is not
|
|
4307
|
+
* interactive. Every `wsl <cmd>` is non-interactive, so it searches the default
|
|
4308
|
+
* PATH from /etc/environment instead, where a stale /usr/local/bin entry left by
|
|
4309
|
+
* an earlier root-prefix install keeps winning. The install genuinely succeeds
|
|
4310
|
+
* and the version reported by `wsl <tool>` is genuinely stale, which is exactly
|
|
4311
|
+
* why this went unnoticed for four months. Repair with a symlink rather than a
|
|
4312
|
+
* copy, so it tracks later installs on its own. */
|
|
4313
|
+
async function verifyWslGlobalBins(cwd) {
|
|
4314
|
+
let names = [];
|
|
4315
|
+
try {
|
|
4316
|
+
const pkg = readPackageJson(cwd);
|
|
4317
|
+
if (typeof pkg?.bin === 'string')
|
|
4318
|
+
names = [String(pkg.name || '').split('/').pop()].filter(Boolean);
|
|
4319
|
+
else if (pkg?.bin && typeof pkg.bin === 'object')
|
|
4320
|
+
names = Object.keys(pkg.bin);
|
|
4321
|
+
}
|
|
4322
|
+
catch {
|
|
4323
|
+
return;
|
|
4324
|
+
}
|
|
4325
|
+
if (!names.length)
|
|
4326
|
+
return;
|
|
4327
|
+
const prefixResult = await runCommandAsync('wsl', ['npm', 'config', 'get', 'prefix'], { silent: true });
|
|
4328
|
+
const prefix = (prefixResult.output || '').trim();
|
|
4329
|
+
if (!prefixResult.success || !prefix.startsWith('/'))
|
|
4330
|
+
return;
|
|
4331
|
+
for (const name of names) {
|
|
4332
|
+
const expected = `${prefix}/bin/${name}`;
|
|
4333
|
+
// `bash -c` is non-interactive — the same shape as a bare `wsl <cmd>`,
|
|
4334
|
+
// which is the case that breaks. A login shell would mask the problem.
|
|
4335
|
+
const lookup = await runCommandAsync('wsl', ['bash', '-c', `command -v ${name} || true`], { silent: true });
|
|
4336
|
+
const found = (lookup.output || '').trim();
|
|
4337
|
+
if (!found || found === expected)
|
|
4338
|
+
continue;
|
|
4339
|
+
console.log(colors.yellow(` WSL resolves ${name} to ${found}, not the copy just installed at ${expected}`));
|
|
4340
|
+
if (!found.startsWith('/usr/local/bin/')) {
|
|
4341
|
+
recordBuildIssue(name, 'warning', `WSL resolves ${name} to ${found} instead of ${expected}, so scripts run a different version than an interactive shell does. Left alone: only /usr/local/bin shadows are repaired automatically.`);
|
|
4342
|
+
continue;
|
|
4343
|
+
}
|
|
4344
|
+
const repair = await runCommandAsync('wsl', ['bash', '-c', `sudo -n rm -f ${found} && sudo -n ln -s ${expected} ${found}`], { silent: true });
|
|
4345
|
+
if (repair.success) {
|
|
4346
|
+
console.log(colors.green(` ✓ Repaired WSL shadow: ${found} -> ${expected}`));
|
|
4347
|
+
continue;
|
|
4348
|
+
}
|
|
4349
|
+
recordBuildIssue(name, 'warning', `WSL resolves ${name} to a stale ${found}. Repair with: wsl sudo rm ${found} && wsl sudo ln -s ${expected} ${found}`);
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4302
4352
|
export async function installInWsl(wslArgs, opts = {}) {
|
|
4303
4353
|
// Same trust rule as the Windows installs: allow our own packages'
|
|
4304
4354
|
// install scripts, leave third-party ones gated. Probed against WSL's
|
|
@@ -4317,9 +4367,16 @@ export async function installInWsl(wslArgs, opts = {}) {
|
|
|
4317
4367
|
process.stderr.write(r.stderr);
|
|
4318
4368
|
return r;
|
|
4319
4369
|
};
|
|
4370
|
+
// Every success path leaves through here, so the shadow check cannot be
|
|
4371
|
+
// skipped by whichever retry happened to be the one that worked.
|
|
4372
|
+
const succeed = async (fixed) => {
|
|
4373
|
+
if (opts.cwd && wslArgs.includes('-g'))
|
|
4374
|
+
await verifyWslGlobalBins(opts.cwd);
|
|
4375
|
+
return { success: true, fixed };
|
|
4376
|
+
};
|
|
4320
4377
|
let result = await runOnce();
|
|
4321
4378
|
if (result.success)
|
|
4322
|
-
return
|
|
4379
|
+
return await succeed(false);
|
|
4323
4380
|
let combined = (result.output || '') + '\n' + (result.stderr || '');
|
|
4324
4381
|
// EACCES on a root-owned npm prefix → switch to a user prefix and retry.
|
|
4325
4382
|
if (/EACCES/.test(combined) && /\/usr\/(?:local\/)?lib\/node_modules/.test(combined)) {
|
|
@@ -4335,7 +4392,7 @@ export async function installInWsl(wslArgs, opts = {}) {
|
|
|
4335
4392
|
console.log(colors.green('✓ WSL npm prefix set to ~/.npm-global; PATH appended to ~/.bashrc'));
|
|
4336
4393
|
result = await runOnce();
|
|
4337
4394
|
if (result.success)
|
|
4338
|
-
return
|
|
4395
|
+
return await succeed(true);
|
|
4339
4396
|
combined = (result.output || '') + '\n' + (result.stderr || '');
|
|
4340
4397
|
}
|
|
4341
4398
|
// E404 on a scoped package has TWO causes, and npm gives the same error for
|
|
@@ -4352,7 +4409,7 @@ export async function installInWsl(wslArgs, opts = {}) {
|
|
|
4352
4409
|
console.log(colors.green('✓ Synced npm token to WSL'));
|
|
4353
4410
|
result = await runOnce();
|
|
4354
4411
|
if (result.success)
|
|
4355
|
-
return
|
|
4412
|
+
return await succeed(true);
|
|
4356
4413
|
}
|
|
4357
4414
|
else {
|
|
4358
4415
|
console.error(colors.yellow(' Could not authenticate WSL npm. Run `wsl npm login` (or sync your ~/.npmrc token) and retry.'));
|
|
@@ -4364,7 +4421,7 @@ export async function installInWsl(wslArgs, opts = {}) {
|
|
|
4364
4421
|
if (await waitForNpmVersionInWsl(spec)) {
|
|
4365
4422
|
result = await runOnce();
|
|
4366
4423
|
if (result.success)
|
|
4367
|
-
return
|
|
4424
|
+
return await succeed(true);
|
|
4368
4425
|
}
|
|
4369
4426
|
else {
|
|
4370
4427
|
console.error(colors.yellow(` ${spec} still not visible to WSL's npm after waiting — try the WSL install again shortly.`));
|