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` attribute 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 result = f origArgs;
70
71 # Creates a functor with the same arguments as f
72 copyArgs = g: lib.setFunctionArgs g (lib.functionArgs f);
73 # Changes the original arguments with (potentially a function that returns) a set of new attributes
74 overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
75
76 # Re-call the function but with different arguments
77 overrideArgs = copyArgs (newArgs: makeOverridable f (overrideWith newArgs));
78 # Change the result of the function call by applying g to it
79 overrideResult = g: makeOverridable (copyArgs (args: g (f args))) origArgs;
80 in
81 if builtins.isAttrs result then
82 result // {
83 override = overrideArgs;
84 overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
85 ${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
86 overrideResult (x: x.overrideAttrs fdrv);
87 }
88 else if lib.isFunction result then
89 # Transform the result into a functor while propagating its arguments
90 lib.setFunctionArgs result (lib.functionArgs result) // {
91 override = overrideArgs;
92 }
93 else result;
94
95
96 /* Call the package function in the file `fn' with the required
97 arguments automatically. The function is called with the
98 arguments `args', but any missing arguments are obtained from
99 `autoArgs'. This function is intended to be partially
100 parameterised, e.g.,
101
102 callPackage = callPackageWith pkgs;
103 pkgs = {
104 libfoo = callPackage ./foo.nix { };
105 libbar = callPackage ./bar.nix { };
106 };
107
108 If the `libbar' function expects an argument named `libfoo', it is
109 automatically passed as an argument. Overrides or missing
110 arguments can be supplied in `args', e.g.
111
112 libbar = callPackage ./bar.nix {
113 libfoo = null;
114 enableX11 = true;
115 };
116 */
117 callPackageWith = autoArgs: fn: args:
118 let
119 f = if lib.isFunction fn then fn else import fn;
120 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
121 in makeOverridable f (auto // args);
122
123
124 /* Like callPackage, but for a function that returns an attribute
125 set of derivations. The override function is added to the
126 individual attributes. */
127 callPackagesWith = autoArgs: fn: args:
128 let
129 f = if lib.isFunction fn then fn else import fn;
130 auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
131 origArgs = auto // args;
132 pkgs = f origArgs;
133 mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
134 in
135 if lib.isDerivation pkgs then throw
136 ("function `callPackages` was called on a *single* derivation "
137 + ''"${pkgs.name or "<unknown-name>"}";''
138 + " did you mean to use `callPackage` instead?")
139 else lib.mapAttrs mkAttrOverridable pkgs;
140
141
142 /* Add attributes to each output of a derivation without changing
143 the derivation itself and check a given condition when evaluating. */
144 extendDerivation = condition: passthru: drv:
145 let
146 outputs = drv.outputs or [ "out" ];
147
148 commonAttrs = drv // (builtins.listToAttrs outputsList) //
149 ({ all = map (x: x.value) outputsList; }) // passthru;
150
151 outputToAttrListElement = outputName:
152 { name = outputName;
153 value = commonAttrs // {
154 inherit (drv.${outputName}) type outputName;
155 outputSpecified = true;
156 drvPath = assert condition; drv.${outputName}.drvPath;
157 outPath = assert condition; drv.${outputName}.outPath;
158 };
159 };
160
161 outputsList = map outputToAttrListElement outputs;
162 in commonAttrs // {
163 drvPath = assert condition; drv.drvPath;
164 outPath = assert condition; drv.outPath;
165 };
166
167 /* Strip a derivation of all non-essential attributes, returning
168 only those needed by hydra-eval-jobs. Also strictly evaluate the
169 result to ensure that there are no thunks kept alive to prevent
170 garbage collection. */
171 hydraJob = drv:
172 let
173 outputs = drv.outputs or ["out"];
174
175 commonAttrs =
176 { inherit (drv) name system meta; inherit outputs; }
177 // lib.optionalAttrs (drv._hydraAggregate or false) {
178 _hydraAggregate = true;
179 constituents = map hydraJob (lib.flatten drv.constituents);
180 }
181 // (lib.listToAttrs outputsList);
182
183 makeOutput = outputName:
184 let output = drv.${outputName}; in
185 { name = outputName;
186 value = commonAttrs // {
187 outPath = output.outPath;
188 drvPath = output.drvPath;
189 type = "derivation";
190 inherit outputName;
191 };
192 };
193
194 outputsList = map makeOutput outputs;
195
196 drv' = (lib.head outputsList).value;
197 in lib.deepSeq drv' drv';
198
199 /* Make a set of packages with a common scope. All packages called
200 with the provided `callPackage' will be evaluated with the same
201 arguments. Any package in the set may depend on any other. The
202 `overrideScope'` function allows subsequent modification of the package
203 set in a consistent way, i.e. all packages in the set will be
204 called with the overridden packages. The package sets may be
205 hierarchical: the packages in the set are called with the scope
206 provided by `newScope' and the set provides a `newScope' attribute
207 which can form the parent scope for later package sets. */
208 makeScope = newScope: f:
209 let self = f self // {
210 newScope = scope: newScope (self // scope);
211 callPackage = self.newScope {};
212 overrideScope = g: lib.warn
213 "`overrideScope` (from `lib.makeScope`) is deprecated. Do `overrideScope' (self: super: { … })` instead of `overrideScope (super: self: { … })`. All other overrides have the parameters in that order, including other definitions of `overrideScope`. This was the only definition violating the pattern."
214 (makeScope newScope (lib.fixedPoints.extends (lib.flip g) f));
215 overrideScope' = g: makeScope newScope (lib.fixedPoints.extends g f);
216 packages = f;
217 };
218 in self;
219
220 /* Like the above, but aims to support cross compilation. It's still ugly, but
221 hopefully it helps a little bit. */
222 makeScopeWithSplicing = splicePackages: newScope: otherSplices: keep: extra: f:
223 let
224 spliced0 = splicePackages {
225 pkgsBuildBuild = otherSplices.selfBuildBuild;
226 pkgsBuildHost = otherSplices.selfBuildHost;
227 pkgsBuildTarget = otherSplices.selfBuildTarget;
228 pkgsHostHost = otherSplices.selfHostHost;
229 pkgsHostTarget = self; # Not `otherSplices.selfHostTarget`;
230 pkgsTargetTarget = otherSplices.selfTargetTarget;
231 };
232 spliced = extra spliced0 // spliced0 // keep self;
233 self = f self // {
234 newScope = scope: newScope (spliced // scope);
235 callPackage = newScope spliced; # == self.newScope {};
236 # N.B. the other stages of the package set spliced in are *not*
237 # overridden.
238 overrideScope = g: makeScopeWithSplicing
239 splicePackages
240 newScope
241 otherSplices
242 keep
243 extra
244 (lib.fixedPoints.extends g f);
245 packages = f;
246 };
247 in self;
248
249}