@pnpm/bins.linker 1000.2.6 → 1100.0.1
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/index.js +30 -38
- package/package.json +20 -21
package/lib/index.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { existsSync, promises as fs } from 'node:fs';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { getBinsFromPackageManifest } from '@pnpm/bins.resolver';
|
|
5
|
-
import { getBunBinLocationForCurrentOS, getDenoBinLocationForCurrentOS, getNodeBinLocationForCurrentOS } from '@pnpm/constants';
|
|
4
|
+
import { getBinsFromPackageManifest, pkgOwnsBin } from '@pnpm/bins.resolver';
|
|
6
5
|
import { PnpmError } from '@pnpm/error';
|
|
7
6
|
import { readModulesDir } from '@pnpm/fs.read-modules-dir';
|
|
8
7
|
import { globalWarn, logger } from '@pnpm/logger';
|
|
9
8
|
import { readPackageJsonFromDir } from '@pnpm/pkg-manifest.reader';
|
|
10
9
|
import { getAllDependenciesFromManifest } from '@pnpm/pkg-manifest.utils';
|
|
11
10
|
import { safeReadProjectManifestOnly } from '@pnpm/workspace.project-manifest-reader';
|
|
12
|
-
import cmdShim from '@zkochan/cmd-shim';
|
|
11
|
+
import { cmdShim, isShimPointingAt } from '@zkochan/cmd-shim';
|
|
13
12
|
import { rimraf } from '@zkochan/rimraf';
|
|
14
13
|
import fixBin from 'bin-links/lib/fix-bin.js';
|
|
15
14
|
import { isSubdir } from 'is-subdir';
|
|
@@ -17,12 +16,14 @@ import isWindows from 'is-windows';
|
|
|
17
16
|
import normalizePath from 'normalize-path';
|
|
18
17
|
import { groupBy, isEmpty, partition, unnest } from 'ramda';
|
|
19
18
|
import semver from 'semver';
|
|
20
|
-
import symlinkDir from 'symlink-dir';
|
|
19
|
+
import { symlinkDir } from 'symlink-dir';
|
|
21
20
|
import { getBinNodePaths } from './getBinNodePaths.js';
|
|
22
21
|
const binsConflictLogger = logger('bins-conflict');
|
|
23
22
|
const IS_WINDOWS = isWindows();
|
|
24
23
|
const EXECUTABLE_SHEBANG_SUPPORTED = !IS_WINDOWS;
|
|
25
24
|
const POWER_SHELL_IS_SUPPORTED = IS_WINDOWS;
|
|
25
|
+
// A cmd-shim is a small shell script. Anything larger is a binary and should not be read.
|
|
26
|
+
const CMD_SHIM_MAX_SIZE = 4 * 1024;
|
|
26
27
|
export async function linkBins(modulesDir, binsDir, opts) {
|
|
27
28
|
const allDeps = await readModulesDir(modulesDir);
|
|
28
29
|
// If the modules dir does not exist, do nothing
|
|
@@ -105,9 +106,12 @@ function resolveCommandConflicts(group, binsDir) {
|
|
|
105
106
|
});
|
|
106
107
|
}
|
|
107
108
|
function compareCommandsInConflict(a, b) {
|
|
108
|
-
|
|
109
|
+
// Check ownership: a package that owns the bin name gets priority
|
|
110
|
+
const aOwns = pkgOwnsBin(a.name, a.pkgName);
|
|
111
|
+
const bOwns = pkgOwnsBin(b.name, b.pkgName);
|
|
112
|
+
if (aOwns && !bOwns)
|
|
109
113
|
return 1;
|
|
110
|
-
if (!
|
|
114
|
+
if (!aOwns && bOwns)
|
|
111
115
|
return -1;
|
|
112
116
|
if (a.pkgName !== b.pkgName)
|
|
113
117
|
return a.pkgName.localeCompare(b.pkgName); // it's pointless to compare versions of 2 different package
|
|
@@ -132,37 +136,6 @@ async function getPackageBins(opts, target) {
|
|
|
132
136
|
? await safeReadProjectManifestOnly(target)
|
|
133
137
|
: await safeReadPkgJson(target);
|
|
134
138
|
if (manifest == null) {
|
|
135
|
-
// There is a probably a better way to do this.
|
|
136
|
-
// It isn't good to have these hardcoded here.
|
|
137
|
-
switch (path.basename(target)) {
|
|
138
|
-
case 'node':
|
|
139
|
-
return [{
|
|
140
|
-
name: 'node',
|
|
141
|
-
path: path.join(target, getNodeBinLocationForCurrentOS()),
|
|
142
|
-
ownName: true,
|
|
143
|
-
pkgName: '',
|
|
144
|
-
pkgVersion: '',
|
|
145
|
-
makePowerShellShim: false,
|
|
146
|
-
}];
|
|
147
|
-
case 'deno':
|
|
148
|
-
return [{
|
|
149
|
-
name: 'deno',
|
|
150
|
-
path: path.join(target, getDenoBinLocationForCurrentOS()),
|
|
151
|
-
ownName: true,
|
|
152
|
-
pkgName: '',
|
|
153
|
-
pkgVersion: '',
|
|
154
|
-
makePowerShellShim: false,
|
|
155
|
-
}];
|
|
156
|
-
case 'bun':
|
|
157
|
-
return [{
|
|
158
|
-
name: 'bun',
|
|
159
|
-
path: path.join(target, getBunBinLocationForCurrentOS()),
|
|
160
|
-
ownName: true,
|
|
161
|
-
pkgName: '',
|
|
162
|
-
pkgVersion: '',
|
|
163
|
-
makePowerShellShim: false,
|
|
164
|
-
}];
|
|
165
|
-
}
|
|
166
139
|
// There's a directory in node_modules without package.json: ${target}.
|
|
167
140
|
// This used to be a warning but it didn't really cause any issues.
|
|
168
141
|
return [];
|
|
@@ -191,7 +164,6 @@ async function getPackageBinsFromManifest(manifest, pkgDir) {
|
|
|
191
164
|
}
|
|
192
165
|
return cmds.map((cmd) => ({
|
|
193
166
|
...cmd,
|
|
194
|
-
ownName: cmd.name === manifest.name,
|
|
195
167
|
pkgName: manifest.name,
|
|
196
168
|
pkgVersion: manifest.version,
|
|
197
169
|
makePowerShellShim: POWER_SHELL_IS_SUPPORTED && manifest.name !== 'pnpm',
|
|
@@ -206,6 +178,26 @@ function runtimeHasNodeDownloaded(runtime) {
|
|
|
206
178
|
}
|
|
207
179
|
async function linkBin(cmd, binsDir, opts) {
|
|
208
180
|
const externalBinPath = path.join(binsDir, cmd.name);
|
|
181
|
+
// Skip if the existing bin already references the correct target.
|
|
182
|
+
// This avoids redundant I/O on warm installs and EACCES on read-only stores.
|
|
183
|
+
// We verify the target path — not just existence — so that conflict resolution
|
|
184
|
+
// changes or provider swaps still get the bin rewritten.
|
|
185
|
+
try {
|
|
186
|
+
const stat = await fs.lstat(externalBinPath);
|
|
187
|
+
if (stat.isSymbolicLink()) {
|
|
188
|
+
const target = await fs.readlink(externalBinPath);
|
|
189
|
+
if (target === cmd.path || path.resolve(binsDir, target) === path.resolve(cmd.path)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
else if (stat.isFile() && stat.size < CMD_SHIM_MAX_SIZE) {
|
|
194
|
+
const content = await fs.readFile(externalBinPath, 'utf8');
|
|
195
|
+
if (isShimPointingAt(content, cmd.path)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch { }
|
|
209
201
|
if (IS_WINDOWS) {
|
|
210
202
|
const exePath = path.join(binsDir, `${cmd.name}${getExeExtension()}`);
|
|
211
203
|
if (existsSync(exePath)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/bins.linker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1100.0.1",
|
|
4
4
|
"description": "Link bins to node_modules/.bin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -25,39 +25,38 @@
|
|
|
25
25
|
"!*.map"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@zkochan/cmd-shim": "^
|
|
28
|
+
"@zkochan/cmd-shim": "^9.0.0",
|
|
29
29
|
"@zkochan/rimraf": "^4.0.0",
|
|
30
|
-
"bin-links": "^
|
|
30
|
+
"bin-links": "^6.0.0",
|
|
31
31
|
"is-subdir": "^2.0.0",
|
|
32
32
|
"is-windows": "^1.0.2",
|
|
33
33
|
"normalize-path": "^3.0.0",
|
|
34
34
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
35
35
|
"semver": "^7.7.2",
|
|
36
|
-
"symlink-dir": "^
|
|
37
|
-
"@pnpm/error": "
|
|
38
|
-
"@pnpm/
|
|
39
|
-
"@pnpm/
|
|
40
|
-
"@pnpm/
|
|
41
|
-
"@pnpm/pkg-manifest.
|
|
42
|
-
"@pnpm/
|
|
43
|
-
"@pnpm/
|
|
44
|
-
"@pnpm/types": "1000.9.0"
|
|
36
|
+
"symlink-dir": "^10.0.1",
|
|
37
|
+
"@pnpm/error": "1100.0.0",
|
|
38
|
+
"@pnpm/pkg-manifest.utils": "1100.0.1",
|
|
39
|
+
"@pnpm/fs.read-modules-dir": "1100.0.0",
|
|
40
|
+
"@pnpm/bins.resolver": "1100.0.1",
|
|
41
|
+
"@pnpm/pkg-manifest.reader": "1100.0.1",
|
|
42
|
+
"@pnpm/workspace.project-manifest-reader": "1100.0.1",
|
|
43
|
+
"@pnpm/types": "1101.0.0"
|
|
45
44
|
},
|
|
46
45
|
"peerDependencies": {
|
|
47
46
|
"@pnpm/logger": ">=1001.0.0 <1002.0.0"
|
|
48
47
|
},
|
|
49
48
|
"devDependencies": {
|
|
50
|
-
"@jest/globals": "30.0
|
|
49
|
+
"@jest/globals": "30.3.0",
|
|
51
50
|
"@types/is-windows": "^1.0.2",
|
|
52
|
-
"@types/node": "^22.19.
|
|
51
|
+
"@types/node": "^22.19.15",
|
|
53
52
|
"@types/normalize-path": "^3.0.2",
|
|
54
|
-
"@types/ramda": "0.
|
|
53
|
+
"@types/ramda": "0.31.1",
|
|
55
54
|
"@types/semver": "7.7.1",
|
|
56
55
|
"cmd-extension": "^2.0.0",
|
|
57
56
|
"tempy": "3.0.0",
|
|
58
|
-
"@pnpm/bins.linker": "
|
|
59
|
-
"@pnpm/logger": "
|
|
60
|
-
"@pnpm/test-fixtures": "
|
|
57
|
+
"@pnpm/bins.linker": "1100.0.1",
|
|
58
|
+
"@pnpm/logger": "1100.0.0",
|
|
59
|
+
"@pnpm/test-fixtures": "1100.0.0"
|
|
61
60
|
},
|
|
62
61
|
"engines": {
|
|
63
62
|
"node": ">=22.13"
|
|
@@ -67,9 +66,9 @@
|
|
|
67
66
|
},
|
|
68
67
|
"scripts": {
|
|
69
68
|
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
70
|
-
"
|
|
71
|
-
"test": "pnpm run compile && pnpm run _test",
|
|
69
|
+
"test": "pn compile && pn .test",
|
|
72
70
|
"fix": "tslint -c tslint.json --project . --fix",
|
|
73
|
-
"compile": "tsgo --build &&
|
|
71
|
+
"compile": "tsgo --build && pn lint --fix",
|
|
72
|
+
".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
|
|
74
73
|
}
|
|
75
74
|
}
|