Isolated builds of dependencies

This commit is contained in:
Stéphan Kochen
2021-04-30 11:39:05 +02:00
parent 0f378786d6
commit 153254f62a
14 changed files with 578 additions and 133 deletions
+1 -1
View File
@@ -3,4 +3,4 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.callPackage ./yarn-project.nix { } ./.
pkgs.callPackage ./yarn-project.nix { } { src = ./.; }
+108 -66
View File
@@ -1,103 +1,145 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
{ lib, coreutils, nodejs, stdenv, writeText }: src:
{ lib, nodejs, stdenv, fetchurl, writeText }:
{ src, overrideAttrs ? null, ... } @ args:
let
yarnPath = @@YARN_PATH@@;
yarnPath = ./@@YARN_PATH@@;
lockfile = ./@@LOCKFILE@@;
cacheFolder = @@CACHE_FOLDER@@;
cacheEntries = @@CACHE_ENTRIES@@;
# Fetch a single dependency.
fetchOne = let
# Call overrideAttrs on a derivation if a function is provided.
optionalOverride = fn: drv:
if fn == null then drv else drv.overrideAttrs fn;
# Common attributes between Yarn derivations.
drvCommon = {
# Make sure the build uses the right Node.js version everywhere.
buildInputs = [ nodejs ];
# Tell node-gyp to use the provided Node.js headers for native code builds.
npm_config_nodedir = nodejs;
# Tell node-pre-gyp to never fetch binaries / always build from source.
npm_config_build_from_source = "true";
# Defines the shell alias to run Yarn.
postHook = ''
yarn() {
CI=1 node "${yarnPath}" "$@"
}
'';
};
# Create derivations for fetching dependencies.
cacheDrvs = let
builder = builtins.toFile "builder.sh" ''
source $stdenv/setup
cd "$src"
HOME="$TMP" yarn_cache_folder="$TMP" CI=1 \
node '${yarnPath}' nixify fetch-one $locatorHash
node '${yarnPath}' nixify fetch-one $locator
mv "$TMP/$outputFilename" $out
'';
in { name, filename, sha512, locatorHash }: stdenv.mkDerivation {
inherit name src builder locatorHash;
in lib.mapAttrs (locator: { filename, sha512 }: stdenv.mkDerivation {
inherit src builder locator;
name = lib.strings.sanitizeDerivationName locator;
buildInputs = [ nodejs ];
outputFilename = filename;
outputHashMode = "flat";
outputHashAlgo = "sha512";
outputHash = sha512;
};
}) cacheEntries;
# Shell snippet to collect all project dependencies.
collectCacheScript = writeText "collect-cache.sh" (
lib.concatMapStrings (args: ''
cp ${fetchOne args} '${args.filename}'
'') cacheEntries
);
# Create a shell snippet to copy dependencies from a list of derivations.
mkCacheBuilderForDrvs = drvs:
writeText "collect-cache.sh" (lib.concatMapStrings (drv: ''
cp ${drv} '${drv.outputFilename}'
'') drvs);
in stdenv.mkDerivation {
name = @@PROJECT_NAME@@;
inherit src;
#@@ IF NEED_ISOLATED_BUILD_SUPPRORT
# Create a shell snippet to copy dependencies from a list of locators.
mkCacheBuilderForLocators = let
pickCacheDrvs = map (locator: cacheDrvs.${locator});
in locators:
mkCacheBuilderForDrvs (pickCacheDrvs locators);
# Disable Nixify plugin to save on some unnecessary processing.
yarn_enable_nixify = "false";
# Tell node-gyp to use the provided Node.js headers for native code builds.
npm_config_nodedir = nodejs;
# Tell node-pre-gyp to never fetch binaries / always build from source.
npm_config_build_from_source = "true";
# Create a derivation that builds a node-pre-gyp module in isolation.
mkIsolatedBuild = { pname, version, locators }: stdenv.mkDerivation (drvCommon // {
inherit pname version;
phases = [ "buildPhase" "installPhase" ];
# Make sure the build uses the right Node.js version everywhere.
buildInputs = [ nodejs ];
buildPhase = ''
mkdir -p .yarn/cache
pushd .yarn/cache > /dev/null
source ${mkCacheBuilderForLocators locators}
popd > /dev/null
# Defines the shell alias to run Yarn.
postHook = ''
yarn() {
CI=1 node "$NIX_YARN_PATH" "$@"
}
'';
echo '{ "dependencies": { "${pname}": "${version}" } }' > package.json
install -m 0600 ${lockfile} ./yarn.lock
yarn --immutable-cache
'';
configurePhase = ''
runHook preConfigure
installPhase = ''
unplugged=( .yarn/unplugged/${pname}-*/node_modules/* )
if [[ ! -e "''${unplugged[@]}" ]]; then
echo >&2 "Could not find the unplugged path for ${pname}"
exit 1
fi
# Copy over the Yarn cache.
rm -fr '${cacheFolder}'
mkdir -p '${cacheFolder}'
pushd '${cacheFolder}' > /dev/null
source ${collectCacheScript}
popd > /dev/null
mv "$unplugged" $out
'';
});
#@@ ENDIF NEED_ISOLATED_BUILD_SUPPRORT
# Store the absolute path to Yarn for the 'yarn' alias.
export NIX_YARN_PATH="$(readlink -f '${yarnPath}')"
# Main project derivation.
project = stdenv.mkDerivation (drvCommon // {
inherit src;
name = @@PROJECT_NAME@@;
# Disable Nixify plugin to save on some unnecessary processing.
yarn_enable_nixify = "false";
# Run normal Yarn install to complete dependency installation.
yarn install --immutable --immutable-cache
configurePhase = ''
runHook preConfigure
runHook postConfigure
'';
# Copy over the Yarn cache.
rm -fr '${cacheFolder}'
mkdir -p '${cacheFolder}'
pushd '${cacheFolder}' > /dev/null
source ${mkCacheBuilderForDrvs (lib.attrValues cacheDrvs)}
popd > /dev/null
buildPhase = ''
runHook preBuild
runHook postBuild
'';
@@ISOLATED_INTEGRATION@@
installPhase = ''
runHook preInstall
# Run normal Yarn install to complete dependency installation.
yarn install --immutable --immutable-cache
mkdir -p $out/libexec $out/bin
runHook postConfigure
'';
# Move the entire project to the output directory.
mv $PWD "$out/libexec/$sourceRoot"
cd "$out/libexec/$sourceRoot"
buildPhase = ''
runHook preBuild
runHook postBuild
'';
# Update the path to Yarn.
export NIX_YARN_PATH="$(readlink -f '${yarnPath}')"
installPhase = ''
runHook preInstall
# Invoke a plugin internal command to setup binaries.
yarn nixify install-bin $out/bin
mkdir -p $out/libexec $out/bin
runHook postInstall
'';
# Move the entire project to the output directory.
mv $PWD "$out/libexec/$sourceRoot"
cd "$out/libexec/$sourceRoot"
passthru = {
inherit nodejs;
};
}
# Invoke a plugin internal command to setup binaries.
yarn nixify install-bin $out/bin
runHook postInstall
'';
passthru = {
inherit nodejs;
};
});
@@CACHE_ENTRIES@@
@@ISOLATED@@
in optionalOverride overrideAttrs project