nixpkgs/pkgs/build-support/build-incremental.nix
2023-12-07 16:55:39 +01:00

67 lines
2.9 KiB
Nix

{ pkgs }:
rec {
/* Prepare a derivation for local builds.
*
* This function prepares incremental builds by provinding,
* containing the build output and the sources for cross checking.
* The build output can be used later to allow incremental builds
* by passing the derivation output to the `mkIncrementalBuild` function.
*
* To build a project incrementaly follow these steps:
* - run prepareIncrementalBuild on the desired derivation
* e.G `incrementalBuildArtifacts = (pkgs.buildIncremental.prepareIncrementalBuild pkgs.virtualbox);`
* - change something you want in the sources of the package( e.G using source override)
* changedVBox = pkgs.virtuabox.overrideAttrs (old: {
* src = path/to/vbox/sources;
* }
* - use `mkIncrementalBuild changedVBox buildOutput`
* - enjoy shorter build times
*/
prepareIncrementalBuild = drv: drv.overrideAttrs (old: {
outputs = [ "out" ];
name = drv.name + "-incrementalBuildArtifacts";
# To determine differences between the state of the build directory
# from an earlier build and a later one we store the state of the build
# directory before build, but after patch phases.
# This way, the same derivation can be used multiple times and only changes are detected.
# Additionally Removed files are handled correctly in later builds.
preBuild = (old.preBuild or "") + ''
mkdir -p $out/sources
cp -r ./* $out/sources/
'';
# After the build the build directory is copied again
# to get the output files.
# We copy the complete build folder, to take care for
# Build tools, building in the source directory, instead of
# having a build root directory, e.G the Linux kernel.
installPhase = ''
mkdir -p $out/outputs
cp -r ./* $out/outputs/
'';
});
/* Build a derivation incrementally based on the output generated by
* the `prepareIncrementalBuild function.
*
* Usage:
* let
* incrementalBuildArtifacts = prepareIncrementalBuild drv
* in mkIncrementalBuild drv incrementalBuildArtifacts
*/
mkIncrementalBuild = drv: previousBuildArtifacts: drv.overrideAttrs (old: {
# The actual incremental build phase.
# We compare the changed sources from a previous build with the current and create a patch
# Afterwards we clean the build directory to copy the previous output files (Including the sources)
# The source difference patch is applied to get the latest changes again to allow short build times.
preBuild = (old.preBuild or "") + ''
set +e
diff -ur ${previousBuildArtifacts}/sources ./ > sourceDifference.patch
set -e
shopt -s extglob dotglob
rm -r !("sourceDifference.patch")
${pkgs.rsync}/bin/rsync -cutU --chown=$USER:$USER --chmod=+w -r ${previousBuildArtifacts}/outputs/* .
patch -p 1 -i sourceDifference.patch
'';
});
}