diff options
Diffstat (limited to 'nixpkgs/pkgs/build-support/node/import-npm-lock/hooks')
3 files changed, 135 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/canonicalize-symlinks.js b/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/canonicalize-symlinks.js new file mode 100644 index 000000000000..81cd2593c5b2 --- /dev/null +++ b/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/canonicalize-symlinks.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node +const fs = require("fs"); +const path = require("path"); + +// When installing files rewritten to the Nix store with npm +// npm writes the symlinks relative to the build directory. +// +// This makes relocating node_modules tricky when refering to the store. +// This script walks node_modules and canonicalizes symlinks. + +async function canonicalize(storePrefix, root) { + console.log(storePrefix, root) + const entries = await fs.promises.readdir(root); + const paths = entries.map((entry) => path.join(root, entry)); + + const stats = await Promise.all( + paths.map(async (path) => { + return { + path: path, + stat: await fs.promises.lstat(path), + }; + }) + ); + + const symlinks = stats.filter((stat) => stat.stat.isSymbolicLink()); + const dirs = stats.filter((stat) => stat.stat.isDirectory()); + + // Canonicalize symlinks to their real path + await Promise.all( + symlinks.map(async (stat) => { + const target = await fs.promises.realpath(stat.path); + if (target.startsWith(storePrefix)) { + await fs.promises.unlink(stat.path); + await fs.promises.symlink(target, stat.path); + } + }) + ); + + // Recurse into directories + await Promise.all(dirs.map((dir) => canonicalize(storePrefix, dir.path))); +} + +async function main() { + const args = process.argv.slice(2); + const storePrefix = args[0]; + + if (fs.existsSync("node_modules")) { + await canonicalize(storePrefix, "node_modules"); + } +} + +main(); diff --git a/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/default.nix b/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/default.nix new file mode 100644 index 000000000000..5990371def91 --- /dev/null +++ b/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/default.nix @@ -0,0 +1,13 @@ +{ callPackage, lib, makeSetupHook, srcOnly, nodejs }: +{ + npmConfigHook = makeSetupHook + { + name = "npm-config-hook"; + substitutions = { + nodeSrc = srcOnly nodejs; + nodeGyp = "${nodejs}/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js"; + canonicalizeSymlinksScript = ./canonicalize-symlinks.js; + storePrefix = builtins.storeDir; + }; + } ./npm-config-hook.sh; +} diff --git a/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/npm-config-hook.sh b/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/npm-config-hook.sh new file mode 100644 index 000000000000..35c3a2061d4b --- /dev/null +++ b/nixpkgs/pkgs/build-support/node/import-npm-lock/hooks/npm-config-hook.sh @@ -0,0 +1,70 @@ +# shellcheck shell=bash + +npmConfigHook() { + echo "Executing npmConfigHook" + + if [ -n "${npmRoot-}" ]; then + pushd "$npmRoot" + fi + + if [ -z "${npmDeps-}" ]; then + echo "Error: 'npmDeps' should be set when using npmConfigHook." + exit 1 + fi + + echo "Configuring npm" + + export HOME="$TMPDIR" + export npm_config_nodedir="@nodeSrc@" + export npm_config_node_gyp="@nodeGyp@" + npm config set offline true + npm config set progress false + npm config set fund false + + echo "Installing patched package.json/package-lock.json" + + # Save original package.json/package-lock.json for closure size reductions. + # The patched one contains store paths we don't want at runtime. + mv package.json .package.json.orig + if test -f package-lock.json; then # Not all packages have package-lock.json. + mv package-lock.json .package-lock.json.orig + fi + cp --no-preserve=mode "${npmDeps}/package.json" package.json + cp --no-preserve=mode "${npmDeps}/package-lock.json" package-lock.json + + echo "Installing dependencies" + + if ! npm install --ignore-scripts $npmInstallFlags "${npmInstallFlagsArray[@]}" $npmFlags "${npmFlagsArray[@]}"; then + echo + echo "ERROR: npm failed to install dependencies" + echo + echo "Here are a few things you can try, depending on the error:" + echo '1. Set `npmFlags = [ "--legacy-peer-deps" ]`' + echo + + exit 1 + fi + + patchShebangs node_modules + + npm rebuild $npmRebuildFlags "${npmRebuildFlagsArray[@]}" $npmFlags "${npmFlagsArray[@]}" + + patchShebangs node_modules + + # Canonicalize symlinks from relative paths to the Nix store. + node @canonicalizeSymlinksScript@ @storePrefix@ + + # Revert to pre-patched package.json/package-lock.json for closure size reductions + mv .package.json.orig package.json + if test -f ".package-lock.json.orig"; then + mv .package-lock.json.orig package-lock.json + fi + + if [ -n "${npmRoot-}" ]; then + popd + fi + + echo "Finished npmConfigHook" +} + +postConfigureHooks+=(npmConfigHook) |