@pnpm/installing.commands 1100.7.3 → 1100.9.0
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/import/index.js +1 -1
- package/lib/install.d.ts +1 -1
- package/lib/install.js +5 -0
- package/lib/installDeps.d.ts +2 -2
- package/lib/installDeps.js +27 -3
- package/lib/link.js +1 -0
- package/lib/recursive.d.ts +10 -4
- package/lib/runPacquet.d.ts +54 -16
- package/lib/runPacquet.js +87 -12
- package/lib/update/index.js +5 -0
- package/lib/verifyPacquetIdentity.js +2 -1
- package/package.json +54 -53
package/lib/import/index.js
CHANGED
|
@@ -230,7 +230,7 @@ function selectProjectByDir(projects, searchedDir) {
|
|
|
230
230
|
const project = projects.find(({ rootDir }) => path.relative(rootDir, searchedDir) === '');
|
|
231
231
|
if (project == null)
|
|
232
232
|
return undefined;
|
|
233
|
-
return { [
|
|
233
|
+
return { [project.rootDir]: { dependencies: [], package: project } };
|
|
234
234
|
}
|
|
235
235
|
function getYarnLockfileType(lockFileContents) {
|
|
236
236
|
return lockFileContents.includes('__metadata')
|
package/lib/install.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare const shorthands: Record<string, string>;
|
|
|
7
7
|
export declare const commandNames: string[];
|
|
8
8
|
export declare const recursiveByDefault = true;
|
|
9
9
|
export declare function help(): string;
|
|
10
|
-
export type InstallCommandOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'configDependencies' | 'dedupeInjectedDeps' | 'dedupeDirectDeps' | 'dedupePeerDependents' | 'dedupePeers' | 'deployAllFiles' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'engineStrict' | 'excludeLinksFromLockfile' | 'frozenLockfile' | 'global' | 'globalPnpmfile' | 'hoistPattern' | 'hoistingLimits' | 'publicHoistPattern' | 'ignorePnpmfile' | 'ignoreScripts' | 'injectWorkspacePackages' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'modulesDir' | 'nodeLinker' | 'patchedDependencies' | 'preferFrozenLockfile' | 'preferWorkspacePackages' | 'production' | 'registries' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveCatalogName' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'virtualStoreDir' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'resolutionMode' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'updateConfig' | 'overrides' | 'packageExtensions' | 'pnprServer' | 'supportedArchitectures' | 'packageConfigs'> & Pick<ConfigContext, 'allProjects' | 'cliOptions' | 'hooks' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'allProjectsGraph' | 'selectedProjectsGraph'> & CreateStoreControllerOptions & Partial<Pick<Config, 'globalPkgDir'>> & {
|
|
10
|
+
export type InstallCommandOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'configDependencies' | 'dedupeInjectedDeps' | 'dedupeDirectDeps' | 'dedupePeerDependents' | 'dedupePeers' | 'deployAllFiles' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'engineStrict' | 'excludeLinksFromLockfile' | 'frozenLockfile' | 'global' | 'globalPnpmfile' | 'hoistPattern' | 'hoistingLimits' | 'publicHoistPattern' | 'ignorePnpmfile' | 'ignoreScripts' | 'injectWorkspacePackages' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'optimisticRepeatInstall' | 'modulesDir' | 'nodeLinker' | 'patchedDependencies' | 'preferFrozenLockfile' | 'preferWorkspacePackages' | 'production' | 'registries' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveCatalogName' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'virtualStoreDir' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'resolutionMode' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'updateConfig' | 'overrides' | 'packageExtensions' | 'pnprServer' | 'supportedArchitectures' | 'packageConfigs'> & Pick<ConfigContext, 'allProjects' | 'cliOptions' | 'hooks' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'allProjectsGraph' | 'selectedProjectsGraph'> & CreateStoreControllerOptions & Partial<Pick<Config, 'globalPkgDir'>> & {
|
|
11
11
|
argv: {
|
|
12
12
|
cooked?: string[];
|
|
13
13
|
original: string[];
|
package/lib/install.js
CHANGED
|
@@ -71,6 +71,7 @@ export function rcOptionsTypes() {
|
|
|
71
71
|
'optional',
|
|
72
72
|
'unsafe-perm',
|
|
73
73
|
'verify-store-integrity',
|
|
74
|
+
'frozen-store',
|
|
74
75
|
'virtual-store-dir',
|
|
75
76
|
'virtual-store-only',
|
|
76
77
|
], allTypes);
|
|
@@ -211,6 +212,10 @@ by any dependencies, so it is an emulation of a flat node_modules',
|
|
|
211
212
|
description: 'If false, skips store integrity checks. These checks detect accidental corruption, not tampering by untrusted users with write access to the store',
|
|
212
213
|
name: '--[no-]verify-store-integrity',
|
|
213
214
|
},
|
|
215
|
+
{
|
|
216
|
+
description: 'Open the package store read-only (immutable) and skip all store writes. For installs against a store on a read-only filesystem (e.g. a Nix store); pair with --offline --frozen-lockfile. Incompatible with --force',
|
|
217
|
+
name: '--frozen-store',
|
|
218
|
+
},
|
|
214
219
|
{
|
|
215
220
|
description: 'Fail on missing or invalid peer dependencies',
|
|
216
221
|
name: '--strict-peer-dependencies',
|
package/lib/installDeps.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { type UpdateMatchingFunction } from '@pnpm/installing.deps-installer';
|
|
|
4
4
|
import type { LockfileObject } from '@pnpm/lockfile.types';
|
|
5
5
|
import { type CreateStoreControllerOptions } from '@pnpm/store.connection-manager';
|
|
6
6
|
import type { IncludedDependencies, PackageVulnerabilityAudit } from '@pnpm/types';
|
|
7
|
-
export type InstallDepsOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'catalogMode' | 'cleanupUnusedCatalogs' | 'dedupePeerDependents' | 'dedupePeers' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'virtualStoreOnly' | 'engineStrict' | 'excludeLinksFromLockfile' | 'global' | 'globalPnpmfile' | 'ignoreCurrentSpecifiers' | 'ignorePnpmfile' | 'ignoreScripts' | 'optimisticRepeatInstall' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'pnprServer' | 'production' | 'preferWorkspacePackages' | 'registries' | 'runtime' | 'runtimeOnFail' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'scriptsPrependNodePath' | 'scriptShell' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'shellEmulator' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'configDependencies' | 'packageExtensions' | 'updateConfig'> & Pick<ConfigContext, 'allProjects' | 'allProjectsGraph' | 'cliOptions' | 'hooks' | 'rootProjectManifestDir' | 'rootProjectManifest' | 'selectedProjectsGraph'> & Partial<Pick<Config, 'ci'>> & CreateStoreControllerOptions & {
|
|
7
|
+
export type InstallDepsOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'catalogMode' | 'cleanupUnusedCatalogs' | 'dedupePeerDependents' | 'dedupePeers' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'virtualStoreOnly' | 'engineStrict' | 'excludeLinksFromLockfile' | 'global' | 'globalPnpmfile' | 'ignoreCurrentSpecifiers' | 'ignorePnpmfile' | 'ignoreScripts' | 'optimisticRepeatInstall' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'pnprServer' | 'production' | 'preferWorkspacePackages' | 'registries' | 'runtime' | 'runtimeOnFail' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'scriptsPrependNodePath' | 'scriptShell' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'shellEmulator' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'configDependencies' | 'packageExtensions' | 'updateConfig' | 'virtualStoreDirMaxLength'> & Pick<ConfigContext, 'allProjects' | 'allProjectsGraph' | 'cliOptions' | 'hooks' | 'rootProjectManifestDir' | 'rootProjectManifest' | 'selectedProjectsGraph'> & Partial<Pick<Config, 'ci'>> & CreateStoreControllerOptions & {
|
|
8
8
|
argv: {
|
|
9
9
|
cooked?: string[];
|
|
10
10
|
original: string[];
|
|
@@ -48,5 +48,5 @@ export type InstallDepsOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin
|
|
|
48
48
|
* subcommand — see `runPacquet.ts`'s `noRuntime` opt.
|
|
49
49
|
*/
|
|
50
50
|
isInstallCommand?: boolean;
|
|
51
|
-
} & Partial<Pick<Config, 'pnpmHomeDir' | 'strictDepBuilds'>>;
|
|
51
|
+
} & Partial<Pick<Config, 'pnpmHomeDir' | 'strictDepBuilds' | 'useLockfile' | 'useGitBranchLockfile'>>;
|
|
52
52
|
export declare function installDeps(opts: InstallDepsOptions, params: string[]): Promise<void>;
|
package/lib/installDeps.js
CHANGED
|
@@ -5,6 +5,7 @@ import { checkDepsStatus } from '@pnpm/deps.status';
|
|
|
5
5
|
import { PnpmError } from '@pnpm/error';
|
|
6
6
|
import { arrayOfWorkspacePackagesToMap } from '@pnpm/installing.context';
|
|
7
7
|
import { install, mutateModulesInSingleProject, } from '@pnpm/installing.deps-installer';
|
|
8
|
+
import { writeWantedLockfile } from '@pnpm/lockfile.fs';
|
|
8
9
|
import { globalInfo, logger } from '@pnpm/logger';
|
|
9
10
|
import { applyRuntimeOnFailOverride, filterDependenciesByType } from '@pnpm/pkg-manifest.utils';
|
|
10
11
|
import { createStoreController } from '@pnpm/store.connection-manager';
|
|
@@ -28,11 +29,11 @@ const OVERWRITE_UPDATE_OPTIONS = {
|
|
|
28
29
|
};
|
|
29
30
|
export async function installDeps(opts, params) {
|
|
30
31
|
if (!opts.update && !opts.dedupe && params.length === 0 && opts.optimisticRepeatInstall) {
|
|
31
|
-
const { upToDate } = await checkDepsStatus({
|
|
32
|
+
const { upToDate, wantedLockfileToRestore } = await checkDepsStatus({
|
|
32
33
|
...opts,
|
|
33
34
|
ignoreFilteredInstallCache: true,
|
|
34
35
|
});
|
|
35
|
-
if (upToDate) {
|
|
36
|
+
if (upToDate && await restoreWantedLockfileIfMissing(wantedLockfileToRestore, opts)) {
|
|
36
37
|
if (opts.hooks?.customResolvers?.some(r => r.shouldRefreshResolution)) {
|
|
37
38
|
logger.warn({
|
|
38
39
|
message: 'shouldRefreshResolution hooks were skipped because optimisticRepeatInstall is enabled.',
|
|
@@ -94,6 +95,7 @@ export async function installDeps(opts, params) {
|
|
|
94
95
|
packageName: pacquetConfigDepName,
|
|
95
96
|
argv: { original: opts.argv.original, remain: opts.argv.remain ?? [] },
|
|
96
97
|
isInstallCommand: opts.isInstallCommand === true,
|
|
98
|
+
virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
|
|
97
99
|
})
|
|
98
100
|
: undefined;
|
|
99
101
|
const includeDirect = opts.includeDirect ?? {
|
|
@@ -351,7 +353,7 @@ function selectProjectByDir(projects, searchedDir) {
|
|
|
351
353
|
const project = projects.find(({ rootDir }) => path.relative(rootDir, searchedDir) === '');
|
|
352
354
|
if (project == null)
|
|
353
355
|
return undefined;
|
|
354
|
-
return { [
|
|
356
|
+
return { [project.rootDir]: { dependencies: [], package: project } };
|
|
355
357
|
}
|
|
356
358
|
async function recursiveInstallThenUpdateWorkspaceState(allProjects, params, opts, cmdFullName) {
|
|
357
359
|
const recursiveResult = await recursive(allProjects, params, opts, cmdFullName);
|
|
@@ -416,4 +418,26 @@ function preferNonvulnerablePackageVersions(packageVulnerabilityAudit) {
|
|
|
416
418
|
}
|
|
417
419
|
return preferredVersions;
|
|
418
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Restore a missing `pnpm-lock.yaml` from the current lockfile before the
|
|
423
|
+
* optimistic repeat-install short-circuit reports "Already up to date", so
|
|
424
|
+
* the fast path leaves the same on-disk contract a full install would.
|
|
425
|
+
* Returns `true` when the short-circuit may proceed: nothing to restore,
|
|
426
|
+
* lockfile writing is disabled (`useLockfile: false`), or the restore
|
|
427
|
+
* succeeded. A failed write returns `false` so the caller falls through to
|
|
428
|
+
* the full install instead of reporting up to date while `pnpm-lock.yaml`
|
|
429
|
+
* stays missing.
|
|
430
|
+
*/
|
|
431
|
+
async function restoreWantedLockfileIfMissing(wantedLockfileToRestore, opts) {
|
|
432
|
+
if (wantedLockfileToRestore == null || opts.useLockfile === false)
|
|
433
|
+
return true;
|
|
434
|
+
try {
|
|
435
|
+
await writeWantedLockfile(wantedLockfileToRestore.lockfileDir, wantedLockfileToRestore.lockfile);
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
catch (error) {
|
|
439
|
+
logger.debug({ msg: 'Failed to restore pnpm-lock.yaml from the current lockfile', error });
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
419
443
|
//# sourceMappingURL=installDeps.js.map
|
package/lib/link.js
CHANGED
package/lib/recursive.d.ts
CHANGED
|
@@ -32,11 +32,17 @@ export type RecursiveOptions = CreateStoreControllerOptions & Pick<Config, 'bail
|
|
|
32
32
|
pnpmfile: string[];
|
|
33
33
|
/**
|
|
34
34
|
* Alternative install engine (today: pacquet) the deps-installer
|
|
35
|
-
* delegates the
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* delegates the install to. Built in `installDeps` when
|
|
36
|
+
* `configDependencies.pacquet` is declared, threaded through here so
|
|
37
|
+
* the recursive workspace path picks it up too.
|
|
38
38
|
*/
|
|
39
|
-
runPacquet?:
|
|
39
|
+
runPacquet?: {
|
|
40
|
+
supportsResolution: boolean;
|
|
41
|
+
run: (opts?: {
|
|
42
|
+
filterResolvedProgress?: boolean;
|
|
43
|
+
resolve?: boolean;
|
|
44
|
+
}) => Promise<void>;
|
|
45
|
+
};
|
|
40
46
|
} & Partial<Pick<Config, 'ci' | 'sort' | 'strictDepBuilds' | 'workspaceConcurrency'>> & Required<Pick<Config, 'workspaceDir'>>;
|
|
41
47
|
export type CommandFullName = 'install' | 'add' | 'remove' | 'update' | 'import';
|
|
42
48
|
export declare function recursive(allProjects: Project[], params: string[], opts: RecursiveOptions, cmdFullName: CommandFullName): Promise<boolean | string>;
|
package/lib/runPacquet.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export interface MakeRunPacquetOpts {
|
|
2
2
|
lockfileDir: string;
|
|
3
|
+
/**
|
|
4
|
+
* Effective pnpm config value. Forwarded through `PNPM_CONFIG_*` so
|
|
5
|
+
* pacquet writes the same `.modules.yaml` and virtual-store paths as
|
|
6
|
+
* the pnpm process that delegated to it, including Windows' shorter
|
|
7
|
+
* default.
|
|
8
|
+
*/
|
|
9
|
+
virtualStoreDirMaxLength: number;
|
|
3
10
|
/**
|
|
4
11
|
* Which `configDependencies` entry installed pacquet: either the
|
|
5
12
|
* original unscoped `pacquet` or the official scoped
|
|
@@ -32,21 +39,6 @@ export interface MakeRunPacquetOpts {
|
|
|
32
39
|
*/
|
|
33
40
|
isInstallCommand: boolean;
|
|
34
41
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Build the install-engine callback `mutateModules` invokes when
|
|
37
|
-
* `configDependencies` declares pacquet.
|
|
38
|
-
*
|
|
39
|
-
* The callback spawns the pacquet binary installed under
|
|
40
|
-
* `node_modules/.pnpm-config/pacquet`. From `pnpm install`/`pnpm i` it
|
|
41
|
-
* forwards the user's own pnpm CLI flags to pacquet's `install`
|
|
42
|
-
* subcommand; from `add`/`update`/`dedupe` it doesn't forward (warning
|
|
43
|
-
* instead). Pacquet's NDJSON stderr is parsed line-by-line and the
|
|
44
|
-
* valid JSON records are re-emitted on pnpm's global `streamParser` so
|
|
45
|
-
* `@pnpm/cli.default-reporter` renders pacquet's events the same way it
|
|
46
|
-
* renders pnpm's own. Non-JSON stderr lines (panic backtraces,
|
|
47
|
-
* unexpected diagnostics) are forwarded to the real stderr verbatim so
|
|
48
|
-
* they reach the user.
|
|
49
|
-
*/
|
|
50
42
|
/** Args the deps-installer passes per pacquet invocation. */
|
|
51
43
|
export interface RunPacquetCallOpts {
|
|
52
44
|
/**
|
|
@@ -60,5 +52,51 @@ export interface RunPacquetCallOpts {
|
|
|
60
52
|
* source.
|
|
61
53
|
*/
|
|
62
54
|
filterResolvedProgress?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* `true` to let pacquet perform the resolution itself rather than
|
|
57
|
+
* materialize an already-resolved lockfile. Drops the injected
|
|
58
|
+
* `--frozen-lockfile`, so pacquet resolves the manifests, writes
|
|
59
|
+
* `pnpm-lock.yaml`, and materializes in a single pass. Only valid
|
|
60
|
+
* when {@link PacquetEngine.supportsResolution} is `true` (pacquet
|
|
61
|
+
* >= 0.11.7).
|
|
62
|
+
*/
|
|
63
|
+
resolve?: boolean;
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Handle to the pacquet install engine: its capabilities plus the
|
|
67
|
+
* callback `mutateModules` invokes to run it.
|
|
68
|
+
*/
|
|
69
|
+
export interface PacquetEngine {
|
|
70
|
+
/**
|
|
71
|
+
* `true` when the installed pacquet is new enough (>= 0.11.7) to
|
|
72
|
+
* perform dependency resolution itself. When `false`, pacquet can
|
|
73
|
+
* only materialize an already-resolved lockfile, so the deps-installer
|
|
74
|
+
* runs its own resolve pass first and hands the written lockfile to
|
|
75
|
+
* pacquet.
|
|
76
|
+
*/
|
|
77
|
+
supportsResolution: boolean;
|
|
78
|
+
run: (callOpts?: RunPacquetCallOpts) => Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build the pacquet install engine `mutateModules` delegates to when
|
|
82
|
+
* `configDependencies` declares pacquet.
|
|
83
|
+
*
|
|
84
|
+
* `run` spawns the pacquet binary installed under
|
|
85
|
+
* `node_modules/.pnpm-config/pacquet`. From `pnpm install`/`pnpm i` it
|
|
86
|
+
* forwards the user's own pnpm CLI flags to pacquet's `install`
|
|
87
|
+
* subcommand; from `add`/`update`/`dedupe` it doesn't forward (warning
|
|
88
|
+
* instead). Pacquet's NDJSON stderr is parsed line-by-line and the
|
|
89
|
+
* valid JSON records are re-emitted on pnpm's global `streamParser` so
|
|
90
|
+
* `@pnpm/cli.default-reporter` renders pacquet's events the same way it
|
|
91
|
+
* renders pnpm's own. Non-JSON stderr lines (panic backtraces,
|
|
92
|
+
* unexpected diagnostics) are forwarded to the real stderr verbatim so
|
|
93
|
+
* they reach the user.
|
|
94
|
+
*/
|
|
95
|
+
export declare function makeRunPacquet(opts: MakeRunPacquetOpts): PacquetEngine;
|
|
96
|
+
/**
|
|
97
|
+
* Name of the `@pacquet/<platform>-<arch>[-musl]` package that holds the
|
|
98
|
+
* native pacquet binary for the host. On linux the binary packages are
|
|
99
|
+
* split by libc and only the matching one is installed, so spawning and
|
|
100
|
+
* signature verification must agree on this exact name.
|
|
101
|
+
*/
|
|
102
|
+
export declare function pacquetPlatformPkgName(): string;
|
package/lib/runPacquet.js
CHANGED
|
@@ -6,12 +6,34 @@ import readline from 'node:readline';
|
|
|
6
6
|
import { PnpmError } from '@pnpm/error';
|
|
7
7
|
import { logger, streamParser } from '@pnpm/logger';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
|
+
import { familySync as getLibcFamilySync, MUSL } from 'detect-libc';
|
|
9
10
|
// The runtime `streamParser` is a `Transform` stream (split2 + JSON.parse).
|
|
10
11
|
// Its public typing only exposes `on`/`removeListener`, so we narrow to the
|
|
11
12
|
// writable side here to feed pacquet's NDJSON lines back through the same
|
|
12
13
|
// parser that `@pnpm/cli.default-reporter` listens on.
|
|
13
14
|
const streamParserWritable = streamParser;
|
|
15
|
+
/**
|
|
16
|
+
* Build the pacquet install engine `mutateModules` delegates to when
|
|
17
|
+
* `configDependencies` declares pacquet.
|
|
18
|
+
*
|
|
19
|
+
* `run` spawns the pacquet binary installed under
|
|
20
|
+
* `node_modules/.pnpm-config/pacquet`. From `pnpm install`/`pnpm i` it
|
|
21
|
+
* forwards the user's own pnpm CLI flags to pacquet's `install`
|
|
22
|
+
* subcommand; from `add`/`update`/`dedupe` it doesn't forward (warning
|
|
23
|
+
* instead). Pacquet's NDJSON stderr is parsed line-by-line and the
|
|
24
|
+
* valid JSON records are re-emitted on pnpm's global `streamParser` so
|
|
25
|
+
* `@pnpm/cli.default-reporter` renders pacquet's events the same way it
|
|
26
|
+
* renders pnpm's own. Non-JSON stderr lines (panic backtraces,
|
|
27
|
+
* unexpected diagnostics) are forwarded to the real stderr verbatim so
|
|
28
|
+
* they reach the user.
|
|
29
|
+
*/
|
|
14
30
|
export function makeRunPacquet(opts) {
|
|
31
|
+
return {
|
|
32
|
+
supportsResolution: pacquetSupportsResolution(resolvePacquetVersion(opts.lockfileDir, opts.packageName)),
|
|
33
|
+
run: makeRun(opts),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function makeRun(opts) {
|
|
15
37
|
return async (callOpts) => {
|
|
16
38
|
const pacquetBin = resolvePacquetBin(opts.lockfileDir, opts.packageName);
|
|
17
39
|
// From `pnpm install`/`pnpm i` we forward the user's flags through to
|
|
@@ -19,21 +41,23 @@ export function makeRunPacquet(opts) {
|
|
|
19
41
|
// surface closely enough on that command that they're safe to pass
|
|
20
42
|
// along. From `add`/`update`/`dedupe` we don't forward anything: those
|
|
21
43
|
// commands carry flags pacquet's `install` doesn't recognize
|
|
22
|
-
// (`--save-dev`, `--save-peer`, etc.) which clap would reject.
|
|
23
|
-
// way pacquet picks up the settings users care about from
|
|
24
|
-
// `pnpm-workspace.yaml` / `.npmrc` on its own, so a non-install
|
|
25
|
-
// delegation isn't broken by the omission.
|
|
44
|
+
// (`--save-dev`, `--save-peer`, etc.) which clap would reject.
|
|
26
45
|
const forwardedFlags = opts.isInstallCommand ? collectForwardedFlags(opts.argv) : [];
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
46
|
+
// In resolve mode pacquet does the resolution itself, so it must not
|
|
47
|
+
// be pinned to the existing lockfile — drop both injected flags.
|
|
48
|
+
//
|
|
49
|
+
// Otherwise (frozen materialization) inject `--frozen-lockfile` plus
|
|
50
|
+
// `--ignore-manifest-check`. The latter tells pacquet to skip its
|
|
51
|
+
// per-importer `package.json` ↔ `pnpm-lock.yaml` freshness gate:
|
|
52
|
+
// pnpm just resolved and wrote the lockfile itself; on `pnpm up` /
|
|
53
|
+
// `add` / `remove` the manifest on disk is still the pre-mutation
|
|
54
|
+
// copy (pnpm writes it after `mutateModules` returns), so pacquet's
|
|
55
|
+
// own check would always fire here. See
|
|
33
56
|
// https://github.com/pnpm/pnpm/issues/11797. The flag is narrow
|
|
34
57
|
// (only the manifest check); settings drift like `overrides` is
|
|
35
58
|
// still enforced and was already re-validated by pnpm.
|
|
36
|
-
const
|
|
59
|
+
const frozenArgs = callOpts?.resolve === true ? [] : ['--frozen-lockfile', '--ignore-manifest-check'];
|
|
60
|
+
const args = ['--reporter=ndjson', 'install', ...frozenArgs, ...forwardedFlags];
|
|
37
61
|
const droppedFlags = opts.isInstallCommand ? [] : collectDroppedFlags(opts.argv);
|
|
38
62
|
if (droppedFlags.length > 0) {
|
|
39
63
|
logger.warn({
|
|
@@ -53,6 +77,7 @@ export function makeRunPacquet(opts) {
|
|
|
53
77
|
logger.info({ message: banner, prefix: opts.lockfileDir });
|
|
54
78
|
const child = spawn(pacquetBin, args, {
|
|
55
79
|
cwd: opts.lockfileDir,
|
|
80
|
+
env: makePacquetEnv(opts),
|
|
56
81
|
stdio: ['ignore', 'inherit', 'pipe'],
|
|
57
82
|
});
|
|
58
83
|
const filterResolved = callOpts?.filterResolvedProgress === true;
|
|
@@ -89,6 +114,16 @@ export function makeRunPacquet(opts) {
|
|
|
89
114
|
});
|
|
90
115
|
};
|
|
91
116
|
}
|
|
117
|
+
function makePacquetEnv(opts) {
|
|
118
|
+
const env = { ...process.env };
|
|
119
|
+
for (const key of Object.keys(env)) {
|
|
120
|
+
if (key.toLowerCase() === 'pnpm_config_virtual_store_dir_max_length') {
|
|
121
|
+
delete env[key];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
env.PNPM_CONFIG_VIRTUAL_STORE_DIR_MAX_LENGTH = String(opts.virtualStoreDirMaxLength);
|
|
125
|
+
return env;
|
|
126
|
+
}
|
|
92
127
|
/**
|
|
93
128
|
* Path of the platform-specific native pacquet binary for the host. The
|
|
94
129
|
* pacquet npm package ships a Node wrapper at `bin/pacquet` that uses
|
|
@@ -108,7 +143,47 @@ export function makeRunPacquet(opts) {
|
|
|
108
143
|
function resolvePacquetBin(lockfileDir, packageName) {
|
|
109
144
|
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
110
145
|
const pacquetPkg = fs.realpathSync(path.join(lockfileDir, 'node_modules/.pnpm-config', packageName, 'package.json'));
|
|
111
|
-
return createRequire(pacquetPkg).resolve(
|
|
146
|
+
return createRequire(pacquetPkg).resolve(`${pacquetPlatformPkgName()}/pacquet${ext}`);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Name of the `@pacquet/<platform>-<arch>[-musl]` package that holds the
|
|
150
|
+
* native pacquet binary for the host. On linux the binary packages are
|
|
151
|
+
* split by libc and only the matching one is installed, so spawning and
|
|
152
|
+
* signature verification must agree on this exact name.
|
|
153
|
+
*/
|
|
154
|
+
export function pacquetPlatformPkgName() {
|
|
155
|
+
const libc = process.platform === 'linux' && getLibcFamilySync() === MUSL ? '-musl' : '';
|
|
156
|
+
return `@pacquet/${process.platform}-${process.arch}${libc}`;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Read the installed pacquet's version from its `package.json` under
|
|
160
|
+
* `node_modules/.pnpm-config/<packageName>`. Returns `undefined` if it
|
|
161
|
+
* can't be read — callers treat that as "assume the older,
|
|
162
|
+
* materialization-only pacquet" so a missing/garbled manifest degrades
|
|
163
|
+
* to the safe path rather than failing the install.
|
|
164
|
+
*/
|
|
165
|
+
function resolvePacquetVersion(lockfileDir, packageName) {
|
|
166
|
+
try {
|
|
167
|
+
const pacquetPkg = fs.realpathSync(path.join(lockfileDir, 'node_modules/.pnpm-config', packageName, 'package.json'));
|
|
168
|
+
const { version } = JSON.parse(fs.readFileSync(pacquetPkg, 'utf8'));
|
|
169
|
+
return version;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* pacquet gained full resolving installs in 0.11.7; earlier releases
|
|
177
|
+
* stay on pnpm's resolve-then-materialize path. Pre-release builds of
|
|
178
|
+
* 0.11.7 (e.g. `0.11.7-rc.1`) count as supporting it.
|
|
179
|
+
*/
|
|
180
|
+
function pacquetSupportsResolution(version) {
|
|
181
|
+
if (version == null)
|
|
182
|
+
return false;
|
|
183
|
+
const [major, minor, patch] = version.split('.', 3).map((part) => parseInt(part, 10));
|
|
184
|
+
if (Number.isNaN(major) || Number.isNaN(minor) || Number.isNaN(patch))
|
|
185
|
+
return false;
|
|
186
|
+
return major > 0 || (major === 0 && (minor > 11 || (minor === 11 && patch >= 7)));
|
|
112
187
|
}
|
|
113
188
|
/**
|
|
114
189
|
* From `pnpm install`/`pnpm i`, return everything in argv that should
|
package/lib/update/index.js
CHANGED
|
@@ -205,6 +205,11 @@ async function interactiveUpdate(input, opts, rebuildHandler) {
|
|
|
205
205
|
flatChoices.push({
|
|
206
206
|
name: choice.message,
|
|
207
207
|
value: choice.value,
|
|
208
|
+
// `name` is the rendered table row (label + versions + workspace + url)
|
|
209
|
+
// that lays out a single choice during selection. After submission
|
|
210
|
+
// @inquirer/prompts comma-joins each choice's `short`, which without
|
|
211
|
+
// this defaults to `name` and dumps the whole table back to stdout.
|
|
212
|
+
short: choice.value,
|
|
208
213
|
});
|
|
209
214
|
}
|
|
210
215
|
}
|
|
@@ -4,6 +4,7 @@ import { PnpmError } from '@pnpm/error';
|
|
|
4
4
|
import { readEnvLockfile } from '@pnpm/lockfile.fs';
|
|
5
5
|
import { logger } from '@pnpm/logger';
|
|
6
6
|
import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header';
|
|
7
|
+
import { pacquetPlatformPkgName } from './runPacquet.js';
|
|
7
8
|
/**
|
|
8
9
|
* Decides whether pnpm may spawn the pacquet binary installed under
|
|
9
10
|
* `node_modules/.pnpm-config/<packageName>` as an install engine.
|
|
@@ -60,7 +61,7 @@ async function collectPacquetPackagesToVerify(packageName, rootDir, registries)
|
|
|
60
61
|
return undefined;
|
|
61
62
|
// Only the host's platform binary is ever spawned, so that's the one whose
|
|
62
63
|
// identity matters. If it isn't in the lockfile, pacquet couldn't run here.
|
|
63
|
-
const platformPkgName =
|
|
64
|
+
const platformPkgName = pacquetPlatformPkgName();
|
|
64
65
|
const platformVersion = envLockfile.snapshots[shimKey]?.optionalDependencies?.[platformPkgName];
|
|
65
66
|
if (platformVersion == null)
|
|
66
67
|
return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/installing.commands",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.9.0",
|
|
4
4
|
"description": "Commands for installation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -30,14 +30,15 @@
|
|
|
30
30
|
"@inquirer/prompts": "^8.4.3",
|
|
31
31
|
"@pnpm/colorize-semver-diff": "^2.0.0",
|
|
32
32
|
"@pnpm/semver-diff": "^2.0.0",
|
|
33
|
-
"@pnpm/util.lex-comparator": "^
|
|
34
|
-
"@yarnpkg/core": "4.
|
|
33
|
+
"@pnpm/util.lex-comparator": "^4.0.1",
|
|
34
|
+
"@yarnpkg/core": "4.8.0",
|
|
35
35
|
"@yarnpkg/lockfile": "^1.1.0",
|
|
36
36
|
"@yarnpkg/parsers": "3.0.3",
|
|
37
37
|
"@zkochan/rimraf": "^4.0.0",
|
|
38
38
|
"@zkochan/table": "^2.0.1",
|
|
39
39
|
"chalk": "^5.6.2",
|
|
40
40
|
"ci-info": "^4.4.0",
|
|
41
|
+
"detect-libc": "^2.1.2",
|
|
41
42
|
"get-npm-tarball-url": "^2.1.0",
|
|
42
43
|
"is-subdir": "^2.0.0",
|
|
43
44
|
"load-json-file": "^7.0.1",
|
|
@@ -47,62 +48,62 @@
|
|
|
47
48
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
48
49
|
"render-help": "^2.0.0",
|
|
49
50
|
"version-selector-type": "^3.0.0",
|
|
50
|
-
"@pnpm/building.
|
|
51
|
-
"@pnpm/
|
|
51
|
+
"@pnpm/building.after-install": "1102.0.0",
|
|
52
|
+
"@pnpm/building.policy": "1100.0.10",
|
|
52
53
|
"@pnpm/catalogs.types": "1100.0.0",
|
|
54
|
+
"@pnpm/cli.utils": "1101.0.12",
|
|
53
55
|
"@pnpm/cli.common-cli-options-help": "1100.0.2",
|
|
54
|
-
"@pnpm/cli.
|
|
56
|
+
"@pnpm/cli.command": "1100.0.1",
|
|
55
57
|
"@pnpm/config.matcher": "1100.0.1",
|
|
56
|
-
"@pnpm/config.pick-registry-for-package": "1100.0.
|
|
57
|
-
"@pnpm/config.
|
|
58
|
+
"@pnpm/config.pick-registry-for-package": "1100.0.9",
|
|
59
|
+
"@pnpm/config.reader": "1101.9.0",
|
|
60
|
+
"@pnpm/config.writer": "1100.0.13",
|
|
58
61
|
"@pnpm/constants": "1100.0.0",
|
|
59
|
-
"@pnpm/
|
|
60
|
-
"@pnpm/deps.
|
|
61
|
-
"@pnpm/deps.
|
|
62
|
-
"@pnpm/deps.
|
|
63
|
-
"@pnpm/deps.security.signatures": "1101.2.0",
|
|
62
|
+
"@pnpm/deps.inspection.outdated": "1100.1.8",
|
|
63
|
+
"@pnpm/deps.path": "1100.0.8",
|
|
64
|
+
"@pnpm/deps.security.signatures": "1101.2.2",
|
|
65
|
+
"@pnpm/deps.status": "1100.1.1",
|
|
64
66
|
"@pnpm/error": "1100.0.0",
|
|
65
|
-
"@pnpm/fs.graceful-fs": "1100.1.0",
|
|
66
67
|
"@pnpm/fs.read-modules-dir": "1100.0.1",
|
|
67
|
-
"@pnpm/
|
|
68
|
-
"@pnpm/
|
|
69
|
-
"@pnpm/
|
|
70
|
-
"@pnpm/installing.dedupe.check": "1100.0.
|
|
71
|
-
"@pnpm/
|
|
72
|
-
"@pnpm/installing.
|
|
73
|
-
"@pnpm/lockfile.
|
|
74
|
-
"@pnpm/installing.
|
|
75
|
-
"@pnpm/
|
|
76
|
-
"@pnpm/
|
|
77
|
-
"@pnpm/network.auth-header": "1101.1.
|
|
78
|
-
"@pnpm/
|
|
68
|
+
"@pnpm/fs.graceful-fs": "1100.1.0",
|
|
69
|
+
"@pnpm/global.commands": "1100.0.28",
|
|
70
|
+
"@pnpm/hooks.pnpmfile": "1100.0.15",
|
|
71
|
+
"@pnpm/installing.dedupe.check": "1100.0.11",
|
|
72
|
+
"@pnpm/installing.context": "1100.0.18",
|
|
73
|
+
"@pnpm/installing.env-installer": "1102.0.0",
|
|
74
|
+
"@pnpm/lockfile.types": "1100.0.11",
|
|
75
|
+
"@pnpm/installing.deps-installer": "1102.0.0",
|
|
76
|
+
"@pnpm/network.fetch": "1100.1.3",
|
|
77
|
+
"@pnpm/lockfile.fs": "1100.1.5",
|
|
78
|
+
"@pnpm/network.auth-header": "1101.1.2",
|
|
79
|
+
"@pnpm/pkg-manifest.reader": "1100.0.8",
|
|
80
|
+
"@pnpm/resolving.npm-resolver": "1102.0.0",
|
|
79
81
|
"@pnpm/resolving.parse-wanted-dependency": "1100.0.1",
|
|
80
|
-
"@pnpm/pkg-manifest.utils": "1100.2.
|
|
81
|
-
"@pnpm/
|
|
82
|
-
"@pnpm/
|
|
83
|
-
"@pnpm/
|
|
84
|
-
"@pnpm/
|
|
85
|
-
"@pnpm/workspace.project-manifest-reader": "1100.0.
|
|
86
|
-
"@pnpm/workspace.
|
|
87
|
-
"@pnpm/workspace.
|
|
88
|
-
"@pnpm/workspace.projects-reader": "1101.0.
|
|
89
|
-
"@pnpm/workspace.projects-
|
|
90
|
-
"@pnpm/workspace.projects-
|
|
91
|
-
"@pnpm/workspace.state": "1100.0.20",
|
|
92
|
-
"@pnpm/workspace.workspace-manifest-writer": "1100.0.12",
|
|
82
|
+
"@pnpm/pkg-manifest.utils": "1100.2.5",
|
|
83
|
+
"@pnpm/store.connection-manager": "1100.3.0",
|
|
84
|
+
"@pnpm/resolving.resolver-base": "1100.4.2",
|
|
85
|
+
"@pnpm/store.controller": "1102.0.0",
|
|
86
|
+
"@pnpm/types": "1101.3.2",
|
|
87
|
+
"@pnpm/workspace.project-manifest-reader": "1100.0.13",
|
|
88
|
+
"@pnpm/workspace.project-manifest-writer": "1100.0.8",
|
|
89
|
+
"@pnpm/workspace.projects-filter": "1100.0.21",
|
|
90
|
+
"@pnpm/workspace.projects-reader": "1101.0.12",
|
|
91
|
+
"@pnpm/workspace.projects-graph": "1100.0.18",
|
|
92
|
+
"@pnpm/workspace.projects-sorter": "1100.0.7",
|
|
93
93
|
"@pnpm/workspace.root-finder": "1100.0.1",
|
|
94
|
-
"@pnpm/
|
|
94
|
+
"@pnpm/workspace.state": "1100.0.22",
|
|
95
|
+
"@pnpm/workspace.workspace-manifest-writer": "1100.0.13"
|
|
95
96
|
},
|
|
96
97
|
"peerDependencies": {
|
|
97
|
-
"@pnpm/logger": "^
|
|
98
|
+
"@pnpm/logger": "^1100.0.0"
|
|
98
99
|
},
|
|
99
100
|
"devDependencies": {
|
|
100
|
-
"@jest/globals": "30.
|
|
101
|
+
"@jest/globals": "30.4.1",
|
|
101
102
|
"@types/normalize-path": "^3.0.2",
|
|
102
103
|
"@types/proxyquire": "^1.3.31",
|
|
103
104
|
"@types/ramda": "0.31.1",
|
|
104
105
|
"@types/yarnpkg__lockfile": "^1.1.9",
|
|
105
|
-
"@types/zkochan__table": "npm:@types/table@6.
|
|
106
|
+
"@types/zkochan__table": "npm:@types/table@6.3.2",
|
|
106
107
|
"delay": "^7.0.0",
|
|
107
108
|
"jest-diff": "^30.4.1",
|
|
108
109
|
"path-name": "^1.0.0",
|
|
@@ -113,19 +114,19 @@
|
|
|
113
114
|
"write-json-file": "^7.0.0",
|
|
114
115
|
"write-package": "7.2.0",
|
|
115
116
|
"write-yaml-file": "^6.0.0",
|
|
116
|
-
"@pnpm/installing.commands": "1100.
|
|
117
|
-
"@pnpm/
|
|
117
|
+
"@pnpm/installing.commands": "1100.9.0",
|
|
118
|
+
"@pnpm/assert-project": "1100.0.16",
|
|
119
|
+
"@pnpm/installing.modules-yaml": "1100.0.9",
|
|
118
120
|
"@pnpm/logger": "1100.0.0",
|
|
119
|
-
"@pnpm/prepare": "1100.0.
|
|
120
|
-
"@pnpm/assert-project": "1100.0.14",
|
|
121
|
-
"@pnpm/store.index": "1100.1.0",
|
|
121
|
+
"@pnpm/prepare": "1100.0.16",
|
|
122
122
|
"@pnpm/test-fixtures": "1100.0.0",
|
|
123
|
-
"@pnpm/testing.command-defaults": "1100.0.4",
|
|
124
|
-
"@pnpm/testing.registry-mock": "1100.0.4",
|
|
125
|
-
"@pnpm/testing.mock-agent": "1101.0.1",
|
|
126
123
|
"@pnpm/test-ipc-server": "1100.0.0",
|
|
127
|
-
"@pnpm/
|
|
128
|
-
"@pnpm/
|
|
124
|
+
"@pnpm/testing.command-defaults": "1100.0.6",
|
|
125
|
+
"@pnpm/testing.mock-agent": "1101.0.3",
|
|
126
|
+
"@pnpm/testing.registry-mock": "1100.0.6",
|
|
127
|
+
"@pnpm/store.index": "1100.2.0",
|
|
128
|
+
"@pnpm/worker": "1100.2.0",
|
|
129
|
+
"@pnpm/workspace.projects-filter": "1100.0.21"
|
|
129
130
|
},
|
|
130
131
|
"engines": {
|
|
131
132
|
"node": ">=22.13"
|