@pnpm/engine.pm.commands 1000.0.0 → 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.
@@ -1,6 +1,6 @@
1
1
  import { type GlobalAddOptions } from '@pnpm/global.commands';
2
2
  import type { EnvLockfile } from '@pnpm/lockfile.types';
3
- import type { StoreController } from '@pnpm/store.controller';
3
+ import { type StoreController } from '@pnpm/store.controller';
4
4
  import type { Registries } from '@pnpm/types';
5
5
  export interface InstallPnpmResult {
6
6
  binDir: string;
@@ -2,12 +2,17 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import util from 'node:util';
4
4
  import { linkBins } from '@pnpm/bins.linker';
5
+ import { createAllowBuildFunction } from '@pnpm/building.policy';
5
6
  import { getCurrentPackageName } from '@pnpm/cli.meta';
6
7
  import { iterateHashedGraphNodes, iteratePkgMeta, lockfileToDepGraph, } from '@pnpm/deps.graph-hasher';
7
8
  import { installGlobalPackages } from '@pnpm/global.commands';
8
9
  import { cleanOrphanedInstallDirs, createGlobalCacheKey, createInstallDir, findGlobalPackage, getHashLink, } from '@pnpm/global.packages';
9
10
  import { headlessInstall } from '@pnpm/installing.deps-restorer';
10
- import symlinkDir from 'symlink-dir';
11
+ import { registerProject } from '@pnpm/store.controller';
12
+ import { symlinkDir } from 'symlink-dir';
13
+ // @pnpm/exe has platform-specific binaries, so its GVS hash must
14
+ // include ENGINE_NAME for correct per-platform resolution.
15
+ const PNPM_ALLOW_BUILDS = { '@pnpm/exe': true };
11
16
  /**
12
17
  * Installs pnpm to the global packages directory (for self-update).
13
18
  * Creates an entry in globalPkgDir that is visible to `pnpm ls -g`.
@@ -34,7 +39,7 @@ export async function installPnpmToStore(pnpmVersion, opts) {
34
39
  const wantedLockfile = buildLockfileFromEnvLockfile(opts.envLockfile, currentPkgName, pnpmVersion);
35
40
  const globalVirtualStoreDir = path.join(opts.storeDir, 'links');
36
41
  // Compute the GVS hash for the pnpm package to find its path
37
- const pnpmGvsPath = findPnpmGvsPath(wantedLockfile, currentPkgName, globalVirtualStoreDir);
42
+ const pnpmGvsPath = findPnpmGvsPath(wantedLockfile, currentPkgName, globalVirtualStoreDir, PNPM_ALLOW_BUILDS);
38
43
  const pnpmPkgDir = path.join(pnpmGvsPath, 'node_modules', currentPkgName);
39
44
  const binDir = path.join(pnpmGvsPath, 'bin');
40
45
  // Check if already installed in the GVS
@@ -51,6 +56,7 @@ export async function installPnpmToStore(pnpmVersion, opts) {
51
56
  try {
52
57
  await installFromLockfile(tmpInstallDir, binDir, {
53
58
  wantedLockfile,
59
+ allowBuilds: PNPM_ALLOW_BUILDS,
54
60
  storeController: opts.storeController,
55
61
  storeDir: opts.storeDir,
56
62
  registries: opts.registries,
@@ -70,10 +76,11 @@ export async function installPnpmToStore(pnpmVersion, opts) {
70
76
  }
71
77
  }
72
78
  function noop(_message) { }
73
- function findPnpmGvsPath(lockfile, pkgName, globalVirtualStoreDir) {
79
+ function findPnpmGvsPath(lockfile, pkgName, globalVirtualStoreDir, allowBuilds) {
74
80
  const graph = lockfileToDepGraph(lockfile);
75
81
  const pkgMetaIterator = iteratePkgMeta(lockfile, graph);
76
- for (const { hash, pkgMeta } of iterateHashedGraphNodes(graph, pkgMetaIterator)) {
82
+ const allowBuild = createAllowBuildFunction({ allowBuilds });
83
+ for (const { hash, pkgMeta } of iterateHashedGraphNodes(graph, pkgMetaIterator, allowBuild)) {
77
84
  if (pkgMeta.name === pkgName) {
78
85
  return path.join(globalVirtualStoreDir, hash);
79
86
  }
@@ -110,12 +117,18 @@ async function installPnpmToGlobalDir(opts, pkgName, version, wantedLockfile) {
110
117
  if (wantedLockfile != null && opts.storeController != null && opts.storeDir != null) {
111
118
  await installFromLockfile(installDir, binDir, {
112
119
  wantedLockfile,
120
+ allowBuilds: PNPM_ALLOW_BUILDS,
113
121
  storeController: opts.storeController,
114
122
  storeDir: opts.storeDir,
115
123
  registries: opts.registries,
116
124
  virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
117
125
  packageManager: opts.packageManager,
118
126
  });
127
+ // headlessInstall does not register the project, so we must do it
128
+ // explicitly. Without this, `pnpm store prune` would not know about
129
+ // this install directory and would remove its packages from the
130
+ // global virtual store.
131
+ await registerProject(opts.storeDir, installDir);
119
132
  }
120
133
  else {
121
134
  await installFromResolution(installDir, opts, [`${pkgName}@${version}`]);
@@ -150,8 +163,8 @@ async function installFromLockfile(installDir, binDir, opts) {
150
163
  registries: opts.registries,
151
164
  enableGlobalVirtualStore: true,
152
165
  globalVirtualStoreDir: path.join(opts.storeDir, 'links'),
166
+ allowBuilds: opts.allowBuilds,
153
167
  ignoreScripts: true,
154
- ignoreDepScripts: true,
155
168
  force: false,
156
169
  engineStrict: false,
157
170
  currentEngine: {
@@ -177,7 +190,7 @@ async function installFromLockfile(installDir, binDir, opts) {
177
190
  virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
178
191
  sideEffectsCacheRead: false,
179
192
  sideEffectsCacheWrite: false,
180
- rawConfig: {},
193
+ configByUri: {},
181
194
  unsafePerm: false,
182
195
  userAgent: '',
183
196
  packageManager: opts.packageManager ?? { name: 'pnpm', version: '' },
@@ -238,6 +251,18 @@ export function linkExePlatformBinary(installDir) {
238
251
  if (!fs.existsSync(src))
239
252
  return;
240
253
  const dest = path.join(exePkgDir, executable);
254
+ forceLink(src, dest);
255
+ if (platform === 'win') {
256
+ const exePkgJsonPath = path.join(exePkgDir, 'package.json');
257
+ const exePkg = JSON.parse(fs.readFileSync(exePkgJsonPath, 'utf8'));
258
+ exePkg.bin.pnpm = 'pnpm.exe';
259
+ exePkg.bin.pn = 'pn.cmd';
260
+ exePkg.bin.pnpx = 'pnpx.cmd';
261
+ exePkg.bin.pnx = 'pnx.cmd';
262
+ fs.writeFileSync(exePkgJsonPath, JSON.stringify(exePkg, null, 2));
263
+ }
264
+ }
265
+ function forceLink(src, dest) {
241
266
  try {
242
267
  fs.unlinkSync(dest);
243
268
  }
@@ -248,13 +273,6 @@ export function linkExePlatformBinary(installDir) {
248
273
  }
249
274
  fs.linkSync(src, dest);
250
275
  fs.chmodSync(dest, 0o755);
251
- if (platform === 'win') {
252
- const exePkgJsonPath = path.join(exePkgDir, 'package.json');
253
- const exePkg = JSON.parse(fs.readFileSync(exePkgJsonPath, 'utf8'));
254
- fs.writeFileSync(path.join(exePkgDir, 'pnpm'), 'This file intentionally left blank');
255
- exePkg.bin.pnpm = 'pnpm.exe';
256
- fs.writeFileSync(exePkgJsonPath, JSON.stringify(exePkg, null, 2));
257
- }
258
276
  }
259
277
  function buildLockfileFromEnvLockfile(envLockfile, pkgName, version) {
260
278
  const dependencies = {};
@@ -1,9 +1,9 @@
1
- import { type Config } from '@pnpm/config.reader';
1
+ import { type Config, type ConfigContext } from '@pnpm/config.reader';
2
2
  import { type CreateStoreControllerOptions } from '@pnpm/store.connection-manager';
3
3
  export declare function rcOptionsTypes(): Record<string, unknown>;
4
4
  export declare function cliOptionsTypes(): Record<string, unknown>;
5
5
  export declare const commandNames: string[];
6
6
  export declare const skipPackageManagerCheck = true;
7
7
  export declare function help(): string;
8
- export type SelfUpdateCommandOptions = CreateStoreControllerOptions & Pick<Config, 'globalPkgDir' | 'lockfileDir' | 'managePackageManagerVersions' | 'modulesDir' | 'pnpmHomeDir' | 'rootProjectManifestDir' | 'wantedPackageManager'>;
8
+ export type SelfUpdateCommandOptions = CreateStoreControllerOptions & Pick<Config, 'globalPkgDir' | 'lockfileDir' | 'managePackageManagerVersions' | 'modulesDir' | 'pnpmHomeDir'> & Pick<ConfigContext, 'rootProjectManifestDir' | 'wantedPackageManager'>;
9
9
  export declare function handler(opts: SelfUpdateCommandOptions, params: string[]): Promise<undefined | string>;
@@ -41,7 +41,7 @@ export async function handler(opts, params) {
41
41
  if (isExecutedByCorepack()) {
42
42
  throw new PnpmError('CANT_SELF_UPDATE_IN_COREPACK', 'You should update pnpm with corepack');
43
43
  }
44
- const { resolve } = createResolver({ ...opts, authConfig: opts.rawConfig });
44
+ const { resolve } = createResolver({ ...opts, configByUri: opts.configByUri });
45
45
  const pkgName = 'pnpm';
46
46
  const bareSpecifier = params[0] ?? 'latest';
47
47
  const resolution = await resolve({ alias: pkgName, bareSpecifier }, {
@@ -108,8 +108,8 @@ export async function handler(opts, params) {
108
108
  storeController: store.ctrl,
109
109
  storeDir: store.dir,
110
110
  });
111
- // Link bins to pnpmHomeDir so the updated pnpm is the active global binary
112
- await linkBins(path.join(baseDir, 'node_modules'), opts.pnpmHomeDir, { warn: globalWarn });
111
+ // Link bins to pnpmHomeDir/bin so the updated pnpm is the active global binary
112
+ await linkBins(path.join(baseDir, 'node_modules'), path.join(opts.pnpmHomeDir, 'bin'), { warn: globalWarn });
113
113
  if (alreadyExisted) {
114
114
  return `The ${bareSpecifier} version, v${resolution.manifest.version}, is already present on the system. It was activated by linking it from ${baseDir}.`;
115
115
  }
@@ -2,6 +2,7 @@ export declare const rcOptionsTypes: () => Record<string, unknown>;
2
2
  export declare const cliOptionsTypes: () => Record<string, unknown>;
3
3
  export declare const shorthands: {};
4
4
  export declare const commandNames: string[];
5
+ export declare const overridableByScript = true;
5
6
  export declare function help(): string;
6
7
  export declare function handler(opts: {
7
8
  force?: boolean;
@@ -5,6 +5,7 @@ import { detectIfCurrentPkgIsExecutable, packageManager } from '@pnpm/cli.meta';
5
5
  import { docsUrl } from '@pnpm/cli.utils';
6
6
  import { logger } from '@pnpm/logger';
7
7
  import { addDirToEnvPath, } from '@pnpm/os.env.path-extender';
8
+ import PATH from 'path-name';
8
9
  import { renderHelp } from 'render-help';
9
10
  export const rcOptionsTypes = () => ({});
10
11
  export const cliOptionsTypes = () => ({
@@ -12,6 +13,7 @@ export const cliOptionsTypes = () => ({
12
13
  });
13
14
  export const shorthands = {};
14
15
  export const commandNames = ['setup'];
16
+ export const overridableByScript = true;
15
17
  export function help() {
16
18
  return renderHelp({
17
19
  description: 'Sets up pnpm',
@@ -55,7 +57,7 @@ function installCliGlobally(execPath, pnpmHomeDir) {
55
57
  fs.writeFileSync(pkgJsonPath, JSON.stringify({
56
58
  name: '@pnpm/exe',
57
59
  version: packageManager.version,
58
- bin: { pnpm: execName },
60
+ bin: { pnpm: execName, pn: execName },
59
61
  }));
60
62
  createdPkgJson = true;
61
63
  }
@@ -64,11 +66,13 @@ function installCliGlobally(execPath, pnpmHomeDir) {
64
66
  prefix: process.cwd(),
65
67
  });
66
68
  try {
69
+ const binDir = path.join(pnpmHomeDir, 'bin');
67
70
  const { status, error } = spawnSync(execPath, ['add', '-g', `file:${execDir}`], {
68
71
  stdio: 'inherit',
69
72
  env: {
70
73
  ...process.env,
71
74
  PNPM_HOME: pnpmHomeDir,
75
+ [PATH]: `${binDir}${path.delimiter}${process.env[PATH] ?? ''}`,
72
76
  },
73
77
  });
74
78
  if (error)
@@ -83,7 +87,7 @@ function installCliGlobally(execPath, pnpmHomeDir) {
83
87
  }
84
88
  }
85
89
  }
86
- function createPnpxScripts(targetDir) {
90
+ function createAliasScripts(targetDir) {
87
91
  // Why script files instead of aliases?
88
92
  // 1. Aliases wouldn't work on all platform, such as Windows Command Prompt or POSIX `sh`.
89
93
  // 2. Aliases wouldn't work on all environments, such as non-interactive shells and CI environments.
@@ -91,32 +95,31 @@ function createPnpxScripts(targetDir) {
91
95
  // 4. Aliases cannot be located with the `which` or `where` command.
92
96
  // 5. Editing rc files is more error-prone than just write new files to the filesystem.
93
97
  fs.mkdirSync(targetDir, { recursive: true });
98
+ createShellScript(targetDir, 'pn', 'pnpm');
99
+ createShellScript(targetDir, 'pnpx', 'pnpm dlx');
100
+ createShellScript(targetDir, 'pnx', 'pnpm dlx');
101
+ }
102
+ function createShellScript(targetDir, name, command) {
94
103
  // windows can also use shell script via mingw or cygwin so no filter
95
- const shellScript = [
96
- '#!/bin/sh',
97
- 'exec pnpm dlx "$@"',
98
- ].join('\n');
99
- fs.writeFileSync(path.join(targetDir, 'pnpx'), shellScript, { mode: 0o755 });
104
+ const shellScript = `#!/bin/sh\nexec ${command} "$@"\n`;
105
+ fs.writeFileSync(path.join(targetDir, name), shellScript, { mode: 0o755 });
100
106
  if (process.platform === 'win32') {
101
- const batchScript = [
102
- '@echo off',
103
- 'pnpm dlx %*',
104
- ].join('\n');
105
- fs.writeFileSync(path.join(targetDir, 'pnpx.cmd'), batchScript);
106
- const powershellScript = 'pnpm dlx @args';
107
- fs.writeFileSync(path.join(targetDir, 'pnpx.ps1'), powershellScript);
107
+ fs.writeFileSync(path.join(targetDir, `${name}.cmd`), `@echo off\n${command} %*\n`);
108
+ fs.writeFileSync(path.join(targetDir, `${name}.ps1`), `${command} @args\n`);
108
109
  }
109
110
  }
110
111
  export async function handler(opts) {
111
112
  const execPath = getExecPath();
113
+ const binDir = path.join(opts.pnpmHomeDir, 'bin');
112
114
  if (execPath.match(/\.[cm]?js$/) == null) {
113
115
  installCliGlobally(execPath, opts.pnpmHomeDir);
114
- createPnpxScripts(opts.pnpmHomeDir);
116
+ createAliasScripts(binDir);
115
117
  }
116
118
  try {
117
119
  const report = await addDirToEnvPath(opts.pnpmHomeDir, {
118
120
  configSectionName: 'pnpm',
119
121
  proxyVarName: 'PNPM_HOME',
122
+ proxyVarSubDir: 'bin',
120
123
  overwrite: opts.force,
121
124
  position: 'start',
122
125
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/engine.pm.commands",
3
- "version": "1000.0.0",
3
+ "version": "1100.0.1",
4
4
  "description": "pnpm commands for self-updating and setting up pnpm",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -24,44 +24,47 @@
24
24
  "!*.map"
25
25
  ],
26
26
  "dependencies": {
27
- "@pnpm/os.env.path-extender": "^2.0.3",
27
+ "@pnpm/os.env.path-extender": "^3.0.0",
28
+ "path-name": "^1.0.0",
28
29
  "ramda": "npm:@pnpm/ramda@0.28.1",
29
30
  "render-help": "^2.0.0",
30
31
  "semver": "^7.7.2",
31
- "symlink-dir": "^7.0.0",
32
- "@pnpm/bins.linker": "1000.2.6",
33
- "@pnpm/cli.meta": "1000.0.11",
34
- "@pnpm/deps.graph-hasher": "1002.0.8",
35
- "@pnpm/cli.utils": "1001.2.8",
36
- "@pnpm/config.reader": "1004.4.2",
37
- "@pnpm/error": "1000.0.5",
38
- "@pnpm/global.packages": "1000.0.0-0",
39
- "@pnpm/installing.client": "1001.1.4",
40
- "@pnpm/global.commands": "1000.0.0-0",
41
- "@pnpm/installing.deps-restorer": "1006.0.0",
42
- "@pnpm/lockfile.types": "1002.0.2",
43
- "@pnpm/resolving.npm-resolver": "1004.4.1",
44
- "@pnpm/installing.env-installer": "1000.0.19",
45
- "@pnpm/store.connection-manager": "1002.2.4",
46
- "@pnpm/store.controller": "1004.0.0",
47
- "@pnpm/types": "1000.9.0",
48
- "@pnpm/workspace.project-manifest-reader": "1001.1.4"
32
+ "symlink-dir": "^10.0.1",
33
+ "@pnpm/bins.linker": "1100.0.1",
34
+ "@pnpm/building.policy": "1100.0.1",
35
+ "@pnpm/config.reader": "1100.0.1",
36
+ "@pnpm/cli.meta": "1100.0.1",
37
+ "@pnpm/cli.utils": "1100.0.1",
38
+ "@pnpm/error": "1100.0.0",
39
+ "@pnpm/deps.graph-hasher": "1100.0.1",
40
+ "@pnpm/global.commands": "1100.0.1",
41
+ "@pnpm/global.packages": "1100.0.1",
42
+ "@pnpm/installing.client": "1100.0.1",
43
+ "@pnpm/installing.env-installer": "1100.0.1",
44
+ "@pnpm/installing.deps-restorer": "1100.0.1",
45
+ "@pnpm/lockfile.types": "1100.0.1",
46
+ "@pnpm/store.connection-manager": "1100.0.1",
47
+ "@pnpm/resolving.npm-resolver": "1100.0.1",
48
+ "@pnpm/types": "1101.0.0",
49
+ "@pnpm/store.controller": "1100.0.1",
50
+ "@pnpm/workspace.project-manifest-reader": "1100.0.1"
49
51
  },
50
52
  "peerDependencies": {
51
53
  "@pnpm/logger": ">=1001.0.0 <1002.0.0"
52
54
  },
53
55
  "devDependencies": {
54
- "@jest/globals": "30.0.5",
56
+ "@jest/globals": "30.3.0",
55
57
  "@types/cross-spawn": "^6.0.6",
56
- "@types/ramda": "0.29.12",
58
+ "@types/ramda": "0.31.1",
57
59
  "@types/semver": "7.7.1",
58
60
  "cross-spawn": "^7.0.6",
59
- "nock": "13.3.4",
60
- "@pnpm/engine.pm.commands": "1000.0.0",
61
- "@pnpm/error": "1000.0.5",
62
- "@pnpm/logger": "1001.0.1",
63
- "@pnpm/prepare": "1000.0.4",
64
- "@pnpm/shell.path": "1000.0.0"
61
+ "@pnpm/constants": "1100.0.0",
62
+ "@pnpm/error": "1100.0.0",
63
+ "@pnpm/logger": "1100.0.0",
64
+ "@pnpm/prepare": "1100.0.1",
65
+ "@pnpm/engine.pm.commands": "1100.0.1",
66
+ "@pnpm/shell.path": "1100.0.0",
67
+ "@pnpm/testing.mock-agent": "1100.0.1"
65
68
  },
66
69
  "engines": {
67
70
  "node": ">=22.13"
@@ -71,8 +74,8 @@
71
74
  },
72
75
  "scripts": {
73
76
  "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
74
- "test": "pnpm run compile && pnpm run _test",
75
- "compile": "tsgo --build && pnpm run lint --fix",
76
- "_test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
77
+ "test": "pn compile && pn .test",
78
+ "compile": "tsgo --build && pn lint --fix",
79
+ ".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
77
80
  }
78
81
  }