fetchPnpmDeps: add fetcherVersion 5

The global virtual store contains package payloads that may use JSONC, as well as generated bin shims containing build-directory paths. These files should not be part of the fixed-output dependency store.

Redirect virtual-store materialization to a temporary directory. pnpmConfigHook reconstructs it offline from the archived content-addressable store.

Assisted-by: pi coding agent (GPT-5.6-sol, GPT-6-sol)
(cherry picked from commit 6692f1219c)
This commit is contained in:
Bang Lee
2026-09-20 12:11:22 -07:00
committed by Gutyina Gergő
parent 9560fc12b5
commit 8126e8cd1b
6 changed files with 116 additions and 8 deletions

View File

@@ -343,7 +343,7 @@ stdenv.mkDerivation (finalAttrs: {
pnpmDeps = fetchPnpmDeps {
inherit (finalAttrs) pname version src;
inherit pnpm;
fetcherVersion = 4;
fetcherVersion = 5;
hash = "...";
};
})
@@ -494,14 +494,14 @@ In this example, `prePnpmInstall` will be run by both `pnpmConfigHook` and by th
#### pnpm `fetcherVersion` {#javascript-pnpm-fetcherVersion}
This is the version of the output of `fetchPnpmDeps`. New packages should use `4`:
This is the version of the output of `fetchPnpmDeps`. New packages should use `5`:
```nix
{
# ...
pnpmDeps = fetchPnpmDeps {
# ...
fetcherVersion = 4;
fetcherVersion = 5;
hash = "..."; # clear this hash and generate a new one
};
}
@@ -520,6 +520,7 @@ Version 3 is the recommended value for new packages. Versions 1 and 2 are deprec
- 2: [Ensure consistent permissions](https://github.com/NixOS/nixpkgs/pull/422975)
- 3: [Build a reproducible tarball](https://github.com/NixOS/nixpkgs/pull/469950)
- 4: [Dump SQLite database to an SQL file](https://github.com/NixOS/nixpkgs/pull/522703)
- 5: [Keep virtual store materializations out of the archived store](https://github.com/NixOS/nixpkgs/pull/565315)
### Yarn {#javascript-yarn}

View File

@@ -21,6 +21,7 @@ let
2 # Ensure consistent permissions. See https://github.com/NixOS/nixpkgs/pull/422975
3 # Build a reproducible tarball. See https://github.com/NixOS/nixpkgs/pull/469950
4 # Dump SQLite database to an SQL file. See https://github.com/NixOS/nixpkgs/pull/522703
5 # Keep virtual store materializations out of the archived store. See https://github.com/NixOS/nixpkgs/pull/565315
];
in
{
@@ -145,6 +146,19 @@ in
# Run any additional pnpm configuration commands that users provide.
${prePnpmInstall}
if [[ ${toString fetcherVersion} -ge 5 ]]; then
# The virtual store is a derived installation artifact. Keep it
# outside the content-addressable store archived by this fetcher.
virtualStorePath=$(mktemp -d)
if versionAtLeast "$pnpmVersion" "11"; then
export pnpm_config_virtual_store_dir="$virtualStorePath"
export pnpm_config_global_virtual_store_dir="$virtualStorePath"
else
export npm_config_virtual_store_dir="$virtualStorePath"
export npm_config_global_virtual_store_dir="$virtualStorePath"
fi
fi
echo "Final pnpm config:"
pnpm config list
echo

View File

@@ -11,10 +11,26 @@
pnpm_11_v3 = callPackage ./pnpm_11_v3 { };
pnpm_11_v4 = callPackage ./integration/default.nix {
pnpm = pnpm_11;
pnpmDepsHash = "sha256-1u7zEw4tU9n3hYsVjiQPioGUHy9dN5yeQyidVyBvnQI=";
fetcherVersion = 4;
enableGlobalVirtualStore = false;
pnpmDepsHash = "sha256-/CwMd6V9Bp2kZASbbJQaNOG1ksbfuOQbwPs0p+zgn1E=";
};
pnpm_12_v4 = callPackage ./integration/default.nix {
pnpm = pnpm_12;
pnpmDepsHash = "sha256-cj/RldHr60y9KwktAexAJI0hmp4HcIaBgbO1N2hkGVI=";
fetcherVersion = 4;
enableGlobalVirtualStore = false;
pnpmDepsHash = "sha256-P7cooRuXXB3qmSrw6nrWooM7HBTTtKpA/1H19YwZ6Ys=";
};
pnpm_12_v5 = callPackage ./integration/default.nix {
pnpm = pnpm_12;
fetcherVersion = 5;
enableGlobalVirtualStore = false;
pnpmDepsHash = "sha256-5RGwG+P1C6XilXwvoeCYPBGAVCNp6puXMgV4CNNCzUw=";
};
pnpm_12_v5_gvs = callPackage ./integration/default.nix {
pnpm = pnpm_12;
fetcherVersion = 5;
enableGlobalVirtualStore = true;
pnpmDepsHash = "sha256-5RGwG+P1C6XilXwvoeCYPBGAVCNp6puXMgV4CNNCzUw=";
};
}

View File

@@ -9,6 +9,8 @@
pnpm,
pnpmDepsHash,
fetcherVersion,
enableGlobalVirtualStore,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "nixpkgs-pnpm-integration-test";
@@ -16,10 +18,18 @@ stdenv.mkDerivation (finalAttrs: {
src = ./src;
prePnpmInstall = lib.optionalString enableGlobalVirtualStore ''
export pnpm_config_enable_global_virtual_store=true
'';
pnpmDeps = testers.invalidateFetcherByDrvHash fetchPnpmDeps {
inherit (finalAttrs) pname version src;
inherit pnpm;
fetcherVersion = 4;
inherit (finalAttrs)
pname
version
src
prePnpmInstall
;
inherit pnpm fetcherVersion;
hash = pnpmDepsHash;
};
@@ -33,6 +43,22 @@ stdenv.mkDerivation (finalAttrs: {
buildPhase = ''
runHook preBuild
${lib.optionalString enableGlobalVirtualStore ''
if tar --zstd -tf "$pnpmDeps/pnpm-store.tar.zst" \
| grep -E '^\./v11/links(/|$)'
then
echo "pnpmDeps unexpectedly contains the global virtual store" >&2
exit 1
fi
# pnpmConfigHook should recreate the global virtual store offline.
test -d "$STORE_PATH/v11/links"
# Package payloads in the global virtual store must remain unchanged.
echo "e58a1e59497a931067b768651e52eabd8cb5328f4f54023b03988ebb7bfe9579 node_modules/@pnpm/npm-conf/lib/tsconfig.make-out.json" \
| sha256sum --check
''}
pnpm build
runHook postBuild

View File

@@ -14,6 +14,7 @@
"dist/"
],
"devDependencies": {
"@pnpm/npm-conf": "3.0.3",
"@types/node": "^25.5.0",
"typescript": "^6.0.2"
},

View File

@@ -8,6 +8,9 @@ importers:
.:
devDependencies:
'@pnpm/npm-conf':
specifier: 3.0.3
version: 3.0.3
'@types/node':
specifier: ^25.5.0
version: 25.9.6
@@ -27,6 +30,18 @@ importers:
packages:
'@pnpm/config.env-replace@1.1.0':
resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
engines: {node: '>=12.22.0'}
'@pnpm/network.ca-file@1.0.2':
resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==}
engines: {node: '>=12.22.0'}
'@pnpm/npm-conf@3.0.3':
resolution: {integrity: sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==}
engines: {node: '>=12'}
'@types/node@25.9.6':
resolution: {integrity: sha512-JR6Q/PV5DKFvjrGFVqQJdeG0qvsqQQLDa3TzFrqVwhqRXqwNaxPo2KYCtCQXpOdIulCouKwT7a6in9nFthBAzw==}
@@ -46,6 +61,18 @@ packages:
cpu: [arm64]
os: [win32]
config-chain@1.1.13:
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
graceful-fs@4.2.10:
resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
typescript@6.0.3:
resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
engines: {node: '>=14.17'}
@@ -56,6 +83,18 @@ packages:
snapshots:
'@pnpm/config.env-replace@1.1.0': {}
'@pnpm/network.ca-file@1.0.2':
dependencies:
graceful-fs: 4.2.10
'@pnpm/npm-conf@3.0.3':
dependencies:
'@pnpm/config.env-replace': 1.1.0
'@pnpm/network.ca-file': 1.0.2
config-chain: 1.1.13
'@types/node@25.9.6':
dependencies:
undici-types: 7.24.6
@@ -69,6 +108,17 @@ snapshots:
'@unrs/resolver-binding-win32-arm64-msvc@1.12.2':
optional: true
config-chain@1.1.13:
dependencies:
ini: 1.3.8
proto-list: 1.2.4
graceful-fs@4.2.10: {}
ini@1.3.8: {}
proto-list@1.2.4: {}
typescript@6.0.3: {}
undici-types@7.24.6: {}