1{ 2 lib, 3 buildPackages, 4 config, 5}: 6 7let 8 # rudimentary support for cross-compiling 9 # see: https://github.com/NixOS/nixpkgs/pull/279487#discussion_r1444449726 10 inherit (buildPackages) 11 mktemp 12 rsync 13 ; 14 15 /* 16 Build a derivation based on the checkpoint output generated by 17 * the `prepareCheckpointBuild` function. 18 * 19 * Usage: 20 * let 21 * checkpointArtifacts = prepareCheckpointBuild drv; 22 * in mkCheckpointBuild drv checkpointArtifacts 23 */ 24 mkCheckpointBuild = 25 drv: checkpointArtifacts: 26 drv.overrideAttrs (old: { 27 # The actual checkpoint build phase. 28 # We compare the changed sources from a previous build with the current and create a patch. 29 # Afterwards we clean the build directory and copy the previous output files (including the sources). 30 # The source difference patch is then applied to get the latest changes again to allow short build times. 31 preBuild = (old.preBuild or "") + '' 32 set +e 33 sourceDifferencePatchFile=$(${mktemp}/bin/mktemp) 34 diff -ur ${checkpointArtifacts}/sources ./ > "$sourceDifferencePatchFile" 35 set -e 36 shopt -s dotglob 37 rm -r * 38 ${rsync}/bin/rsync \ 39 --checksum --times --atimes --chown=$USER:$USER --chmod=+w \ 40 -r ${checkpointArtifacts}/outputs/ . 41 patch -p 1 -i "$sourceDifferencePatchFile" 42 rm "$sourceDifferencePatchFile" 43 ''; 44 }); 45in 46 47rec { 48 inherit mkCheckpointBuild; 49 /* 50 Prepare a derivation for local builds. 51 * 52 * This function prepares checkpoint builds by storing 53 * the build output and the sources for cross checking. 54 * The build output can be used later to allow checkpoint builds 55 * by passing the derivation output to the `mkCheckpointBuild` function. 56 * 57 * To build a project with checkpoints, follow these steps: 58 * - run `prepareCheckpointBuild` on the desired derivation, e.g. 59 * checkpointArtifacts = prepareCheckpointBuild virtualbox; 60 * - change something you want in the sources of the package, 61 * e.g. using source override: 62 * changedVBox = pkgs.virtuabox.overrideAttrs (old: { 63 * src = path/to/vbox/sources; 64 * }; 65 * - use `mkCheckpointBuild changedVBox checkpointArtifacts` 66 * - enjoy shorter build times 67 */ 68 prepareCheckpointBuild = 69 drv: 70 drv.overrideAttrs (old: { 71 outputs = [ "out" ]; 72 name = drv.name + "-checkpointArtifacts"; 73 # To determine differences between the state of the build directory 74 # from an earlier build and a later one we store the state of the build 75 # directory before build, but after patch phases. 76 # This way, the same derivation can be used multiple times and only changes are detected. 77 # Additionally, removed files are handled correctly in later builds. 78 preBuild = (old.preBuild or "") + '' 79 mkdir -p $out/sources 80 cp -r ./* $out/sources/ 81 ''; 82 83 # After the build, the build directory is copied again 84 # to get the output files. 85 # We copy the complete build folder, to take care of 86 # build tools that build in the source directory, instead of 87 # having a separate build directory such as the Linux kernel. 88 installPhase = '' 89 runHook preCheckpointInstall 90 mkdir -p $out/outputs 91 cp -r ./* $out/outputs/ 92 runHook postCheckpointInstall 93 unset postPhases 94 ''; 95 96 dontFixup = true; 97 doInstallCheck = false; 98 doDist = false; 99 }); 100} 101// lib.optionalAttrs config.allowAliases { 102 mkCheckpointedBuild = lib.warn "`mkCheckpointedBuild` is deprecated, use `mkCheckpointBuild` instead!" mkCheckpointBuild; 103}