@pnpm/exe 11.21.0 → 11.23.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/dist/worker.js CHANGED
@@ -6904,7 +6904,7 @@ function filesIncludeInstallScripts(filesIndex) {
6904
6904
  var LOCKFILE_MAJOR_VERSION = "9";
6905
6905
  var LOCKFILE_VERSION = `${LOCKFILE_MAJOR_VERSION}.0`;
6906
6906
  var ENGINE_NAME = `${process.platform};${process.arch};node${process.version.split(".")[0].substring(1)}`;
6907
- var BUILTIN_NAMED_REGISTRIES = Object.freeze({
6907
+ var BUILTIN_REGISTRIES_BY_PREFIX = Object.freeze({
6908
6908
  gh: "https://npm.pkg.github.com/",
6909
6909
  npmjs: "https://registry.npmjs.org/"
6910
6910
  });
@@ -8040,7 +8040,12 @@ function contentPathFromHex(fileType, hex) {
8040
8040
  }
8041
8041
 
8042
8042
  // ../store/cafs/lib/checkPkgFilesIntegrity.js
8043
- global["verifiedFileIntegrity"] = 0;
8043
+ var verifiedFileIntegrity = { files: 0, ms: 0 };
8044
+ function takeVerifiedFileIntegrity() {
8045
+ const taken = verifiedFileIntegrity;
8046
+ verifiedFileIntegrity = { files: 0, ms: 0 };
8047
+ return taken;
8048
+ }
8044
8049
  function checkPkgFilesIntegrity(storeDir, pkgIndex) {
8045
8050
  const verifiedFilesCache = /* @__PURE__ */ new Set();
8046
8051
  const _checkFilesIntegrity = checkFilesIntegrity.bind(null, verifiedFilesCache, storeDir, pkgIndex.algo);
@@ -8129,7 +8134,7 @@ function verifyFile(filename, fstat, algorithm) {
8129
8134
  rimrafSync(filename);
8130
8135
  return false;
8131
8136
  }
8132
- const passed = verifyFileIntegrity(filename, { digest: fstat.digest, algorithm });
8137
+ const passed = tallyVerifyFileIntegrity(filename, { digest: fstat.digest, algorithm });
8133
8138
  if (!passed) {
8134
8139
  lib_default.unlinkSync(filename);
8135
8140
  }
@@ -8137,21 +8142,39 @@ function verifyFile(filename, fstat, algorithm) {
8137
8142
  }
8138
8143
  return true;
8139
8144
  }
8145
+ function tallyVerifyFileIntegrity(filename, integrity) {
8146
+ const startedAt = performance.now();
8147
+ const data = readFileForIntegrity(filename);
8148
+ if (data == null)
8149
+ return false;
8150
+ const passed = hashMatches(data, integrity);
8151
+ if (passed == null)
8152
+ return false;
8153
+ verifiedFileIntegrity.files++;
8154
+ verifiedFileIntegrity.ms += performance.now() - startedAt;
8155
+ return passed;
8156
+ }
8140
8157
  function verifyFileIntegrity(filename, integrity) {
8141
- global["verifiedFileIntegrity"]++;
8142
- let data;
8158
+ const data = readFileForIntegrity(filename);
8159
+ if (data == null)
8160
+ return false;
8161
+ return hashMatches(data, integrity) ?? false;
8162
+ }
8163
+ function readFileForIntegrity(filename) {
8143
8164
  try {
8144
- data = lib_default.readFileSync(filename);
8165
+ return lib_default.readFileSync(filename);
8145
8166
  } catch (err) {
8146
8167
  if (util4.types.isNativeError(err) && "code" in err && err.code === "ENOENT") {
8147
- return false;
8168
+ return null;
8148
8169
  }
8149
8170
  throw err;
8150
8171
  }
8172
+ }
8173
+ function hashMatches(data, integrity) {
8151
8174
  try {
8152
8175
  return crypto3.hash(integrity.algorithm, data, "hex") === integrity.digest;
8153
8176
  } catch {
8154
- return false;
8177
+ return null;
8155
8178
  }
8156
8179
  }
8157
8180
  function checkFile(filename, checkedAt) {
@@ -8388,21 +8411,18 @@ function removeContentsOfDirSync(dir) {
8388
8411
  // ../fs/indexed-pkg-importer/lib/importIndexedDir.js
8389
8412
  var import_sanitize_filename = __toESM(require_sanitize_filename(), 1);
8390
8413
  var filenameConflictsLogger = logger("_filename-conflicts");
8414
+ var RENAME_RETRY_BUDGET_MS = 6e4;
8415
+ var RENAME_RETRY_BACKOFF_CAP_MS = 100;
8416
+ var FILE_COMPARE_BUFFER_SIZE = 64 * 1024;
8417
+ var renameRetrySleepBuffer = new Int32Array(new SharedArrayBuffer(4));
8391
8418
  function importIndexedDir(importer, newDir, filenames, opts2) {
8392
- if (!opts2.keepModulesDir) {
8393
- if (opts2.safeToSkip) {
8394
- try {
8395
- fs9.mkdirSync(newDir, { recursive: true });
8396
- tryImportIndexedDir(importer, newDir, filenames);
8397
- return;
8398
- } catch (err) {
8399
- if (util6.types.isNativeError(err) && "code" in err && err.code === "EEXIST" && allFilesMatch(newDir, filenames)) {
8400
- return;
8401
- }
8402
- }
8403
- } else if (tryExclusiveImport(importer, newDir, filenames)) {
8404
- return;
8405
- }
8419
+ const dirImport = { importer, newDir, filenames, opts: opts2 };
8420
+ if (opts2.safeToSkip && opts2.resolvedFrom !== "local-dir") {
8421
+ importIntoSharedDir(dirImport);
8422
+ return;
8423
+ }
8424
+ if (!opts2.keepModulesDir && tryExclusiveImport(importer, newDir, filenames)) {
8425
+ return;
8406
8426
  }
8407
8427
  const stage = fastPathTemp(newDir);
8408
8428
  try {
@@ -8416,51 +8436,161 @@ function importIndexedDir(importer, newDir, filenames, opts2) {
8416
8436
  rimrafSync(stage);
8417
8437
  } catch {
8418
8438
  }
8419
- if (util6.types.isNativeError(err) && "code" in err && err.code === "EEXIST") {
8420
- const { uniqueFileMap, conflictingFileNames } = getUniqueFileMap(filenames);
8421
- if (conflictingFileNames.size === 0)
8422
- throw err;
8423
- filenameConflictsLogger.debug({
8424
- conflicts: Object.fromEntries(conflictingFileNames),
8425
- writingTo: newDir
8426
- });
8427
- globalWarn(`Not all files were linked to "${path13.relative(process.cwd(), newDir)}". Some of the files have equal names in different case, which is an issue on case-insensitive filesystems. The conflicting file names are: ${JSON.stringify(Object.fromEntries(conflictingFileNames))}`);
8428
- importIndexedDir(importer, newDir, uniqueFileMap, opts2);
8439
+ if (retryWithFixedFileMap(err, dirImport))
8429
8440
  return;
8441
+ throw err;
8442
+ }
8443
+ try {
8444
+ renameOverwriteSync(stage, newDir);
8445
+ } catch (renameErr) {
8446
+ try {
8447
+ rimrafSync(stage);
8448
+ } catch {
8430
8449
  }
8431
- if (util6.types.isNativeError(err) && "code" in err && err.code === "ENOENT") {
8432
- if (retryWithSanitizedFilenames(importer, newDir, filenames, opts2))
8433
- return;
8450
+ throw renameErr;
8451
+ }
8452
+ }
8453
+ function importIntoSharedDir(dirImport) {
8454
+ const { importer, newDir, filenames } = dirImport;
8455
+ fs9.mkdirSync(path13.dirname(newDir), { recursive: true });
8456
+ let created = false;
8457
+ try {
8458
+ fs9.mkdirSync(newDir);
8459
+ created = true;
8460
+ } catch (err) {
8461
+ if (!util6.types.isNativeError(err) || !("code" in err) || err.code !== "EEXIST")
8434
8462
  throw err;
8463
+ }
8464
+ if (created) {
8465
+ try {
8466
+ tryImportIndexedDir(importer, newDir, filenames);
8467
+ return;
8468
+ } catch (err) {
8469
+ if (retryWithFixedFileMap(err, dirImport))
8470
+ return;
8435
8471
  }
8472
+ }
8473
+ if (allFilesMatch(newDir, filenames))
8474
+ return;
8475
+ try {
8476
+ repairIndexedDir(dirImport);
8477
+ } catch (err) {
8478
+ if (retryWithFixedFileMap(err, dirImport))
8479
+ return;
8436
8480
  throw err;
8437
8481
  }
8438
- if (opts2.safeToSkip) {
8482
+ }
8483
+ function repairIndexedDir({ importer, newDir, filenames }) {
8484
+ makeFileMapDirs(newDir, filenames, { clearBlockers: true });
8485
+ let packageJsonSrc;
8486
+ for (const [f, src2] of filenames) {
8487
+ if (f === "package.json") {
8488
+ packageJsonSrc = src2;
8489
+ continue;
8490
+ }
8491
+ replaceFileIfDifferent(importer.importFile, src2, path13.join(newDir, f));
8492
+ }
8493
+ if (packageJsonSrc !== void 0) {
8494
+ replaceFileIfDifferent(importer.importFile, packageJsonSrc, path13.join(newDir, "package.json"));
8495
+ }
8496
+ }
8497
+ function replaceFileIfDifferent(importFile, src2, dest) {
8498
+ if (mismatchReason(dest, src2) === void 0)
8499
+ return;
8500
+ const tmp = fastPathTemp(dest);
8501
+ try {
8502
+ importFile(src2, tmp);
8503
+ } catch (err) {
8439
8504
  try {
8440
- fs9.renameSync(stage, newDir);
8505
+ fs9.unlinkSync(tmp);
8506
+ } catch {
8507
+ }
8508
+ throw err;
8509
+ }
8510
+ try {
8511
+ clearDirBlockingFile(dest);
8512
+ renameFileWithRetry(tmp, dest);
8513
+ } catch (err) {
8514
+ try {
8515
+ fs9.unlinkSync(tmp);
8516
+ } catch {
8517
+ }
8518
+ if (mismatchReason(dest, src2) === void 0)
8519
+ return;
8520
+ throw err;
8521
+ }
8522
+ }
8523
+ function renameFileWithRetry(src2, dest) {
8524
+ const startedAt = Date.now();
8525
+ let backoffMs = 0;
8526
+ for (; ; ) {
8527
+ try {
8528
+ fs9.renameSync(src2, dest);
8441
8529
  return;
8442
8530
  } catch (err) {
8443
- if (util6.types.isNativeError(err) && "code" in err && (err.code === "ENOTEMPTY" || err.code === "EEXIST" || err.code === "EPERM")) {
8444
- if (allFilesMatch(newDir, filenames)) {
8445
- try {
8446
- rimrafSync(stage);
8447
- } catch {
8448
- }
8449
- return;
8450
- }
8451
- }
8531
+ if (!isTransientRenameError(err) || Date.now() - startedAt >= RENAME_RETRY_BUDGET_MS)
8532
+ throw err;
8533
+ if (backoffMs > 0)
8534
+ Atomics.wait(renameRetrySleepBuffer, 0, 0, backoffMs);
8535
+ backoffMs = Math.min(backoffMs + 10, RENAME_RETRY_BACKOFF_CAP_MS);
8452
8536
  }
8453
8537
  }
8538
+ }
8539
+ function isTransientRenameError(err) {
8540
+ return process.platform === "win32" && util6.types.isNativeError(err) && "code" in err && (err.code === "EPERM" || err.code === "EACCES" || err.code === "EBUSY");
8541
+ }
8542
+ function clearDirBlockingFile(dest) {
8543
+ let stats;
8454
8544
  try {
8455
- renameOverwriteSync(stage, newDir);
8456
- } catch (renameErr) {
8545
+ stats = fs9.lstatSync(dest);
8546
+ } catch (err) {
8547
+ if (util6.types.isNativeError(err) && "code" in err && err.code === "ENOENT")
8548
+ return;
8549
+ throw err;
8550
+ }
8551
+ if (stats.isDirectory()) {
8552
+ rimrafSync(dest);
8553
+ }
8554
+ }
8555
+ function clearDirentBlockingDir(newDir, relativeDir) {
8556
+ let dir = newDir;
8557
+ for (const segment of relativeDir.split(/[\\/]/)) {
8558
+ dir = path13.join(dir, segment);
8559
+ let stats;
8457
8560
  try {
8458
- rimrafSync(stage);
8459
- } catch {
8561
+ stats = fs9.lstatSync(dir);
8562
+ } catch (err) {
8563
+ if (util6.types.isNativeError(err) && "code" in err && err.code === "ENOENT")
8564
+ return;
8565
+ throw err;
8460
8566
  }
8461
- throw renameErr;
8567
+ if (stats.isDirectory())
8568
+ continue;
8569
+ fs9.unlinkSync(dir);
8570
+ return;
8462
8571
  }
8463
8572
  }
8573
+ function retryWithFixedFileMap(err, dirImport) {
8574
+ const { importer, newDir, filenames, opts: opts2 } = dirImport;
8575
+ if (!util6.types.isNativeError(err) || !("code" in err))
8576
+ return false;
8577
+ if (err.code === "EEXIST") {
8578
+ const { uniqueFileMap, conflictingFileNames } = getUniqueFileMap(filenames);
8579
+ if (conflictingFileNames.size === 0)
8580
+ return false;
8581
+ filenameConflictsLogger.debug({
8582
+ conflicts: Object.fromEntries(conflictingFileNames),
8583
+ writingTo: newDir
8584
+ });
8585
+ globalWarn(`Not all files were linked to "${path13.relative(process.cwd(), newDir)}". Some of the files have equal names in different case, which is an issue on case-insensitive filesystems. The conflicting file names are: ${JSON.stringify(Object.fromEntries(conflictingFileNames))}`);
8586
+ importIndexedDir(importer, newDir, uniqueFileMap, opts2);
8587
+ return true;
8588
+ }
8589
+ if (err.code === "ENOENT") {
8590
+ return retryWithSanitizedFilenames(dirImport);
8591
+ }
8592
+ return false;
8593
+ }
8464
8594
  function tryExclusiveImport(importer, newDir, filenames) {
8465
8595
  fs9.mkdirSync(path13.dirname(newDir), { recursive: true });
8466
8596
  try {
@@ -8482,29 +8612,67 @@ function tryExclusiveImport(importer, newDir, filenames) {
8482
8612
  }
8483
8613
  }
8484
8614
  function allFilesMatch(dir, filenames) {
8615
+ const markerSrc = filenames.get("package.json");
8616
+ if (markerSrc !== void 0 && !fileMatches(dir, "package.json", markerSrc))
8617
+ return false;
8485
8618
  for (const [f, src2] of filenames) {
8486
- const target2 = path13.join(dir, f);
8619
+ if (f === "package.json")
8620
+ continue;
8621
+ if (!fileMatches(dir, f, src2))
8622
+ return false;
8623
+ }
8624
+ return true;
8625
+ }
8626
+ function fileMatches(dir, f, src2) {
8627
+ const reason = mismatchReason(path13.join(dir, f), src2);
8628
+ if (reason === void 0)
8629
+ return true;
8630
+ globalInfo(`Re-importing "${dir}" because file "${f}" ${reason}`);
8631
+ return false;
8632
+ }
8633
+ function mismatchReason(target2, src2) {
8634
+ try {
8635
+ const targetStat = fs9.lstatSync(target2, { bigint: true });
8636
+ if (!targetStat.isFile())
8637
+ return "is not a regular file";
8638
+ const srcStat = lib_default.statSync(src2, { bigint: true });
8639
+ const hasSameFileIdentity = targetStat.ino !== 0n && targetStat.dev !== 0n && targetStat.ino === srcStat.ino && targetStat.dev === srcStat.dev;
8640
+ if (hasSameFileIdentity)
8641
+ return void 0;
8642
+ if (targetStat.size !== srcStat.size)
8643
+ return "has a different size";
8644
+ if (!filesHaveEqualContents(target2, src2))
8645
+ return "has different content";
8646
+ return void 0;
8647
+ } catch {
8648
+ return "is missing or unreadable";
8649
+ }
8650
+ }
8651
+ function filesHaveEqualContents(left, right) {
8652
+ const leftBuffer = Buffer.allocUnsafe(FILE_COMPARE_BUFFER_SIZE);
8653
+ const rightBuffer = Buffer.allocUnsafe(FILE_COMPARE_BUFFER_SIZE);
8654
+ const leftFd = fs9.openSync(left, "r");
8655
+ try {
8656
+ const rightFd = fs9.openSync(right, "r");
8487
8657
  try {
8488
- const targetStat = lib_default.statSync(target2);
8489
- const srcStat = lib_default.statSync(src2);
8490
- if (targetStat.ino === srcStat.ino && targetStat.dev === srcStat.dev)
8491
- continue;
8492
- if (targetStat.size !== srcStat.size) {
8493
- globalInfo(`Re-importing "${dir}" because file "${f}" has a different size`);
8494
- return false;
8495
- }
8496
- if (!lib_default.readFileSync(target2).equals(lib_default.readFileSync(src2))) {
8497
- globalInfo(`Re-importing "${dir}" because file "${f}" has different content`);
8498
- return false;
8658
+ for (; ; ) {
8659
+ const leftBytes = fs9.readSync(leftFd, leftBuffer, 0, leftBuffer.length, null);
8660
+ const rightBytes = fs9.readSync(rightFd, rightBuffer, 0, rightBuffer.length, null);
8661
+ if (leftBytes !== rightBytes)
8662
+ return false;
8663
+ if (leftBytes === 0)
8664
+ return true;
8665
+ if (!leftBuffer.subarray(0, leftBytes).equals(rightBuffer.subarray(0, rightBytes)))
8666
+ return false;
8499
8667
  }
8500
- } catch {
8501
- globalInfo(`Re-importing "${dir}" because file "${f}" is missing or unreadable`);
8502
- return false;
8668
+ } finally {
8669
+ fs9.closeSync(rightFd);
8503
8670
  }
8671
+ } finally {
8672
+ fs9.closeSync(leftFd);
8504
8673
  }
8505
- return true;
8506
8674
  }
8507
- function retryWithSanitizedFilenames(importer, newDir, filenames, opts2) {
8675
+ function retryWithSanitizedFilenames({ importer, newDir, filenames, opts: opts2 }) {
8508
8676
  const { sanitizedFilenames, invalidFilenames } = sanitizeFilenames(filenames);
8509
8677
  if (invalidFilenames.length === 0)
8510
8678
  return false;
@@ -8525,14 +8693,7 @@ function sanitizeFilenames(filenames) {
8525
8693
  return { sanitizedFilenames, invalidFilenames };
8526
8694
  }
8527
8695
  function tryImportIndexedDir({ importFile, importFileAtomic }, newDir, filenames) {
8528
- const allDirs = /* @__PURE__ */ new Set();
8529
- for (const f of filenames.keys()) {
8530
- const dir = path13.dirname(f);
8531
- if (dir === ".")
8532
- continue;
8533
- allDirs.add(dir);
8534
- }
8535
- Array.from(allDirs).sort((d1, d2) => d1.length - d2.length).forEach((dir) => fs9.mkdirSync(path13.join(newDir, dir), { recursive: true }));
8696
+ makeFileMapDirs(newDir, filenames);
8536
8697
  let packageJsonSrc;
8537
8698
  for (const [f, src2] of filenames) {
8538
8699
  if (f === "package.json") {
@@ -8545,6 +8706,21 @@ function tryImportIndexedDir({ importFile, importFileAtomic }, newDir, filenames
8545
8706
  importFileAtomic(packageJsonSrc, path13.join(newDir, "package.json"));
8546
8707
  }
8547
8708
  }
8709
+ function makeFileMapDirs(newDir, filenames, opts2) {
8710
+ const allDirs = /* @__PURE__ */ new Set();
8711
+ for (const f of filenames.keys()) {
8712
+ const dir = path13.dirname(f);
8713
+ if (dir === ".")
8714
+ continue;
8715
+ allDirs.add(dir);
8716
+ }
8717
+ for (const dir of Array.from(allDirs).sort((d1, d2) => d1.length - d2.length)) {
8718
+ if (opts2?.clearBlockers) {
8719
+ clearDirentBlockingDir(newDir, dir);
8720
+ }
8721
+ fs9.mkdirSync(path13.join(newDir, dir), { recursive: true });
8722
+ }
8723
+ }
8548
8724
  function getUniqueFileMap(fileMap) {
8549
8725
  const lowercaseFiles = /* @__PURE__ */ new Map();
8550
8726
  const conflictingFileNames = /* @__PURE__ */ new Map();
@@ -11658,6 +11834,7 @@ async function handleMessage(message) {
11658
11834
  if (!pkgFilesIndex) {
11659
11835
  parentPort.postMessage({
11660
11836
  status: "success",
11837
+ verifiedFileIntegrity: takeVerifiedFileIntegrity(),
11661
11838
  value: {
11662
11839
  verified: false,
11663
11840
  pkgFilesIndex: null
@@ -11692,6 +11869,10 @@ If you want to ignore this issue, set strictStorePkgContentCheck to false in you
11692
11869
  parentPort.postMessage({
11693
11870
  status: "success",
11694
11871
  warnings,
11872
+ // Store verification happens here, in the worker, but the
11873
+ // install reports it from the main thread. Hand this worker's
11874
+ // share back with the answer it belongs to.
11875
+ verifiedFileIntegrity: takeVerifiedFileIntegrity(),
11695
11876
  value: {
11696
11877
  verified: verifyResult.passed,
11697
11878
  bundledManifest,
@@ -11718,6 +11899,10 @@ If you want to ignore this issue, set strictStorePkgContentCheck to false in you
11718
11899
  } catch (e) {
11719
11900
  parentPort.postMessage({
11720
11901
  status: "error",
11902
+ // Drained here too: a request that hashed and then threw would
11903
+ // otherwise leave its share in this worker, to be handed to
11904
+ // whichever install asks next.
11905
+ verifiedFileIntegrity: takeVerifiedFileIntegrity(),
11721
11906
  error: {
11722
11907
  code: e.code,
11723
11908
  message: e.message ?? e.toString(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/exe",
3
- "version": "11.21.0",
3
+ "version": "11.23.0",
4
4
  "description": "Fast, disk space efficient package manager",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -35,17 +35,17 @@
35
35
  "detect-libc": "^2.1.2"
36
36
  },
37
37
  "optionalDependencies": {
38
- "@pnpm/linux-arm64": "11.21.0",
39
- "@pnpm/linux-x64": "11.21.0",
40
- "@pnpm/linuxstatic-arm64": "11.21.0",
41
- "@pnpm/linuxstatic-x64": "11.21.0",
42
- "@pnpm/macos-arm64": "11.21.0",
43
- "@pnpm/win-arm64": "11.21.0",
44
- "@pnpm/win-x64": "11.21.0"
38
+ "@pnpm/linux-arm64": "11.23.0",
39
+ "@pnpm/linux-x64": "11.23.0",
40
+ "@pnpm/linuxstatic-arm64": "11.23.0",
41
+ "@pnpm/linuxstatic-x64": "11.23.0",
42
+ "@pnpm/macos-arm64": "11.23.0",
43
+ "@pnpm/win-arm64": "11.23.0",
44
+ "@pnpm/win-x64": "11.23.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@jest/globals": "30.4.1",
48
- "@pnpm/exe": "11.21.0",
48
+ "@pnpm/exe": "11.23.0",
49
49
  "@pnpm/jest-config": "1100.0.22",
50
50
  "@zkochan/cmd-shim": "^9.0.7",
51
51
  "execa": "npm:safe-execa@0.3.0"