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