1{
2 lib,
3 runCommand,
4 writeText,
5}:
6
7{
8 beforeDir,
9 afterDir,
10 evalSystem,
11}:
12
13let
14 # Usually we expect a derivation, but when evaluating in multiple separate steps, we pass
15 # nix store paths around. These need to be turned into (fake) derivations again to track
16 # dependencies properly.
17 # We use two steps for evaluation, because we compare results from two different checkouts.
18 # CI additionalls spreads evaluation across multiple workers.
19 before = if lib.isDerivation beforeDir then beforeDir else lib.toDerivation beforeDir;
20 after = if lib.isDerivation afterDir then afterDir else lib.toDerivation afterDir;
21
22 /*
23 Computes the key difference between two attrs
24
25 {
26 added: [ <keys only in the second object> ],
27 removed: [ <keys only in the first object> ],
28 changed: [ <keys with different values between the two objects> ],
29 rebuilds: [ <keys in the second object with values not present at all in first object> ],
30 }
31 */
32 diff =
33 old: new:
34 let
35 filterKeys = cond: attrs: lib.attrNames (lib.filterAttrs cond attrs);
36 oldOutputs = lib.pipe old [
37 (lib.mapAttrsToList (_: lib.attrValues))
38 lib.concatLists
39 (lib.flip lib.genAttrs (_: true))
40 ];
41 in
42 {
43 added = filterKeys (n: _: !(old ? ${n})) new;
44 removed = filterKeys (n: _: !(new ? ${n})) old;
45 changed = filterKeys (
46 n: v:
47 # Filter out attributes that don't exist anymore
48 (new ? ${n})
49
50 # Filter out attributes that are the same as the new value
51 && (v != (new.${n}))
52 ) old;
53 # A "rebuild" is every attrpath ...
54 rebuilds = filterKeys (
55 _: pkg:
56 # ... that has at least one output ...
57 lib.any (
58 output:
59 # ... which has not been built in "old" already.
60 !(oldOutputs ? ${output})
61 ) (lib.attrValues pkg)
62 ) new;
63 };
64
65 getAttrs =
66 dir:
67 let
68 raw = builtins.readFile "${dir}/${evalSystem}/paths.json";
69 # The file contains Nix paths; we need to ignore them for evaluation purposes,
70 # else there will be a "is not allowed to refer to a store path" error.
71 data = builtins.unsafeDiscardStringContext raw;
72 in
73 builtins.fromJSON data;
74
75 beforeAttrs = getAttrs before;
76 afterAttrs = getAttrs after;
77 diffAttrs = diff beforeAttrs afterAttrs;
78 diffJson = writeText "diff.json" (builtins.toJSON diffAttrs);
79in
80runCommand "diff" { } ''
81 mkdir -p $out/${evalSystem}
82
83 cp -r ${before} $out/before
84 cp -r ${after} $out/after
85 cp ${diffJson} $out/${evalSystem}/diff.json
86''