@pnpm/building.after-install 1101.0.18 → 1101.0.19

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.
@@ -41,6 +41,8 @@ export type StrictBuildOptions = {
41
41
  shamefullyHoist: boolean;
42
42
  deployAllFiles: boolean;
43
43
  allowBuilds?: Record<string, boolean | string>;
44
+ enableGlobalVirtualStore?: boolean;
45
+ globalVirtualStoreDir?: string;
44
46
  virtualStoreDirMaxLength: number;
45
47
  peersSuffixMaxLength: number;
46
48
  strictStorePkgContentCheck: boolean;
package/lib/index.js CHANGED
@@ -6,7 +6,7 @@ import { pkgRequiresBuild } from '@pnpm/building.pkg-requires-build';
6
6
  import { createAllowBuildFunction } from '@pnpm/building.policy';
7
7
  import { LAYOUT_VERSION, WANTED_LOCKFILE, } from '@pnpm/constants';
8
8
  import { skippedOptionalDependencyLogger } from '@pnpm/core-loggers';
9
- import { calcDepState, findRuntimeNodeVersion, lockfileToDepGraph } from '@pnpm/deps.graph-hasher';
9
+ import { calcDepState, findRuntimeNodeVersion, iterateHashedGraphNodes, iteratePkgMeta, lockfileToDepGraph } from '@pnpm/deps.graph-hasher';
10
10
  import { graphSequencer } from '@pnpm/deps.graph-sequencer';
11
11
  import * as dp from '@pnpm/deps.path';
12
12
  import { PnpmError } from '@pnpm/error';
@@ -25,6 +25,10 @@ import pLimit from 'p-limit';
25
25
  import { runGroups } from 'run-groups';
26
26
  import semver from 'semver';
27
27
  import { extendBuildOptions, } from './extendBuildOptions.js';
28
+ // Serializes builds of a shared GVS projection across concurrent per-project
29
+ // rebuilds: the first build proceeds, concurrent ones await it and reuse the
30
+ // result. Keyed by the absolute projection directory.
31
+ const gvsBuildLocks = new Map();
28
32
  function findPackages(packages, searched, opts) {
29
33
  return Object.keys(packages)
30
34
  .filter((relativeDepPath) => {
@@ -229,12 +233,25 @@ async function _rebuild(ctx, opts) {
229
233
  };
230
234
  const builtDepPaths = new Set();
231
235
  const storeIndex = opts.skipIfHasSideEffectsCache ? new StoreIndex(opts.storeDir) : undefined;
236
+ // Under GVS, packages live at `<globalVirtualStoreDir>/<hash>/node_modules/<name>`,
237
+ // not the classic virtualStoreDir layout. The hash is computed with the same inputs
238
+ // as the installer so rebuild resolves the exact directory the install created.
239
+ const gvsDirByDepPath = new Map();
240
+ if (opts.enableGlobalVirtualStore) {
241
+ const globalVirtualStoreDir = opts.globalVirtualStoreDir ?? path.join(opts.storeDir, 'links');
242
+ for (const { hash, pkgMeta } of iterateHashedGraphNodes(depGraph, iteratePkgMeta(ctx.currentLockfile, depGraph), _allowBuild, opts.supportedArchitectures, nodeVersion)) {
243
+ gvsDirByDepPath.set(pkgMeta.depPath, path.join(globalVirtualStoreDir, hash));
244
+ }
245
+ }
246
+ const pkgModulesDir = (depPath) => gvsDirByDepPath.has(depPath)
247
+ ? path.join(gvsDirByDepPath.get(depPath), 'node_modules')
248
+ : path.join(ctx.virtualStoreDir, dp.depPathToFilename(depPath, opts.virtualStoreDirMaxLength), 'node_modules');
232
249
  const groups = chunks.map((chunk) => chunk.filter((depPath) => ctx.pkgsToRebuild.has(depPath) && !ctx.skipped.has(depPath)).map((depPath) => async () => {
233
250
  const pkgSnapshot = pkgSnapshots[depPath];
234
251
  const pkgInfo = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
235
252
  const pkgRoots = opts.nodeLinker === 'hoisted'
236
253
  ? (ctx.modulesFile?.hoistedLocations?.[depPath] ?? []).map((hoistedLocation) => path.join(opts.lockfileDir, hoistedLocation))
237
- : [path.join(ctx.virtualStoreDir, dp.depPathToFilename(depPath, opts.virtualStoreDirMaxLength), 'node_modules', pkgInfo.name)];
254
+ : [path.join(pkgModulesDir(depPath), pkgInfo.name)];
238
255
  if (pkgRoots.length === 0) {
239
256
  if (pkgSnapshot.optional)
240
257
  return;
@@ -243,10 +260,32 @@ async function _rebuild(ctx, opts) {
243
260
  });
244
261
  }
245
262
  const pkgRoot = pkgRoots[0];
263
+ // If another project is already building this shared projection, wait for it
264
+ // and reuse the result instead of racing on the same directory.
265
+ const gvsDir = gvsDirByDepPath.get(depPath);
266
+ if (gvsDir != null) {
267
+ const inFlight = gvsBuildLocks.get(gvsDir);
268
+ if (inFlight != null) {
269
+ await inFlight.catch(() => { });
270
+ pkgsThatWereRebuilt.add(depPath);
271
+ return;
272
+ }
273
+ }
274
+ let releaseGvsLock;
275
+ if (gvsDir != null) {
276
+ let resolveLock;
277
+ gvsBuildLocks.set(gvsDir, new Promise((resolve) => {
278
+ resolveLock = resolve;
279
+ }));
280
+ releaseGvsLock = () => {
281
+ gvsBuildLocks.delete(gvsDir);
282
+ resolveLock();
283
+ };
284
+ }
246
285
  try {
247
286
  const extraBinPaths = ctx.extraBinPaths;
248
287
  if (opts.nodeLinker !== 'hoisted') {
249
- const modules = path.join(ctx.virtualStoreDir, dp.depPathToFilename(depPath, opts.virtualStoreDirMaxLength), 'node_modules');
288
+ const modules = pkgModulesDir(depPath);
250
289
  const binPath = path.join(pkgRoot, 'node_modules', '.bin');
251
290
  await linkBins(modules, binPath, { extraNodePaths: ctx.extraNodePaths, warn });
252
291
  }
@@ -337,6 +376,9 @@ async function _rebuild(ctx, opts) {
337
376
  }
338
377
  throw err;
339
378
  }
379
+ finally {
380
+ releaseGvsLock?.();
381
+ }
340
382
  if (pkgRoots.length > 1) {
341
383
  await hardLinkDir(pkgRoot, pkgRoots.slice(1));
342
384
  }
@@ -351,7 +393,7 @@ async function _rebuild(ctx, opts) {
351
393
  .map(async (depPath) => limitLinking(async () => {
352
394
  const pkgSnapshot = pkgSnapshots[depPath];
353
395
  const pkgInfo = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
354
- const modules = path.join(ctx.virtualStoreDir, dp.depPathToFilename(depPath, opts.virtualStoreDirMaxLength), 'node_modules');
396
+ const modules = pkgModulesDir(depPath);
355
397
  const binPath = path.join(modules, pkgInfo.name, 'node_modules', '.bin');
356
398
  return linkBins(modules, binPath, { warn });
357
399
  })));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/building.after-install",
3
- "version": "1101.0.18",
3
+ "version": "1101.0.19",
4
4
  "description": "Rebuild packages that are already installed by running their lifecycle scripts",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -9,7 +9,10 @@
9
9
  ],
10
10
  "license": "MIT",
11
11
  "funding": "https://opencollective.com/pnpm",
12
- "repository": "https://github.com/pnpm/pnpm/tree/main/building/after-install",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/pnpm/pnpm/tree/main/building/after-install"
15
+ },
13
16
  "homepage": "https://github.com/pnpm/pnpm/tree/main/building/after-install#readme",
14
17
  "bugs": {
15
18
  "url": "https://github.com/pnpm/pnpm/issues"
@@ -30,37 +33,37 @@
30
33
  "p-limit": "^7.3.0",
31
34
  "run-groups": "^5.0.0",
32
35
  "semver": "^7.8.1",
33
- "@pnpm/building.pkg-requires-build": "1100.0.5",
34
- "@pnpm/building.policy": "1100.0.7",
35
- "@pnpm/bins.linker": "1100.0.10",
36
- "@pnpm/config.normalize-registries": "1100.0.5",
37
- "@pnpm/config.reader": "1101.5.0",
36
+ "@pnpm/building.pkg-requires-build": "1100.0.6",
37
+ "@pnpm/config.normalize-registries": "1100.0.6",
38
+ "@pnpm/config.reader": "1101.6.0",
38
39
  "@pnpm/constants": "1100.0.0",
39
- "@pnpm/core-loggers": "1100.1.2",
40
- "@pnpm/deps.graph-hasher": "1100.2.2",
40
+ "@pnpm/building.policy": "1100.0.8",
41
+ "@pnpm/core-loggers": "1100.1.3",
41
42
  "@pnpm/deps.graph-sequencer": "1100.0.0",
42
- "@pnpm/deps.path": "1100.0.5",
43
+ "@pnpm/deps.path": "1100.0.6",
44
+ "@pnpm/deps.graph-hasher": "1100.2.3",
43
45
  "@pnpm/error": "1100.0.0",
44
- "@pnpm/exec.lifecycle": "1100.0.14",
45
- "@pnpm/installing.context": "1100.0.14",
46
- "@pnpm/installing.modules-yaml": "1100.0.6",
47
- "@pnpm/lockfile.types": "1100.0.8",
48
- "@pnpm/lockfile.walker": "1100.0.8",
49
- "@pnpm/pkg-manifest.reader": "1100.0.5",
50
- "@pnpm/lockfile.utils": "1100.0.10",
51
- "@pnpm/store.connection-manager": "1100.2.5",
52
- "@pnpm/store.controller-types": "1100.1.2",
53
- "@pnpm/store.cafs": "1100.1.7",
46
+ "@pnpm/installing.context": "1100.0.15",
47
+ "@pnpm/exec.lifecycle": "1100.0.15",
48
+ "@pnpm/installing.modules-yaml": "1100.0.7",
49
+ "@pnpm/lockfile.utils": "1100.0.11",
50
+ "@pnpm/lockfile.walker": "1100.0.9",
51
+ "@pnpm/pkg-manifest.reader": "1100.0.6",
52
+ "@pnpm/store.cafs": "1100.1.8",
53
+ "@pnpm/store.connection-manager": "1100.2.6",
54
+ "@pnpm/store.controller-types": "1100.1.3",
54
55
  "@pnpm/store.index": "1100.1.0",
55
- "@pnpm/types": "1101.2.0"
56
+ "@pnpm/lockfile.types": "1100.0.9",
57
+ "@pnpm/types": "1101.3.0",
58
+ "@pnpm/bins.linker": "1100.0.11"
56
59
  },
57
60
  "peerDependencies": {
58
61
  "@pnpm/logger": "^1001.0.1",
59
- "@pnpm/worker": "^1100.1.8"
62
+ "@pnpm/worker": "^1100.1.9"
60
63
  },
61
64
  "devDependencies": {
62
65
  "@types/semver": "7.7.1",
63
- "@pnpm/building.after-install": "1101.0.18"
66
+ "@pnpm/building.after-install": "1101.0.19"
64
67
  },
65
68
  "engines": {
66
69
  "node": ">=22.13"