1{ lib }:
2
3rec {
4
5
6 /* `overrideDerivation drv f' takes a derivation (i.e., the result
7 of a call to the builtin function `derivation') and returns a new
8 derivation in which the attributes of the original are overridden
9 according to the function `f'. The function `f' is called with
10 the original derivation attributes.
11
12 `overrideDerivation' allows certain "ad-hoc" customisation
13 scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance,
14 if you want to "patch" the derivation returned by a package
15 function in Nixpkgs to build another version than what the
16 function itself provides, you can do something like this:
17
18 mySed = overrideDerivation pkgs.gnused (oldAttrs: {
19 name = "sed-4.2.2-pre";
20 src = fetchurl {
21 url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
22 sha256 = "11nq06d131y4wmf3drm0yk502d2xc6n5qy82cg88rb9nqd2lj41k";
23 };
24 patches = [];
25 });
26
27 For another application, see build-support/vm, where this
28 function is used to build arbitrary derivations inside a QEMU
29 virtual machine.
30 */
31 overrideDerivation = drv: f:
32 let
33 newDrv = derivation (drv.drvAttrs // (f drv));
34 in lib.flip (extendDerivation true) newDrv (
35 { meta = drv.meta or {};
36 passthru = if drv ? passthru then drv.passthru else {};
37 }
38 //
39 (drv.passthru or {})
40 //
41 (if (drv ? crossDrv && drv ? nativeDrv)
42 then {
43 crossDrv = overrideDerivation drv.crossDrv f;
44 nativeDrv = overrideDerivation drv.nativeDrv f;
45 }
46 else { }));
47
48
49 /* `makeOverridable` takes a function from attribute set to attribute set and
50 injects `override` attibute which can be used to override arguments of
51 the function.
52
53 nix-repl> x = {a, b}: { result = a + b; }
54
55 nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
56
57 nix-repl> y
58 { override = «lambda»; overrideDerivation = «lambda»; result = 3; }
59
60 nix-repl> y.override { a = 10; }
61 { override = «lambda»; overrideDerivation = «lambda»; result = 12; }
62
63 Please refer to "Nixpkgs Contributors Guide" section
64 "<pkg>.overrideDerivation" to learn about `overrideDerivation` and caveats
65 related to its use.
66 */
67 makeOverridable = f: origArgs:
68 let
69 ff = f origArgs;
70 overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
71 in
72 if builtins.isAttrs ff then (ff // {
73 override = newArgs: makeOverridable f (overrideWith newArgs);
74 overrideDerivation = fdrv:
75 makeOverridable (args: overrideDerivation (f args) fdrv) origArgs;
76 ${if ff ? overrideAttrs then "overrideAttrs" else null} = fdrv:
77 makeOverridable (args: (f args).overrideAttrs fdrv) origArgs;
78 })
79 else if lib.isFunction ff then {
80 override = newArgs: makeOverridable f (overrideWith newArgs);
81 __functor = self: ff;
82 overrideDerivation = throw "overrideDerivation not yet supported for functors";
83 }
84 else ff;
85
86
87 /* Call the package function in the file `fn' with the required
88 arguments automatically. The function is called with the
89 arguments `args', but any missing arguments are obtained from
90 `autoArgs'. This function is intended to be partially
91 parameterised, e.g.,
92
93 callPackage = callPackageWith pkgs;
94 pkgs = {
95 libfoo = callPackage ./foo.nix { };
96 libbar = callPackage ./bar.nix { };
97 };
98
99 If the `libbar' function expects an argument named `libfoo', it is
100 automatically passed as an argument. Overrides or missing
101 arguments can be supplied in `args', e.g.
102
103 libbar = callPackage ./bar.nix {
104 libfoo = null;
105 enableX11 = true;
106 };
107 */
108 callPackageWith = autoArgs: fn: args:
109 let
110 f = if lib.isFunction fn then fn else import fn;
111 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
112 in makeOverridable f (auto // args);
113
114
115 /* Like callPackage, but for a function that returns an attribute
116 set of derivations. The override function is added to the
117 individual attributes. */
118 callPackagesWith = autoArgs: fn: args:
119 let
120 f = if lib.isFunction fn then fn else import fn;
121 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
122 origArgs = auto // args;
123 pkgs = f origArgs;
124 mkAttrOverridable = name: pkg: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
125 in lib.mapAttrs mkAttrOverridable pkgs;
126
127
128 /* Add attributes to each output of a derivation without changing
129 the derivation itself and check a given condition when evaluating. */
130 extendDerivation = condition: passthru: drv:
131 let
132 outputs = drv.outputs or [ "out" ];
133
134 commonAttrs = drv // (builtins.listToAttrs outputsList) //
135 ({ all = map (x: x.value) outputsList; }) // passthru;
136
137 outputToAttrListElement = outputName:
138 { name = outputName;
139 value = commonAttrs // {
140 inherit (drv.${outputName}) type outputName;
141 drvPath = assert condition; drv.${outputName}.drvPath;
142 outPath = assert condition; drv.${outputName}.outPath;
143 };
144 };
145
146 outputsList = map outputToAttrListElement outputs;
147 in commonAttrs // {
148 outputUnspecified = true;
149 drvPath = assert condition; drv.drvPath;
150 outPath = assert condition; drv.outPath;
151 };
152
153 /* Strip a derivation of all non-essential attributes, returning
154 only those needed by hydra-eval-jobs. Also strictly evaluate the
155 result to ensure that there are no thunks kept alive to prevent
156 garbage collection. */
157 hydraJob = drv:
158 let
159 outputs = drv.outputs or ["out"];
160
161 commonAttrs =
162 { inherit (drv) name system meta; inherit outputs; }
163 // lib.optionalAttrs (drv._hydraAggregate or false) {
164 _hydraAggregate = true;
165 constituents = map hydraJob (lib.flatten drv.constituents);
166 }
167 // (lib.listToAttrs outputsList);
168
169 makeOutput = outputName:
170 let output = drv.${outputName}; in
171 { name = outputName;
172 value = commonAttrs // {
173 outPath = output.outPath;
174 drvPath = output.drvPath;
175 type = "derivation";
176 inherit outputName;
177 };
178 };
179
180 outputsList = map makeOutput outputs;
181
182 drv' = (lib.head outputsList).value;
183 in lib.deepSeq drv' drv';
184
185 /* Make a set of packages with a common scope. All packages called
186 with the provided `callPackage' will be evaluated with the same
187 arguments. Any package in the set may depend on any other. The
188 `overrideScope' function allows subsequent modification of the package
189 set in a consistent way, i.e. all packages in the set will be
190 called with the overridden packages. The package sets may be
191 hierarchical: the packages in the set are called with the scope
192 provided by `newScope' and the set provides a `newScope' attribute
193 which can form the parent scope for later package sets. */
194 makeScope = newScope: f:
195 let self = f self // {
196 newScope = scope: newScope (self // scope);
197 callPackage = self.newScope {};
198 # TODO(@Ericson2314): Haromonize argument order of `g` with everything else
199 overrideScope = g:
200 makeScope newScope
201 (lib.fixedPoints.extends (lib.flip g) f);
202 packages = f;
203 };
204 in self;
205
206}