1# Operations on attribute sets.
2
3let
4 inherit (builtins) head tail length;
5 inherit (import ./trivial.nix) and or;
6 inherit (import ./default.nix) fold;
7 inherit (import ./strings.nix) concatStringsSep;
8 inherit (import ./lists.nix) concatMap concatLists all deepSeqList;
9in
10
11rec {
12 inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr;
13
14
15 /* Return an attribute from nested attribute sets.
16
17 Example:
18 x = { a = { b = 3; }; }
19 attrByPath ["a" "b"] 6 x
20 => 3
21 attrByPath ["z" "z"] 6 x
22 => 6
23 */
24 attrByPath = attrPath: default: e:
25 let attr = head attrPath;
26 in
27 if attrPath == [] then e
28 else if e ? ${attr}
29 then attrByPath (tail attrPath) default e.${attr}
30 else default;
31
32 /* Return if an attribute from nested attribute set exists.
33
34 Example:
35 x = { a = { b = 3; }; }
36 hasAttrByPath ["a" "b"] x
37 => true
38 hasAttrByPath ["z" "z"] x
39 => false
40
41 */
42 hasAttrByPath = attrPath: e:
43 let attr = head attrPath;
44 in
45 if attrPath == [] then true
46 else if e ? ${attr}
47 then hasAttrByPath (tail attrPath) e.${attr}
48 else false;
49
50
51 /* Return nested attribute set in which an attribute is set.
52
53 Example:
54 setAttrByPath ["a" "b"] 3
55 => { a = { b = 3; }; }
56 */
57 setAttrByPath = attrPath: value:
58 if attrPath == [] then value
59 else listToAttrs
60 [ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
61
62
63 /* Like `getAttrPath' without a default value. If it doesn't find the
64 path it will throw.
65
66 Example:
67 x = { a = { b = 3; }; }
68 getAttrFromPath ["a" "b"] x
69 => 3
70 getAttrFromPath ["z" "z"] x
71 => error: cannot find attribute `z.z'
72 */
73 getAttrFromPath = attrPath: set:
74 let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
75 in attrByPath attrPath (abort errorMsg) set;
76
77
78 /* Return the specified attributes from a set.
79
80 Example:
81 attrVals ["a" "b" "c"] as
82 => [as.a as.b as.c]
83 */
84 attrVals = nameList: set: map (x: set.${x}) nameList;
85
86
87 /* Return the values of all attributes in the given set, sorted by
88 attribute name.
89
90 Example:
91 attrValues {c = 3; a = 1; b = 2;}
92 => [1 2 3]
93 */
94 attrValues = builtins.attrValues or (attrs: attrVals (attrNames attrs) attrs);
95
96
97 /* Collect each attribute named `attr' from a list of attribute
98 sets. Sets that don't contain the named attribute are ignored.
99
100 Example:
101 catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
102 => [1 2]
103 */
104 catAttrs = builtins.catAttrs or
105 (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
106
107
108 /* Filter an attribute set by removing all attributes for which the
109 given predicate return false.
110
111 Example:
112 filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
113 => { foo = 1; }
114 */
115 filterAttrs = pred: set:
116 listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set));
117
118
119 /* Filter an attribute set recursively by removing all attributes for
120 which the given predicate return false.
121
122 Example:
123 filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
124 => { foo = {}; }
125 */
126 filterAttrsRecursive = pred: set:
127 listToAttrs (
128 concatMap (name:
129 let v = set.${name}; in
130 if pred name v then [
131 (nameValuePair name (
132 if isAttrs v then filterAttrsRecursive pred v
133 else v
134 ))
135 ] else []
136 ) (attrNames set)
137 );
138
139 /* Apply fold functions to values grouped by key.
140
141 Example:
142 foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }]
143 => { a = [ 2 3 ]; }
144 */
145 foldAttrs = op: nul: list_of_attrs:
146 fold (n: a:
147 fold (name: o:
148 o // (listToAttrs [{inherit name; value = op n.${name} (a.${name} or nul); }])
149 ) a (attrNames n)
150 ) {} list_of_attrs;
151
152
153 /* Recursively collect sets that verify a given predicate named `pred'
154 from the set `attrs'. The recursion is stopped when the predicate is
155 verified.
156
157 Type:
158 collect ::
159 (AttrSet -> Bool) -> AttrSet -> [x]
160
161 Example:
162 collect isList { a = { b = ["b"]; }; c = [1]; }
163 => [["b"] [1]]
164
165 collect (x: x ? outPath)
166 { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
167 => [{ outPath = "a/"; } { outPath = "b/"; }]
168 */
169 collect = pred: attrs:
170 if pred attrs then
171 [ attrs ]
172 else if isAttrs attrs then
173 concatMap (collect pred) (attrValues attrs)
174 else
175 [];
176
177
178 /* Utility function that creates a {name, value} pair as expected by
179 builtins.listToAttrs.
180
181 Example:
182 nameValuePair "some" 6
183 => { name = "some"; value = 6; }
184 */
185 nameValuePair = name: value: { inherit name value; };
186
187
188 /* Apply a function to each element in an attribute set. The
189 function takes two arguments --- the attribute name and its value
190 --- and returns the new value for the attribute. The result is a
191 new attribute set.
192
193 Example:
194 mapAttrs (name: value: name + "-" + value)
195 { x = "foo"; y = "bar"; }
196 => { x = "x-foo"; y = "y-bar"; }
197 */
198 mapAttrs = f: set:
199 listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set));
200
201
202 /* Like `mapAttrs', but allows the name of each attribute to be
203 changed in addition to the value. The applied function should
204 return both the new name and value as a `nameValuePair'.
205
206 Example:
207 mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
208 { x = "a"; y = "b"; }
209 => { foo_x = "bar-a"; foo_y = "bar-b"; }
210 */
211 mapAttrs' = f: set:
212 listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
213
214
215 /* Call a function for each attribute in the given set and return
216 the result in a list.
217
218 Example:
219 mapAttrsToList (name: value: name + value)
220 { x = "a"; y = "b"; }
221 => [ "xa" "yb" ]
222 */
223 mapAttrsToList = f: attrs:
224 map (name: f name attrs.${name}) (attrNames attrs);
225
226
227 /* Like `mapAttrs', except that it recursively applies itself to
228 attribute sets. Also, the first argument of the argument
229 function is a *list* of the names of the containing attributes.
230
231 Type:
232 mapAttrsRecursive ::
233 ([String] -> a -> b) -> AttrSet -> AttrSet
234
235 Example:
236 mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
237 { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
238 => { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
239 */
240 mapAttrsRecursive = mapAttrsRecursiveCond (as: true);
241
242
243 /* Like `mapAttrsRecursive', but it takes an additional predicate
244 function that tells it whether to recursive into an attribute
245 set. If it returns false, `mapAttrsRecursiveCond' does not
246 recurse, but does apply the map function. It is returns true, it
247 does recurse, and does not apply the map function.
248
249 Type:
250 mapAttrsRecursiveCond ::
251 (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
252
253 Example:
254 # To prevent recursing into derivations (which are attribute
255 # sets with the attribute "type" equal to "derivation"):
256 mapAttrsRecursiveCond
257 (as: !(as ? "type" && as.type == "derivation"))
258 (x: ... do something ...)
259 attrs
260 */
261 mapAttrsRecursiveCond = cond: f: set:
262 let
263 recurse = path: set:
264 let
265 g =
266 name: value:
267 if isAttrs value && cond value
268 then recurse (path ++ [name]) value
269 else f (path ++ [name]) value;
270 in mapAttrs g set;
271 in recurse [] set;
272
273
274 /* Generate an attribute set by mapping a function over a list of
275 attribute names.
276
277 Example:
278 genAttrs [ "foo" "bar" ] (name: "x_" + name)
279 => { foo = "x_foo"; bar = "x_bar"; }
280 */
281 genAttrs = names: f:
282 listToAttrs (map (n: nameValuePair n (f n)) names);
283
284
285 /* Check whether the argument is a derivation. Any set with
286 { type = "derivation"; } counts as a derivation.
287
288 Example:
289 nixpkgs = import <nixpkgs> {}
290 isDerivation nixpkgs.ruby
291 => true
292 isDerivation "foobar"
293 => false
294 */
295 isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
296
297 /* Converts a store path to a fake derivation. */
298 toDerivation = path:
299 let
300 path' = builtins.storePath path;
301 res =
302 { type = "derivation";
303 name = builtins.unsafeDiscardStringContext (builtins.substring 33 (-1) (baseNameOf path'));
304 outPath = path';
305 outputs = [ "out" ];
306 out = res;
307 outputName = "out";
308 };
309 in res;
310
311
312 /* If `cond' is true, return the attribute set `as',
313 otherwise an empty attribute set.
314
315 Example:
316 optionalAttrs (true) { my = "set"; }
317 => { my = "set"; }
318 optionalAttrs (false) { my = "set"; }
319 => { }
320 */
321 optionalAttrs = cond: as: if cond then as else {};
322
323
324 /* Merge sets of attributes and use the function f to merge attributes
325 values.
326
327 Example:
328 zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
329 => { a = ["x" "y"]; }
330 */
331 zipAttrsWithNames = names: f: sets:
332 listToAttrs (map (name: {
333 inherit name;
334 value = f name (catAttrs name sets);
335 }) names);
336
337 /* Implementation note: Common names appear multiple times in the list of
338 names, hopefully this does not affect the system because the maximal
339 laziness avoid computing twice the same expression and listToAttrs does
340 not care about duplicated attribute names.
341
342 Example:
343 zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
344 => { a = ["x" "y"]; b = ["z"] }
345 */
346 zipAttrsWith = f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets;
347 /* Like `zipAttrsWith' with `(name: values: value)' as the function.
348
349 Example:
350 zipAttrs [{a = "x";} {a = "y"; b = "z";}]
351 => { a = ["x" "y"]; b = ["z"] }
352 */
353 zipAttrs = zipAttrsWith (name: values: values);
354
355 /* Does the same as the update operator '//' except that attributes are
356 merged until the given predicate is verified. The predicate should
357 accept 3 arguments which are the path to reach the attribute, a part of
358 the first attribute set and a part of the second attribute set. When
359 the predicate is verified, the value of the first attribute set is
360 replaced by the value of the second attribute set.
361
362 Example:
363 recursiveUpdateUntil (path: l: r: path == ["foo"]) {
364 # first attribute set
365 foo.bar = 1;
366 foo.baz = 2;
367 bar = 3;
368 } {
369 #second attribute set
370 foo.bar = 1;
371 foo.quz = 2;
372 baz = 4;
373 }
374
375 returns: {
376 foo.bar = 1; # 'foo.*' from the second set
377 foo.quz = 2; #
378 bar = 3; # 'bar' from the first set
379 baz = 4; # 'baz' from the second set
380 }
381
382 */
383 recursiveUpdateUntil = pred: lhs: rhs:
384 let f = attrPath:
385 zipAttrsWith (n: values:
386 if tail values == []
387 || pred attrPath (head (tail values)) (head values) then
388 head values
389 else
390 f (attrPath ++ [n]) values
391 );
392 in f [] [rhs lhs];
393
394 /* A recursive variant of the update operator ‘//’. The recursion
395 stops when one of the attribute values is not an attribute set,
396 in which case the right hand side value takes precedence over the
397 left hand side value.
398
399 Example:
400 recursiveUpdate {
401 boot.loader.grub.enable = true;
402 boot.loader.grub.device = "/dev/hda";
403 } {
404 boot.loader.grub.device = "";
405 }
406
407 returns: {
408 boot.loader.grub.enable = true;
409 boot.loader.grub.device = "";
410 }
411
412 */
413 recursiveUpdate = lhs: rhs:
414 recursiveUpdateUntil (path: lhs: rhs:
415 !(isAttrs lhs && isAttrs rhs)
416 ) lhs rhs;
417
418 /* Returns true if the pattern is contained in the set. False otherwise.
419
420 Example:
421 matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
422 => true
423 */
424 matchAttrs = pattern: attrs: assert isAttrs pattern;
425 fold and true (attrValues (zipAttrsWithNames (attrNames pattern) (n: values:
426 let pat = head values; val = head (tail values); in
427 if length values == 1 then false
428 else if isAttrs pat then isAttrs val && matchAttrs pat val
429 else pat == val
430 ) [pattern attrs]));
431
432 /* Override only the attributes that are already present in the old set
433 useful for deep-overriding.
434
435 Example:
436 x = { a = { b = 4; c = 3; }; }
437 overrideExisting x { a = { b = 6; d = 2; }; }
438 => { a = { b = 6; d = 2; }; }
439 */
440 overrideExisting = old: new:
441 old // listToAttrs (map (attr: nameValuePair attr (attrByPath [attr] old.${attr} new)) (attrNames old));
442
443 /* Get a package output.
444 If no output is found, fallback to `.out` and then to the default.
445
446 Example:
447 getOutput "dev" pkgs.openssl
448 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
449 */
450 getOutput = output: pkg:
451 if pkg.outputUnspecified or false
452 then pkg.${output} or pkg.out or pkg
453 else pkg;
454
455 getBin = getOutput "bin";
456 getLib = getOutput "lib";
457 getDev = getOutput "dev";
458
459 /* Pick the outputs of packages to place in buildInputs */
460 chooseDevOutputs = drvs: builtins.map getDev drvs;
461
462 /*** deprecated stuff ***/
463
464 zipWithNames = zipAttrsWithNames;
465 zip = builtins.trace
466 "lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;
467
468}