mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-06-05 21:03:40 +00:00
241 lines
8.0 KiB
Nix
241 lines
8.0 KiB
Nix
{
|
|
lib,
|
|
stdenvNoCC,
|
|
callPackage,
|
|
jq,
|
|
moreutils,
|
|
cacert,
|
|
makeSetupHook,
|
|
pnpm,
|
|
pnpm-fixup-state-db,
|
|
sqlite,
|
|
writableTmpDirAsHomeHook,
|
|
yq,
|
|
zstd,
|
|
}:
|
|
let
|
|
pnpmLatest = pnpm;
|
|
|
|
supportedFetcherVersions = [
|
|
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
|
|
];
|
|
in
|
|
{
|
|
fetchPnpmDeps = lib.makeOverridable (
|
|
{
|
|
hash ? "",
|
|
pname,
|
|
pnpm ? pnpmLatest,
|
|
pnpmWorkspaces ? [ ],
|
|
prePnpmInstall ? "",
|
|
pnpmInstallFlags ? [ ],
|
|
fetcherVersion ? null,
|
|
...
|
|
}@args:
|
|
let
|
|
args' = removeAttrs args [
|
|
"hash"
|
|
"pname"
|
|
];
|
|
hash' =
|
|
if hash != "" then
|
|
{ outputHash = hash; }
|
|
else
|
|
{
|
|
outputHash = "";
|
|
outputHashAlgo = "sha256";
|
|
};
|
|
|
|
filterFlags = lib.map (package: "--filter=${package}") pnpmWorkspaces;
|
|
|
|
pnpm-fixup-state-db' =
|
|
if pnpm.nodejs or null != null then
|
|
pnpm-fixup-state-db.override {
|
|
inherit (pnpm) nodejs;
|
|
}
|
|
else
|
|
pnpm-fixup-state-db;
|
|
in
|
|
assert
|
|
fetcherVersion != null
|
|
|| throw "fetchPnpmDeps: `fetcherVersion` is not set, see https://nixos.org/manual/nixpkgs/stable/#javascript-pnpm-fetcherVersion.";
|
|
|
|
assert
|
|
!(fetcherVersion == 1 || fetcherVersion == 2)
|
|
|| throw "fetchPnpmDeps: `fetcherVersion = ${toString fetcherVersion}` was removed in the 26.11 release. Please migrate `${pname}` to `fetcherVersion = 3` and regenerate the hash. See https://nixos.org/manual/nixpkgs/stable/#javascript-pnpm-fetcherVersion.";
|
|
|
|
assert
|
|
builtins.elem fetcherVersion supportedFetcherVersions
|
|
|| throw "fetchPnpmDeps `fetcherVersion` is not set to a supported value (${lib.concatStringsSep ", " (map toString supportedFetcherVersions)}), see https://nixos.org/manual/nixpkgs/stable/#javascript-pnpm-fetcherVersion.";
|
|
|
|
stdenvNoCC.mkDerivation (
|
|
finalAttrs:
|
|
(
|
|
args'
|
|
// {
|
|
name = "${pname}-pnpm-deps";
|
|
|
|
nativeBuildInputs = [
|
|
cacert
|
|
jq
|
|
moreutils
|
|
pnpm # from args
|
|
pnpm-fixup-state-db'
|
|
sqlite
|
|
writableTmpDirAsHomeHook
|
|
yq
|
|
zstd
|
|
]
|
|
++ args.nativeBuildInputs or [ ];
|
|
|
|
impureEnvVars =
|
|
lib.fetchers.proxyImpureEnvVars ++ [ "NIX_NPM_REGISTRY" ] ++ args.impureEnvVars or [ ];
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
versionAtLeast () {
|
|
local cur_version=$1 min_version=$2
|
|
printf "%s\0%s" "$min_version" "$cur_version" | sort -zVC
|
|
}
|
|
|
|
lockfileVersion="$(yq -r .lockfileVersion pnpm-lock.yaml)"
|
|
if [[ ''${lockfileVersion:0:1} -gt ${lib.versions.major pnpm.version} ]]; then
|
|
echo "ERROR: lockfileVersion $lockfileVersion in pnpm-lock.yaml is too new for the provided pnpm version ${lib.versions.major pnpm.version}!"
|
|
exit 1
|
|
fi
|
|
|
|
# The pnpm store is bundled into a compressed tarball within $out,
|
|
# without distributing the uncompressed store files.
|
|
mkdir $out
|
|
storePath=$(mktemp -d)
|
|
|
|
pushd "$HOME"
|
|
pnpmVersion=$(pnpm --version)
|
|
|
|
if versionAtLeast "$pnpmVersion" "11"; then
|
|
# pnpm 11 uses a different mechanism to manage package manager versions
|
|
export pnpm_config_pm_on_fail=ignore
|
|
|
|
# Some packages produce platform dependent outputs. We do not want to cache those in the global store
|
|
export pnpm_config_side_effects_cache=false
|
|
|
|
export pnpm_config_update_notifier=false
|
|
else
|
|
pnpm config set manage-package-manager-versions false
|
|
pnpm config set side-effects-cache false
|
|
pnpm config set update-notifier false
|
|
fi
|
|
popd
|
|
|
|
pnpm config set store-dir $storePath
|
|
|
|
# Run any additional pnpm configuration commands that users provide.
|
|
${prePnpmInstall}
|
|
|
|
echo "Final pnpm config:"
|
|
pnpm config list
|
|
echo
|
|
|
|
# pnpm is going to warn us about using --force
|
|
# --force allows us to fetch all dependencies including ones that aren't meant for our host platform
|
|
pnpm install \
|
|
--force \
|
|
--ignore-scripts \
|
|
${lib.escapeShellArgs filterFlags} \
|
|
${lib.escapeShellArgs pnpmInstallFlags} \
|
|
--registry="$NIX_NPM_REGISTRY" \
|
|
--frozen-lockfile
|
|
|
|
# Record the fetcherVersion in the output for introspection.
|
|
echo ${toString fetcherVersion} > $out/.fetcher-version
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
fixupPhase = ''
|
|
runHook preFixup
|
|
|
|
# Remove timestamp and sort the json files
|
|
rm -rf $storePath/{v3,v10,v11}/tmp
|
|
for f in $(find $storePath -name "*.json"); do
|
|
jq --sort-keys "del(.. | .checkedAt?)" $f | sponge $f
|
|
done
|
|
|
|
if [ -f "$storePath/v11/index.db" ]; then
|
|
pnpm-fixup-state-db "$storePath/v11";
|
|
# Dump the SQLite database to a SQL text file for reproducibility.
|
|
# SQLite's binary format is non-deterministic (version-valid-for number, etc),
|
|
# so we store the logical contents as SQL statements and reconstruct during build.
|
|
if [[ ${toString fetcherVersion} -ge 4 ]]; then
|
|
sqlite3 "$storePath/v11/index.db" .dump > "$storePath/v11/index.db.sql"
|
|
rm "$storePath/v11/index.db"
|
|
fi
|
|
fi
|
|
|
|
# This folder contains symlinks to /build/source which we don't need
|
|
# since https://github.com/pnpm/pnpm/releases/tag/v10.27.0
|
|
rm -rf $storePath/{v3,v10,v11}/projects
|
|
|
|
# Ensure consistent permissions
|
|
# NOTE: For reasons not yet fully understood, pnpm might create files with
|
|
# inconsistent permissions, for example inside the ubuntu-24.04
|
|
# github actions runner.
|
|
# To ensure stable derivations, we need to set permissions
|
|
# consistently, namely:
|
|
# * All files with `-exec` suffix have 555.
|
|
# * All other files have 444.
|
|
# * All folders have 555.
|
|
# See https://github.com/NixOS/nixpkgs/pull/350063
|
|
# See https://github.com/NixOS/nixpkgs/issues/422889
|
|
find $storePath -type f -name "*-exec" -print0 | xargs --no-run-if-empty -0 chmod 555
|
|
find $storePath -type f -not -name "*-exec" -print0 | xargs --no-run-if-empty -0 chmod 444
|
|
find $storePath -type d -print0 | xargs --no-run-if-empty -0 chmod 555
|
|
|
|
(
|
|
cd $storePath
|
|
|
|
# Build a reproducible tarball, per instructions at https://reproducible-builds.org/docs/archives/
|
|
tar --sort=name \
|
|
--mtime="@$SOURCE_DATE_EPOCH" \
|
|
--owner=0 --group=0 --numeric-owner \
|
|
--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \
|
|
--zstd -cf $out/pnpm-store.tar.zst .
|
|
)
|
|
|
|
runHook postFixup
|
|
'';
|
|
|
|
passthru = args.passthru or { } // {
|
|
inherit fetcherVersion;
|
|
serve = callPackage ./serve.nix {
|
|
inherit pnpm; # from args
|
|
pnpmDeps = finalAttrs.finalPackage;
|
|
};
|
|
};
|
|
|
|
dontConfigure = true;
|
|
dontBuild = true;
|
|
outputHashMode = "recursive";
|
|
}
|
|
// hash'
|
|
)
|
|
)
|
|
);
|
|
|
|
pnpmConfigHook = makeSetupHook {
|
|
name = "pnpm-config-hook";
|
|
propagatedBuildInputs = [
|
|
sqlite
|
|
writableTmpDirAsHomeHook
|
|
zstd
|
|
];
|
|
substitutions = {
|
|
npmArch = stdenvNoCC.targetPlatform.node.arch;
|
|
npmPlatform = stdenvNoCC.targetPlatform.node.platform;
|
|
};
|
|
meta.license = lib.licenses.mit;
|
|
} ./pnpm-config-hook.sh;
|
|
}
|