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