nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1/**
2 Operations on attribute sets.
3*/
4{ lib }:
5
6let
7 inherit (builtins) head length typeOf;
8 inherit (lib.asserts) assertMsg;
9 inherit (lib.trivial) oldestSupportedReleaseIsAtLeast mergeAttrs;
10 inherit (lib.strings)
11 concatStringsSep
12 concatMapStringsSep
13 escapeNixIdentifier
14 sanitizeDerivationName
15 ;
16 inherit (lib.lists)
17 filter
18 foldr
19 foldl'
20 concatMap
21 elemAt
22 all
23 partition
24 groupBy
25 take
26 foldl
27 ;
28in
29
30rec {
31 inherit (builtins)
32 attrNames
33 listToAttrs
34 hasAttr
35 isAttrs
36 getAttr
37 removeAttrs
38 intersectAttrs
39 ;
40
41 /**
42 Returns an attribute from nested attribute sets.
43
44 Nix has an [attribute selection operator `.`](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example:
45
46 ```nix
47 (x.a.b or 6) == attrByPath ["a" "b"] 6 x
48 # and
49 (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x
50 ```
51
52 # Inputs
53
54 `attrPath`
55
56 : A list of strings representing the attribute path to return from `set`
57
58 `default`
59
60 : Default value if `attrPath` does not resolve to an existing value
61
62 `set`
63
64 : The nested attribute set to select values from
65
66 # Type
67
68 ```
69 attrByPath :: [String] -> Any -> AttrSet -> Any
70 ```
71
72 # Examples
73 :::{.example}
74 ## `lib.attrsets.attrByPath` usage example
75
76 ```nix
77 x = { a = { b = 3; }; }
78 # ["a" "b"] is equivalent to x.a.b
79 # 6 is a default value to return if the path does not exist in attrset
80 attrByPath ["a" "b"] 6 x
81 => 3
82 attrByPath ["z" "z"] 6 x
83 => 6
84 ```
85
86 :::
87 */
88 attrByPath =
89 attrPath: default: set:
90 let
91 lenAttrPath = length attrPath;
92 attrByPath' =
93 n: s:
94 (
95 if n == lenAttrPath then
96 s
97 else
98 (
99 let
100 attr = elemAt attrPath n;
101 in
102 if s ? ${attr} then attrByPath' (n + 1) s.${attr} else default
103 )
104 );
105 in
106 attrByPath' 0 set;
107
108 /**
109 Returns if an attribute from nested attribute set exists.
110
111 Nix has a [has attribute operator `?`](https://nixos.org/manual/nix/stable/language/operators#has-attribute), which is sufficient for such queries, as long as the number of attributes is static. For example:
112
113 ```nix
114 (x?a.b) == hasAttrByPath ["a" "b"] x
115 # and
116 (x?${f p}."example.com") == hasAttrByPath [ (f p) "example.com" ] x
117 ```
118
119 **Laws**:
120 1. ```nix
121 hasAttrByPath [] x == true
122 ```
123
124 # Inputs
125
126 `attrPath`
127
128 : A list of strings representing the attribute path to check from `set`
129
130 `set`
131
132 : The nested attribute set to check
133
134 # Type
135
136 ```
137 hasAttrByPath :: [String] -> AttrSet -> Bool
138 ```
139
140 # Examples
141 :::{.example}
142 ## `lib.attrsets.hasAttrByPath` usage example
143
144 ```nix
145 x = { a = { b = 3; }; }
146 hasAttrByPath ["a" "b"] x
147 => true
148 hasAttrByPath ["z" "z"] x
149 => false
150 hasAttrByPath [] (throw "no need")
151 => true
152 ```
153
154 :::
155 */
156 hasAttrByPath =
157 attrPath: e:
158 let
159 lenAttrPath = length attrPath;
160 hasAttrByPath' =
161 n: s:
162 (
163 n == lenAttrPath
164 || (
165 let
166 attr = elemAt attrPath n;
167 in
168 if s ? ${attr} then hasAttrByPath' (n + 1) s.${attr} else false
169 )
170 );
171 in
172 hasAttrByPath' 0 e;
173
174 /**
175 Returns the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets.
176
177 Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition,
178 although this will evaluate the predicate function on sibling attributes as well.
179
180 Note that the empty attribute path is valid for all values, so this function only throws an exception if any of its inputs does.
181
182 **Laws**:
183 1. ```nix
184 attrsets.longestValidPathPrefix [] x == []
185 ```
186
187 2. ```nix
188 hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true
189 ```
190
191 # Inputs
192
193 `attrPath`
194
195 : A list of strings representing the longest possible path that may be returned.
196
197 `v`
198
199 : The nested attribute set to check.
200
201 # Type
202
203 ```
204 attrsets.longestValidPathPrefix :: [String] -> Value -> [String]
205 ```
206
207 # Examples
208 :::{.example}
209 ## `lib.attrsets.longestValidPathPrefix` usage example
210
211 ```nix
212 x = { a = { b = 3; }; }
213 attrsets.longestValidPathPrefix ["a" "b" "c"] x
214 => ["a" "b"]
215 attrsets.longestValidPathPrefix ["a"] x
216 => ["a"]
217 attrsets.longestValidPathPrefix ["z" "z"] x
218 => []
219 attrsets.longestValidPathPrefix ["z" "z"] (throw "no need")
220 => []
221 ```
222
223 :::
224 */
225 longestValidPathPrefix =
226 attrPath: v:
227 let
228 lenAttrPath = length attrPath;
229 getPrefixForSetAtIndex =
230 # The nested attribute set to check, if it is an attribute set, which
231 # is not a given.
232 remainingSet:
233 # The index of the attribute we're about to check, as well as
234 # the length of the prefix we've already checked.
235 remainingPathIndex:
236
237 if remainingPathIndex == lenAttrPath then
238 # All previously checked attributes exist, and no attr names left,
239 # so we return the whole path.
240 attrPath
241 else
242 let
243 attr = elemAt attrPath remainingPathIndex;
244 in
245 if remainingSet ? ${attr} then
246 getPrefixForSetAtIndex remainingSet.${attr} # advance from the set to the attribute value
247 (remainingPathIndex + 1) # advance the path
248 else
249 # The attribute doesn't exist, so we return the prefix up to the
250 # previously checked length.
251 take remainingPathIndex attrPath;
252 in
253 getPrefixForSetAtIndex v 0;
254
255 /**
256 Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
257
258 # Inputs
259
260 `attrPath`
261
262 : A list of strings representing the attribute path to set
263
264 `value`
265
266 : The value to set at the location described by `attrPath`
267
268 # Type
269
270 ```
271 setAttrByPath :: [String] -> Any -> AttrSet
272 ```
273
274 # Examples
275 :::{.example}
276 ## `lib.attrsets.setAttrByPath` usage example
277
278 ```nix
279 setAttrByPath ["a" "b"] 3
280 => { a = { b = 3; }; }
281 ```
282
283 :::
284 */
285 setAttrByPath =
286 attrPath: value:
287 let
288 len = length attrPath;
289 atDepth = n: if n == len then value else { ${elemAt attrPath n} = atDepth (n + 1); };
290 in
291 atDepth 0;
292
293 /**
294 Like `attrByPath`, but without a default value. If it doesn't find the
295 path it will throw an error.
296
297 Nix has an [attribute selection operator](https://nixos.org/manual/nix/stable/language/operators#attribute-selection) which is sufficient for such queries, as long as the number of attributes is static. For example:
298
299 ```nix
300 x.a.b == getAttrFromPath ["a" "b"] x
301 # and
302 x.${f p}."example.com" == getAttrFromPath [ (f p) "example.com" ] x
303 ```
304
305 # Inputs
306
307 `attrPath`
308
309 : A list of strings representing the attribute path to get from `set`
310
311 `set`
312
313 : The nested attribute set to find the value in.
314
315 # Type
316
317 ```
318 getAttrFromPath :: [String] -> AttrSet -> Any
319 ```
320
321 # Examples
322 :::{.example}
323 ## `lib.attrsets.getAttrFromPath` usage example
324
325 ```nix
326 x = { a = { b = 3; }; }
327 getAttrFromPath ["a" "b"] x
328 => 3
329 getAttrFromPath ["z" "z"] x
330 => error: cannot find attribute `z.z'
331 ```
332
333 :::
334 */
335 getAttrFromPath =
336 attrPath: set:
337 attrByPath attrPath (abort ("cannot find attribute '" + concatStringsSep "." attrPath + "'")) set;
338
339 /**
340 Map each attribute in the given set and merge them into a new attribute set.
341
342 # Inputs
343
344 `f`
345
346 : 1\. Function argument
347
348 `v`
349
350 : 2\. Function argument
351
352 # Type
353
354 ```
355 concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet
356 ```
357
358 # Examples
359 :::{.example}
360 ## `lib.attrsets.concatMapAttrs` usage example
361
362 ```nix
363 concatMapAttrs
364 (name: value: {
365 ${name} = value;
366 ${name + value} = value;
367 })
368 { x = "a"; y = "b"; }
369 => { x = "a"; xa = "a"; y = "b"; yb = "b"; }
370 ```
371
372 :::
373 */
374 concatMapAttrs = f: v: foldl' mergeAttrs { } (attrValues (mapAttrs f v));
375
376 /**
377 Update or set specific paths of an attribute set.
378
379 Takes a list of updates to apply and an attribute set to apply them to,
380 and returns the attribute set with the updates applied. Updates are
381 represented as `{ path = ...; update = ...; }` values, where `path` is a
382 list of strings representing the attribute path that should be updated,
383 and `update` is a function that takes the old value at that attribute path
384 as an argument and returns the new
385 value it should be.
386
387 Properties:
388
389 - Updates to deeper attribute paths are applied before updates to more
390 shallow attribute paths
391
392 - Multiple updates to the same attribute path are applied in the order
393 they appear in the update list
394
395 - If any but the last `path` element leads into a value that is not an
396 attribute set, an error is thrown
397
398 - If there is an update for an attribute path that doesn't exist,
399 accessing the argument in the update function causes an error, but
400 intermediate attribute sets are implicitly created as needed
401
402 # Type
403
404 ```
405 updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet
406 ```
407
408 # Examples
409 :::{.example}
410 ## `lib.attrsets.updateManyAttrsByPath` usage example
411
412 ```nix
413 updateManyAttrsByPath [
414 {
415 path = [ "a" "b" ];
416 update = old: { d = old.c; };
417 }
418 {
419 path = [ "a" "b" "c" ];
420 update = old: old + 1;
421 }
422 {
423 path = [ "x" "y" ];
424 update = old: "xy";
425 }
426 ] { a.b.c = 0; }
427 => { a = { b = { d = 1; }; }; x = { y = "xy"; }; }
428 ```
429
430 :::
431 */
432 updateManyAttrsByPath =
433 let
434 # When recursing into attributes, instead of updating the `path` of each
435 # update using `tail`, which needs to allocate an entirely new list,
436 # we just pass a prefix length to use and make sure to only look at the
437 # path without the prefix length, so that we can reuse the original list
438 # entries.
439 go =
440 prefixLength: hasValue: value: updates:
441 let
442 # Splits updates into ones on this level (split.right)
443 # And ones on levels further down (split.wrong)
444 split = partition (el: length el.path == prefixLength) updates;
445
446 # Groups updates on further down levels into the attributes they modify
447 nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
448
449 # Applies only nested modification to the input value
450 withNestedMods =
451 # Return the value directly if we don't have any nested modifications
452 if split.wrong == [ ] then
453 if hasValue then
454 value
455 else
456 # Throw an error if there is no value. This `head` call here is
457 # safe, but only in this branch since `go` could only be called
458 # with `hasValue == false` for nested updates, in which case
459 # it's also always called with at least one update
460 let
461 updatePath = (head split.right).path;
462 in
463 throw (
464 "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
465 + "not exist in the given value, but the first update to this "
466 + "path tries to access the existing value."
467 )
468 else
469 # If there are nested modifications, try to apply them to the value
470 if !hasValue then
471 # But if we don't have a value, just use an empty attribute set
472 # as the value, but simplify the code a bit
473 mapAttrs (name: go (prefixLength + 1) false null) nested
474 else if isAttrs value then
475 # If we do have a value and it's an attribute set, override it
476 # with the nested modifications
477 value // mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
478 else
479 # However if it's not an attribute set, we can't apply the nested
480 # modifications, throw an error
481 let
482 updatePath = (head split.wrong).path;
483 in
484 throw (
485 "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
486 + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
487 + "of the given value is not an attribute set, so we can't "
488 + "update an attribute inside of it."
489 );
490
491 # We get the final result by applying all the updates on this level
492 # after having applied all the nested updates
493 # We use foldl instead of foldl' so that in case of multiple updates,
494 # intermediate values aren't evaluated if not needed
495 in
496 foldl (acc: el: el.update acc) withNestedMods split.right;
497
498 in
499 updates: value: go 0 true value updates;
500
501 /**
502 Returns the specified attributes from a set.
503
504 # Inputs
505
506 `nameList`
507
508 : The list of attributes to fetch from `set`. Each attribute name must exist on the attribute set
509
510 `set`
511
512 : The set to get attribute values from
513
514 # Type
515
516 ```
517 attrVals :: [String] -> AttrSet -> [Any]
518 ```
519
520 # Examples
521 :::{.example}
522 ## `lib.attrsets.attrVals` usage example
523
524 ```nix
525 attrVals ["a" "b" "c"] as
526 => [as.a as.b as.c]
527 ```
528
529 :::
530 */
531 attrVals = nameList: set: map (x: set.${x}) nameList;
532
533 /**
534 Returns the values of all attributes in the given set, sorted by
535 attribute name.
536
537 # Type
538
539 ```
540 attrValues :: AttrSet -> [Any]
541 ```
542
543 # Examples
544 :::{.example}
545 ## `lib.attrsets.attrValues` usage example
546
547 ```nix
548 attrValues {c = 3; a = 1; b = 2;}
549 => [1 2 3]
550 ```
551
552 :::
553 */
554 attrValues = builtins.attrValues;
555
556 /**
557 Given a set of attribute names, return the set of the corresponding
558 attributes from the given set.
559
560 # Inputs
561
562 `names`
563
564 : A list of attribute names to get out of `set`
565
566 `set`
567
568 : The set to get the named attributes from
569
570 # Type
571
572 ```
573 getAttrs :: [String] -> AttrSet -> AttrSet
574 ```
575
576 # Examples
577 :::{.example}
578 ## `lib.attrsets.getAttrs` usage example
579
580 ```nix
581 getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }
582 => { a = 1; b = 2; }
583 ```
584
585 :::
586 */
587 getAttrs = names: attrs: genAttrs names (name: attrs.${name});
588
589 /**
590 Collect each attribute named `attr` from a list of attribute
591 sets. Sets that don't contain the named attribute are ignored.
592
593 # Inputs
594
595 `attr`
596
597 : The attribute name to get out of the sets.
598
599 `list`
600
601 : The list of attribute sets to go through
602
603 # Type
604
605 ```
606 catAttrs :: String -> [AttrSet] -> [Any]
607 ```
608
609 # Examples
610 :::{.example}
611 ## `lib.attrsets.catAttrs` usage example
612
613 ```nix
614 catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
615 => [1 2]
616 ```
617
618 :::
619 */
620 catAttrs = builtins.catAttrs;
621
622 /**
623 Filter an attribute set by removing all attributes for which the
624 given predicate return false.
625
626 # Inputs
627
628 `pred`
629
630 : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
631
632 <!-- TIP -->
633 If possible, decide on `name` first and on `value` only if necessary.
634 This avoids evaluating the value if the name is already enough, making it possible, potentially, to have the argument reference the return value.
635 (Depending on context, that could still be considered a self reference by users; a common pattern in Nix.)
636
637 <!-- TIP -->
638 `filterAttrs` is occasionally the cause of infinite recursion in configuration systems that allow self-references.
639 To support the widest range of user-provided logic, perform the `filterAttrs` call as late as possible.
640 Typically that's right before using it in a derivation, as opposed to an implicit conversion whose result is accessible to the user's expressions.
641
642 `set`
643
644 : The attribute set to filter
645
646 # Type
647
648 ```
649 filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet
650 ```
651
652 # Examples
653 :::{.example}
654 ## `lib.attrsets.filterAttrs` usage example
655
656 ```nix
657 filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
658 => { foo = 1; }
659 ```
660
661 :::
662 */
663 filterAttrs = pred: set: removeAttrs set (filter (name: !pred name set.${name}) (attrNames set));
664
665 /**
666 Filter an attribute set recursively by removing all attributes for
667 which the given predicate return false.
668
669 # Inputs
670
671 `pred`
672
673 : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
674
675 `set`
676
677 : The attribute set to filter
678
679 # Type
680
681 ```
682 filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet
683 ```
684
685 # Examples
686 :::{.example}
687 ## `lib.attrsets.filterAttrsRecursive` usage example
688
689 ```nix
690 filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
691 => { foo = {}; }
692 ```
693
694 :::
695 */
696 filterAttrsRecursive =
697 pred: set:
698 listToAttrs (
699 concatMap (
700 name:
701 let
702 v = set.${name};
703 in
704 if pred name v then
705 [
706 (nameValuePair name (if isAttrs v then filterAttrsRecursive pred v else v))
707 ]
708 else
709 [ ]
710 ) (attrNames set)
711 );
712
713 /**
714 Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets.
715 Iterates over every name-value pair in the given attribute set.
716 The result of the callback function is often called `acc` for accumulator. It is passed between callbacks from left to right and the final `acc` is the return value of `foldlAttrs`.
717
718 ::: {.note}
719 There is a completely different function `lib.foldAttrs`
720 which has nothing to do with this function, despite the similar name.
721 :::
722
723 # Inputs
724
725 `f`
726
727 : 1\. Function argument
728
729 `init`
730
731 : 2\. Function argument
732
733 `set`
734
735 : 3\. Function argument
736
737 # Type
738
739 ```
740 foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
741 ```
742
743 # Examples
744 :::{.example}
745 ## `lib.attrsets.foldlAttrs` usage example
746
747 ```nix
748 foldlAttrs
749 (acc: name: value: {
750 sum = acc.sum + value;
751 names = acc.names ++ [name];
752 })
753 { sum = 0; names = []; }
754 {
755 foo = 1;
756 bar = 10;
757 }
758 ->
759 {
760 sum = 11;
761 names = ["bar" "foo"];
762 }
763
764 foldlAttrs
765 (throw "function not needed")
766 123
767 {};
768 ->
769 123
770
771 foldlAttrs
772 (acc: _: _: acc)
773 3
774 { z = throw "value not needed"; a = throw "value not needed"; };
775 ->
776 3
777
778 The accumulator doesn't have to be an attrset.
779 It can be as simple as a number or string.
780
781 foldlAttrs
782 (acc: _: v: acc * 10 + v)
783 1
784 { z = 1; a = 2; };
785 ->
786 121
787 ```
788
789 :::
790 */
791 foldlAttrs =
792 f: init: set:
793 foldl' (acc: name: f acc name set.${name}) init (attrNames set);
794
795 /**
796 Apply fold functions to values grouped by key.
797
798 # Inputs
799
800 `op`
801
802 : A function, given a value and a collector combines the two.
803
804 `nul`
805
806 : The starting value.
807
808 `list_of_attrs`
809
810 : A list of attribute sets to fold together by key.
811
812 # Type
813
814 ```
815 foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any
816 ```
817
818 # Examples
819 :::{.example}
820 ## `lib.attrsets.foldAttrs` usage example
821
822 ```nix
823 foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }]
824 => { a = [ 2 3 ]; }
825 ```
826
827 :::
828 */
829 foldAttrs =
830 op: nul: list_of_attrs:
831 foldr (
832 n: a: foldr (name: o: o // { ${name} = op n.${name} (a.${name} or nul); }) a (attrNames n)
833 ) { } list_of_attrs;
834
835 /**
836 Recursively collect sets that verify a given predicate named `pred`
837 from the set `attrs`. The recursion is stopped when the predicate is
838 verified.
839
840 # Inputs
841
842 `pred`
843
844 : Given an attribute's value, determine if recursion should stop.
845
846 `attrs`
847
848 : The attribute set to recursively collect.
849
850 # Type
851
852 ```
853 collect :: (AttrSet -> Bool) -> AttrSet -> [x]
854 ```
855
856 # Examples
857 :::{.example}
858 ## `lib.attrsets.collect` usage example
859
860 ```nix
861 collect isList { a = { b = ["b"]; }; c = [1]; }
862 => [["b"] [1]]
863
864 collect (x: x ? outPath)
865 { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
866 => [{ outPath = "a/"; } { outPath = "b/"; }]
867 ```
868
869 :::
870 */
871 collect =
872 pred: attrs:
873 if pred attrs then
874 [ attrs ]
875 else if isAttrs attrs then
876 concatMap (collect pred) (attrValues attrs)
877 else
878 [ ];
879
880 /**
881 Return the cartesian product of attribute set value combinations.
882
883 # Inputs
884
885 `attrsOfLists`
886
887 : Attribute set with attributes that are lists of values
888
889 # Type
890
891 ```
892 cartesianProduct :: AttrSet -> [AttrSet]
893 ```
894
895 # Examples
896 :::{.example}
897 ## `lib.attrsets.cartesianProduct` usage example
898
899 ```nix
900 cartesianProduct { a = [ 1 2 ]; b = [ 10 20 ]; }
901 => [
902 { a = 1; b = 10; }
903 { a = 1; b = 20; }
904 { a = 2; b = 10; }
905 { a = 2; b = 20; }
906 ]
907 ```
908
909 :::
910 */
911 cartesianProduct =
912 attrsOfLists:
913 foldl' (
914 listOfAttrs: attrName:
915 concatMap (
916 attrs: map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
917 ) listOfAttrs
918 ) [ { } ] (attrNames attrsOfLists);
919
920 /**
921 Return the result of function `f` applied to the cartesian product of attribute set value combinations.
922 Equivalent to using `cartesianProduct` followed by `map`.
923
924 # Inputs
925
926 `f`
927
928 : A function, given an attribute set, it returns a new value.
929
930 `attrsOfLists`
931
932 : Attribute set with attributes that are lists of values
933
934 # Type
935
936 ```
937 mapCartesianProduct :: (AttrSet -> a) -> AttrSet -> [a]
938 ```
939
940 # Examples
941 :::{.example}
942 ## `lib.attrsets.mapCartesianProduct` usage example
943
944 ```nix
945 mapCartesianProduct ({a, b}: "${a}-${b}") { a = [ "1" "2" ]; b = [ "3" "4" ]; }
946 => [ "1-3" "1-4" "2-3" "2-4" ]
947 ```
948
949 :::
950 */
951 mapCartesianProduct = f: attrsOfLists: map f (cartesianProduct attrsOfLists);
952
953 /**
954 Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`.
955
956 # Inputs
957
958 `name`
959
960 : Attribute name
961
962 `value`
963
964 : Attribute value
965
966 # Type
967
968 ```
969 nameValuePair :: String -> Any -> { name :: String; value :: Any; }
970 ```
971
972 # Examples
973 :::{.example}
974 ## `lib.attrsets.nameValuePair` usage example
975
976 ```nix
977 nameValuePair "some" 6
978 => { name = "some"; value = 6; }
979 ```
980
981 :::
982 */
983 nameValuePair = name: value: { inherit name value; };
984
985 /**
986 Apply a function to each element in an attribute set, creating a new attribute set.
987
988 # Inputs
989
990 `f`
991
992 : A function that takes an attribute name and its value, and returns the new value for the attribute.
993
994 `attrset`
995
996 : The attribute set to iterate through.
997
998 # Type
999
1000 ```
1001 mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet
1002 ```
1003
1004 # Examples
1005 :::{.example}
1006 ## `lib.attrsets.mapAttrs` usage example
1007
1008 ```nix
1009 mapAttrs (name: value: name + "-" + value)
1010 { x = "foo"; y = "bar"; }
1011 => { x = "x-foo"; y = "y-bar"; }
1012 ```
1013
1014 :::
1015 */
1016 mapAttrs = builtins.mapAttrs;
1017
1018 /**
1019 Like `mapAttrs`, but allows the name of each attribute to be
1020 changed in addition to the value. The applied function should
1021 return both the new name and value as a `nameValuePair`.
1022
1023 # Inputs
1024
1025 `f`
1026
1027 : A function, given an attribute's name and value, returns a new `nameValuePair`.
1028
1029 `set`
1030
1031 : Attribute set to map over.
1032
1033 # Type
1034
1035 ```
1036 mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet
1037 ```
1038
1039 # Examples
1040 :::{.example}
1041 ## `lib.attrsets.mapAttrs'` usage example
1042
1043 ```nix
1044 mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
1045 { x = "a"; y = "b"; }
1046 => { foo_x = "bar-a"; foo_y = "bar-b"; }
1047 ```
1048
1049 :::
1050 */
1051 mapAttrs' = f: set: listToAttrs (mapAttrsToList f set);
1052
1053 /**
1054 Call a function for each attribute in the given set and return
1055 the result in a list.
1056
1057 # Inputs
1058
1059 `f`
1060
1061 : A function, given an attribute's name and value, returns a new value.
1062
1063 `attrs`
1064
1065 : Attribute set to map over.
1066
1067 # Type
1068
1069 ```
1070 mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b]
1071 ```
1072
1073 # Examples
1074 :::{.example}
1075 ## `lib.attrsets.mapAttrsToList` usage example
1076
1077 ```nix
1078 mapAttrsToList (name: value: name + value)
1079 { x = "a"; y = "b"; }
1080 => [ "xa" "yb" ]
1081 ```
1082
1083 :::
1084 */
1085 mapAttrsToList = f: attrs: attrValues (mapAttrs f attrs);
1086
1087 /**
1088 Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs).
1089 Each element of the resulting list is an attribute set with these attributes:
1090 - `name` (string): The name of the attribute
1091 - `value` (any): The value of the attribute
1092
1093 The following is always true:
1094 ```nix
1095 builtins.listToAttrs (attrsToList attrs) == attrs
1096 ```
1097
1098 :::{.warning}
1099 The opposite is not always true. In general expect that
1100 ```nix
1101 attrsToList (builtins.listToAttrs list) != list
1102 ```
1103
1104 This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
1105 :::
1106
1107 # Inputs
1108
1109 `set`
1110
1111 : The attribute set to deconstruct.
1112
1113 # Type
1114
1115 ```
1116 attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
1117 ```
1118
1119 # Examples
1120 :::{.example}
1121 ## `lib.attrsets.attrsToList` usage example
1122
1123 ```nix
1124 attrsToList { foo = 1; bar = "asdf"; }
1125 => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
1126 ```
1127
1128 :::
1129 */
1130 attrsToList = mapAttrsToList nameValuePair;
1131
1132 /**
1133 Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set:
1134 the second argument of the function will never be an attrset.
1135 Also, the first argument of the mapping function is a *list* of the attribute names that form the path to the leaf attribute.
1136
1137 For a function that gives you control over what counts as a leaf, see `mapAttrsRecursiveCond`.
1138
1139 :::{#map-attrs-recursive-example .example}
1140 # Map over leaf attributes
1141
1142 ```nix
1143 mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
1144 { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
1145 ```
1146 evaluates to
1147 ```nix
1148 { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
1149 ```
1150 :::
1151
1152 # Type
1153 ```
1154 mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
1155 ```
1156 */
1157 mapAttrsRecursive = f: set: mapAttrsRecursiveCond (as: true) f set;
1158
1159 /**
1160 Like `mapAttrsRecursive`, but it takes an additional predicate that tells it whether to recurse into an attribute set.
1161 If the predicate returns false, `mapAttrsRecursiveCond` does not recurse, but instead applies the mapping function.
1162 If the predicate returns true, it does recurse, and does not apply the mapping function.
1163
1164 :::{#map-attrs-recursive-cond-example .example}
1165 # Map over an leaf attributes defined by a condition
1166
1167 Map derivations to their `name` attribute.
1168 Derivatons are identified as attribute sets that contain `{ type = "derivation"; }`.
1169 ```nix
1170 mapAttrsRecursiveCond
1171 (as: !(as ? "type" && as.type == "derivation"))
1172 (path: x: x.name)
1173 attrs
1174 ```
1175 :::
1176
1177 # Type
1178 ```
1179 mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
1180 ```
1181 */
1182 mapAttrsRecursiveCond =
1183 cond: f: set:
1184 let
1185 recurse =
1186 path:
1187 mapAttrs (
1188 name: value:
1189 if isAttrs value && cond value then recurse (path ++ [ name ]) value else f (path ++ [ name ]) value
1190 );
1191 in
1192 recurse [ ] set;
1193
1194 /**
1195 Apply a function to each leaf (non‐attribute‐set attribute) of a tree of
1196 nested attribute sets, returning the results of the function as a list,
1197 ordered lexicographically by their attribute paths.
1198
1199 Like `mapAttrsRecursive`, but concatenates the mapping function results
1200 into a list.
1201
1202 # Inputs
1203
1204 `f`
1205
1206 : Mapping function which, given an attribute’s path and value, returns a
1207 new value.
1208
1209 This value will be an element of the list returned by
1210 `mapAttrsToListRecursive`.
1211
1212 The first argument to the mapping function is a list of attribute names
1213 forming the path to the leaf attribute. The second argument is the leaf
1214 attribute value, which will never be an attribute set.
1215
1216 `set`
1217
1218 : Attribute set to map over.
1219
1220 # Type
1221
1222 ```
1223 mapAttrsToListRecursive :: ([String] -> a -> b) -> AttrSet -> [b]
1224 ```
1225
1226 # Examples
1227 :::{.example}
1228 ## `lib.attrsets.mapAttrsToListRecursive` usage example
1229
1230 ```nix
1231 mapAttrsToListRecursive (path: value: "${concatStringsSep "." path}=${value}")
1232 { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
1233 => [ "n.a=A" "n.m.b=B" "n.m.c=C" "d=D" ]
1234 ```
1235 :::
1236 */
1237 mapAttrsToListRecursive = mapAttrsToListRecursiveCond (_: _: true);
1238
1239 /**
1240 Determine the nodes of a tree of nested attribute sets by applying a
1241 predicate, then apply a function to the leaves, returning the results
1242 as a list, ordered lexicographically by their attribute paths.
1243
1244 Like `mapAttrsToListRecursive`, but takes an additional predicate to
1245 decide whether to recurse into an attribute set.
1246
1247 Unlike `mapAttrsRecursiveCond` this predicate receives the attribute path
1248 as its first argument, in addition to the attribute set.
1249
1250 # Inputs
1251
1252 `pred`
1253
1254 : Predicate to decide whether to recurse into an attribute set.
1255
1256 If the predicate returns true, `mapAttrsToListRecursiveCond` recurses into
1257 the attribute set. If the predicate returns false, it does not recurse
1258 but instead applies the mapping function, treating the attribute set as
1259 a leaf.
1260
1261 The first argument to the predicate is a list of attribute names forming
1262 the path to the attribute set. The second argument is the attribute set.
1263
1264 `f`
1265
1266 : Mapping function which, given an attribute’s path and value, returns a
1267 new value.
1268
1269 This value will be an element of the list returned by
1270 `mapAttrsToListRecursiveCond`.
1271
1272 The first argument to the mapping function is a list of attribute names
1273 forming the path to the leaf attribute. The second argument is the leaf
1274 attribute value, which may be an attribute set if the predicate returned
1275 false.
1276
1277 `set`
1278
1279 : Attribute set to map over.
1280
1281 # Type
1282 ```
1283 mapAttrsToListRecursiveCond :: ([String] -> AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> [b]
1284 ```
1285
1286 # Examples
1287 :::{.example}
1288 ## `lib.attrsets.mapAttrsToListRecursiveCond` usage example
1289
1290 ```nix
1291 mapAttrsToListRecursiveCond
1292 (path: as: !(lib.isDerivation as))
1293 (path: value: "--set=${lib.concatStringsSep "." path}=${toString value}")
1294 {
1295 rust.optimize = 2;
1296 target = {
1297 riscv64-unknown-linux-gnu.linker = pkgs.lld;
1298 };
1299 }
1300 => [ "--set=rust.optimize=2" "--set=target.riscv64-unknown-linux-gnu.linker=/nix/store/sjw4h1k…" ]
1301 ```
1302 :::
1303 */
1304 mapAttrsToListRecursiveCond =
1305 pred: f: set:
1306 let
1307 mapRecursive =
1308 path: value: if isAttrs value && pred path value then recurse path value else [ (f path value) ];
1309 recurse = path: set: concatMap (name: mapRecursive (path ++ [ name ]) set.${name}) (attrNames set);
1310 in
1311 recurse [ ] set;
1312
1313 /**
1314 Generate an attribute set by mapping a function over a list of
1315 attribute names.
1316
1317 # Inputs
1318
1319 `names`
1320
1321 : Names of values in the resulting attribute set.
1322
1323 `f`
1324
1325 : A function, given the name of the attribute, returns the attribute's value.
1326
1327 # Type
1328
1329 ```
1330 genAttrs :: [ String ] -> (String -> Any) -> AttrSet
1331 ```
1332
1333 # Examples
1334 :::{.example}
1335 ## `lib.attrsets.genAttrs` usage example
1336
1337 ```nix
1338 genAttrs [ "foo" "bar" ] (name: "x_" + name)
1339 => { foo = "x_foo"; bar = "x_bar"; }
1340 ```
1341
1342 :::
1343 */
1344 genAttrs = names: f: genAttrs' names (n: nameValuePair n (f n));
1345
1346 /**
1347 Like `genAttrs`, but allows the name of each attribute to be specified in addition to the value.
1348 The applied function should return both the new name and value as a `nameValuePair`.
1349 ::: {.warning}
1350 In case of attribute name collision the first entry determines the value,
1351 all subsequent conflicting entries for the same name are silently ignored.
1352 :::
1353
1354 # Inputs
1355
1356 `xs`
1357
1358 : A list of strings `s` used as generator.
1359
1360 `f`
1361
1362 : A function, given a string `s` from the list `xs`, returns a new `nameValuePair`.
1363
1364 # Type
1365
1366 ```
1367 genAttrs' :: [ Any ] -> (Any -> { name :: String; value :: Any; }) -> AttrSet
1368 ```
1369
1370 # Examples
1371 :::{.example}
1372 ## `lib.attrsets.genAttrs'` usage example
1373
1374 ```nix
1375 genAttrs' [ "foo" "bar" ] (s: nameValuePair ("x_" + s) ("y_" + s))
1376 => { x_foo = "y_foo"; x_bar = "y_bar"; }
1377 ```
1378
1379 :::
1380 */
1381 genAttrs' = xs: f: listToAttrs (map f xs);
1382
1383 /**
1384 Check whether the argument is a derivation. Any set with
1385 `{ type = "derivation"; }` counts as a derivation.
1386
1387 # Inputs
1388
1389 `value`
1390
1391 : Value to check.
1392
1393 # Type
1394
1395 ```
1396 isDerivation :: Any -> Bool
1397 ```
1398
1399 # Examples
1400 :::{.example}
1401 ## `lib.attrsets.isDerivation` usage example
1402
1403 ```nix
1404 nixpkgs = import <nixpkgs> {}
1405 isDerivation nixpkgs.ruby
1406 => true
1407 isDerivation "foobar"
1408 => false
1409 ```
1410
1411 :::
1412 */
1413 isDerivation = value: value.type or null == "derivation";
1414
1415 /**
1416 Converts a store path to a fake derivation.
1417
1418 # Inputs
1419
1420 `path`
1421
1422 : A store path to convert to a derivation.
1423
1424 # Type
1425
1426 ```
1427 toDerivation :: Path -> Derivation
1428 ```
1429 */
1430 toDerivation =
1431 path:
1432 let
1433 path' = builtins.storePath path;
1434 res = {
1435 type = "derivation";
1436 name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
1437 outPath = path';
1438 outputs = [ "out" ];
1439 out = res;
1440 outputName = "out";
1441 };
1442 in
1443 res;
1444
1445 /**
1446 If `cond` is true, return the attribute set `as`,
1447 otherwise an empty attribute set.
1448
1449 # Inputs
1450
1451 `cond`
1452
1453 : Condition under which the `as` attribute set is returned.
1454
1455 `as`
1456
1457 : The attribute set to return if `cond` is `true`.
1458
1459 # Type
1460
1461 ```
1462 optionalAttrs :: Bool -> AttrSet -> AttrSet
1463 ```
1464
1465 # Examples
1466 :::{.example}
1467 ## `lib.attrsets.optionalAttrs` usage example
1468
1469 ```nix
1470 optionalAttrs (true) { my = "set"; }
1471 => { my = "set"; }
1472 optionalAttrs (false) { my = "set"; }
1473 => { }
1474 ```
1475
1476 :::
1477 */
1478 optionalAttrs = cond: as: if cond then as else { };
1479
1480 /**
1481 Merge sets of attributes and use the function `f` to merge attributes
1482 values.
1483
1484 # Inputs
1485
1486 `names`
1487
1488 : List of attribute names to zip.
1489
1490 `f`
1491
1492 : A function, accepts an attribute name, all the values, and returns a combined value.
1493
1494 `sets`
1495
1496 : List of values from the list of attribute sets.
1497
1498 # Type
1499
1500 ```
1501 zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1502 ```
1503
1504 # Examples
1505 :::{.example}
1506 ## `lib.attrsets.zipAttrsWithNames` usage example
1507
1508 ```nix
1509 zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
1510 => { a = ["x" "y"]; }
1511 ```
1512
1513 :::
1514 */
1515 zipAttrsWithNames =
1516 names: f: sets:
1517 listToAttrs (
1518 map (name: {
1519 inherit name;
1520 value = f name (catAttrs name sets);
1521 }) names
1522 );
1523
1524 /**
1525 Merge sets of attributes and use the function `f` to merge attribute values.
1526 Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`.
1527
1528 Implementation note: Common names appear multiple times in the list of
1529 names, hopefully this does not affect the system because the maximal
1530 laziness avoid computing twice the same expression and `listToAttrs` does
1531 not care about duplicated attribute names.
1532
1533 # Type
1534
1535 ```
1536 zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1537 ```
1538
1539 # Examples
1540 :::{.example}
1541 ## `lib.attrsets.zipAttrsWith` usage example
1542
1543 ```nix
1544 zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
1545 => { a = ["x" "y"]; b = ["z"]; }
1546 ```
1547
1548 :::
1549 */
1550 zipAttrsWith =
1551 builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets);
1552
1553 /**
1554 Merge sets of attributes and combine each attribute value in to a list.
1555
1556 Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function.
1557
1558 # Type
1559
1560 ```
1561 zipAttrs :: [ AttrSet ] -> AttrSet
1562 ```
1563
1564 # Examples
1565 :::{.example}
1566 ## `lib.attrsets.zipAttrs` usage example
1567
1568 ```nix
1569 zipAttrs [{a = "x";} {a = "y"; b = "z";}]
1570 => { a = ["x" "y"]; b = ["z"]; }
1571 ```
1572
1573 :::
1574 */
1575 zipAttrs = zipAttrsWith (name: values: values);
1576
1577 /**
1578 Merge a list of attribute sets together using the `//` operator.
1579 In case of duplicate attributes, values from later list elements take precedence over earlier ones.
1580 The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs.
1581 For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n).
1582
1583 # Inputs
1584
1585 `list`
1586
1587 : 1\. Function argument
1588
1589 # Type
1590
1591 ```
1592 mergeAttrsList :: [ Attrs ] -> Attrs
1593 ```
1594
1595 # Examples
1596 :::{.example}
1597 ## `lib.attrsets.mergeAttrsList` usage example
1598
1599 ```nix
1600 mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]
1601 => { a = 0; b = 1; c = 2; d = 3; }
1602 mergeAttrsList [ { a = 0; } { a = 1; } ]
1603 => { a = 1; }
1604 ```
1605
1606 :::
1607 */
1608 mergeAttrsList =
1609 list:
1610 let
1611 # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
1612 # Type: Int -> Int -> Attrs
1613 binaryMerge =
1614 start: end:
1615 # assert start < end; # Invariant
1616 if end - start >= 2 then
1617 # If there's at least 2 elements, split the range in two, recurse on each part and merge the result
1618 # The invariant is satisfied because each half will have at least 1 element
1619 binaryMerge start (start + (end - start) / 2) // binaryMerge (start + (end - start) / 2) end
1620 else
1621 # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
1622 elemAt list start;
1623 in
1624 if list == [ ] then
1625 # Calling binaryMerge as below would not satisfy its invariant
1626 { }
1627 else
1628 binaryMerge 0 (length list);
1629
1630 /**
1631 Update `lhs` so that `rhs` wins for any given attribute path that occurs in both.
1632
1633 Unlike the `//` (update) operator, which operates on a single attribute set,
1634 This function views its operands `lhs` and `rhs` as a mapping from attribute *paths*
1635 to values.
1636
1637 The caller-provided function `pred` decides whether any given path is one of the following:
1638
1639 - `true`: a value in the mapping
1640 - `false`: an attribute set whose purpose is to create the nesting structure.
1641
1642 # Inputs
1643
1644 `pred`
1645
1646 : Predicate function (of type `List String -> Any -> Any -> Bool`)
1647
1648 Inputs:
1649
1650 - `path : List String`: the path to the current attribute as a list of strings for attribute names
1651 - `lhsAtPath : Any`: the value at that path in `lhs`; same as `getAttrFromPath path lhs`
1652 - `rhsAtPath : Any`: the value at that path in `rhs`; same as `getAttrFromPath path rhs`
1653
1654 Output:
1655
1656 - `true`: `path` points to a value in the mapping, and `rhsAtPath` will appear in the return value of `recursiveUpdateUntil`
1657 - `false`: `path` is part of the nesting structure and will be an attrset in the return value of `recursiveUpdateUntil`
1658
1659 `pred` is only called for `path`s that extend prefixes for which `pred` returned `false`.
1660
1661 `lhs`
1662
1663 : Left attribute set of the update.
1664
1665 `rhs`
1666
1667 : Right attribute set of the update.
1668
1669 # Type
1670
1671 ```
1672 recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
1673 ```
1674
1675 # Examples
1676 :::{.example}
1677 ## `lib.attrsets.recursiveUpdateUntil` usage example
1678
1679 ```nix
1680 recursiveUpdateUntil (path: lhs: rhs: path == ["foo"]) {
1681 # left attribute set
1682 foo.bar = 1;
1683 foo.baz = 2;
1684 bar = 3;
1685 } {
1686 # right attribute set
1687 foo.bar = 1;
1688 foo.quz = 2;
1689 baz = 4;
1690 }
1691
1692 => {
1693 foo.bar = 1; # 'foo.*' from the 'right' set
1694 foo.quz = 2; #
1695 bar = 3; # 'bar' from the 'left' set
1696 baz = 4; # 'baz' from the 'right' set
1697 }
1698 ```
1699
1700 :::
1701 */
1702 recursiveUpdateUntil =
1703 pred: lhs: rhs:
1704 let
1705 f =
1706 attrPath:
1707 zipAttrsWith (
1708 name: values:
1709 let
1710 here = attrPath ++ [ name ];
1711 in
1712 if length values == 1 || pred here (elemAt values 1) (head values) then
1713 head values
1714 else
1715 f here values
1716 );
1717 in
1718 f [ ] [ rhs lhs ];
1719
1720 /**
1721 A recursive variant of the update operator `//`. The recursion
1722 stops when one of the attribute values is not an attribute set,
1723 in which case the right hand side value takes precedence over the
1724 left hand side value.
1725
1726 # Inputs
1727
1728 `lhs`
1729
1730 : Left attribute set of the merge.
1731
1732 `rhs`
1733
1734 : Right attribute set of the merge.
1735
1736 # Type
1737
1738 ```
1739 recursiveUpdate :: AttrSet -> AttrSet -> AttrSet
1740 ```
1741
1742 # Examples
1743 :::{.example}
1744 ## `lib.attrsets.recursiveUpdate` usage example
1745
1746 ```nix
1747 recursiveUpdate {
1748 boot.loader.grub.enable = true;
1749 boot.loader.grub.device = "/dev/hda";
1750 } {
1751 boot.loader.grub.device = "";
1752 }
1753
1754 returns: {
1755 boot.loader.grub.enable = true;
1756 boot.loader.grub.device = "";
1757 }
1758 ```
1759
1760 :::
1761 */
1762 recursiveUpdate =
1763 lhs: rhs:
1764 recursiveUpdateUntil (
1765 path: lhs: rhs:
1766 !(isAttrs lhs && isAttrs rhs)
1767 ) lhs rhs;
1768
1769 /**
1770 Recurse into every attribute set of the first argument and check that:
1771 - Each attribute path also exists in the second argument.
1772 - If the attribute's value is not a nested attribute set, it must have the same value in the right argument.
1773
1774 # Inputs
1775
1776 `pattern`
1777
1778 : Attribute set structure to match
1779
1780 `attrs`
1781
1782 : Attribute set to check
1783
1784 # Type
1785
1786 ```
1787 matchAttrs :: AttrSet -> AttrSet -> Bool
1788 ```
1789
1790 # Examples
1791 :::{.example}
1792 ## `lib.attrsets.matchAttrs` usage example
1793
1794 ```nix
1795 matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
1796 => true
1797 ```
1798
1799 :::
1800 */
1801 matchAttrs =
1802 pattern: attrs:
1803 assert isAttrs pattern;
1804 all (
1805 # Compare equality between `pattern` & `attrs`.
1806 attr:
1807 # Missing attr, not equal.
1808 attrs ? ${attr}
1809 && (
1810 let
1811 lhs = pattern.${attr};
1812 rhs = attrs.${attr};
1813 in
1814 # If attrset check recursively
1815 if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs else lhs == rhs
1816 )
1817 ) (attrNames pattern);
1818
1819 /**
1820 Override only the attributes that are already present in the old set
1821 useful for deep-overriding.
1822
1823 # Inputs
1824
1825 `old`
1826
1827 : Original attribute set
1828
1829 `new`
1830
1831 : Attribute set with attributes to override in `old`.
1832
1833 # Type
1834
1835 ```
1836 overrideExisting :: AttrSet -> AttrSet -> AttrSet
1837 ```
1838
1839 # Examples
1840 :::{.example}
1841 ## `lib.attrsets.overrideExisting` usage example
1842
1843 ```nix
1844 overrideExisting {} { a = 1; }
1845 => {}
1846 overrideExisting { b = 2; } { a = 1; }
1847 => { b = 2; }
1848 overrideExisting { a = 3; b = 2; } { a = 1; }
1849 => { a = 1; b = 2; }
1850 ```
1851
1852 :::
1853 */
1854 overrideExisting = old: new: mapAttrs (name: value: new.${name} or value) old;
1855
1856 /**
1857 Turns a list of strings into a human-readable description of those
1858 strings represented as an attribute path. The result of this function is
1859 not intended to be machine-readable.
1860 Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
1861
1862 # Inputs
1863
1864 `path`
1865
1866 : Attribute path to render to a string
1867
1868 # Type
1869
1870 ```
1871 showAttrPath :: [String] -> String
1872 ```
1873
1874 # Examples
1875 :::{.example}
1876 ## `lib.attrsets.showAttrPath` usage example
1877
1878 ```nix
1879 showAttrPath [ "foo" "10" "bar" ]
1880 => "foo.\"10\".bar"
1881 showAttrPath []
1882 => "<root attribute path>"
1883 ```
1884
1885 :::
1886 */
1887 showAttrPath =
1888 path:
1889 if path == [ ] then "<root attribute path>" else concatMapStringsSep "." escapeNixIdentifier path;
1890
1891 /**
1892 Get a package output.
1893 If no output is found, fallback to `.out` and then to the default.
1894 The function is idempotent: `getOutput "b" (getOutput "a" p) == getOutput "a" p`.
1895
1896 # Inputs
1897
1898 `output`
1899
1900 : 1\. Function argument
1901
1902 `pkg`
1903
1904 : 2\. Function argument
1905
1906 # Type
1907
1908 ```
1909 getOutput :: String -> :: Derivation -> Derivation
1910 ```
1911
1912 # Examples
1913 :::{.example}
1914 ## `lib.attrsets.getOutput` usage example
1915
1916 ```nix
1917 "${getOutput "dev" pkgs.openssl}"
1918 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1919 ```
1920
1921 :::
1922 */
1923 getOutput =
1924 output: pkg:
1925 if !pkg ? outputSpecified || !pkg.outputSpecified then pkg.${output} or pkg.out or pkg else pkg;
1926
1927 /**
1928 Get the first of the `outputs` provided by the package, or the default.
1929 This function is aligned with `_overrideFirst()` from the `multiple-outputs.sh` setup hook.
1930 Like `getOutput`, the function is idempotent.
1931
1932 # Inputs
1933
1934 `outputs`
1935
1936 : 1\. Function argument
1937
1938 `pkg`
1939
1940 : 2\. Function argument
1941
1942 # Type
1943
1944 ```
1945 getFirstOutput :: [String] -> Derivation -> Derivation
1946 ```
1947
1948 # Examples
1949 :::{.example}
1950 ## `lib.attrsets.getFirstOutput` usage example
1951
1952 ```nix
1953 "${getFirstOutput [ "include" "dev" ] pkgs.openssl}"
1954 => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r-dev"
1955 ```
1956
1957 :::
1958 */
1959 getFirstOutput =
1960 candidates: pkg:
1961 let
1962 outputs = builtins.filter (name: hasAttr name pkg) candidates;
1963 output = builtins.head outputs;
1964 in
1965 if pkg.outputSpecified or false || outputs == [ ] then pkg else pkg.${output};
1966
1967 /**
1968 Get a package's `bin` output.
1969 If the output does not exist, fallback to `.out` and then to the default.
1970
1971 # Inputs
1972
1973 `pkg`
1974
1975 : The package whose `bin` output will be retrieved.
1976
1977 # Type
1978
1979 ```
1980 getBin :: Derivation -> Derivation
1981 ```
1982
1983 # Examples
1984 :::{.example}
1985 ## `lib.attrsets.getBin` usage example
1986
1987 ```nix
1988 "${getBin pkgs.openssl}"
1989 => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r"
1990 ```
1991
1992 :::
1993 */
1994 getBin = getOutput "bin";
1995
1996 /**
1997 Get a package's `lib` output.
1998 If the output does not exist, fallback to `.out` and then to the default.
1999
2000 # Inputs
2001
2002 `pkg`
2003
2004 : The package whose `lib` output will be retrieved.
2005
2006 # Type
2007
2008 ```
2009 getLib :: Derivation -> Derivation
2010 ```
2011
2012 # Examples
2013 :::{.example}
2014 ## `lib.attrsets.getLib` usage example
2015
2016 ```nix
2017 "${getLib pkgs.openssl}"
2018 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib"
2019 ```
2020
2021 :::
2022 */
2023 getLib = getOutput "lib";
2024
2025 /**
2026 Get a package's `static` output.
2027 If the output does not exist, fallback to `.lib`, then to `.out`, and then to the default.
2028
2029 # Inputs
2030
2031 `pkg`
2032
2033 : The package whose `static` output will be retrieved.
2034
2035 # Type
2036
2037 ```
2038 getStatic :: Derivation -> Derivation
2039 ```
2040
2041 # Examples
2042 :::{.example}
2043 ## `lib.attrsets.getStatic` usage example
2044
2045 ```nix
2046 "${lib.getStatic pkgs.glibc}"
2047 => "/nix/store/00000000000000000000000000000000-glibc-2.39-52-static"
2048 ```
2049
2050 :::
2051 */
2052 getStatic = getFirstOutput [
2053 "static"
2054 "lib"
2055 "out"
2056 ];
2057
2058 /**
2059 Get a package's `dev` output.
2060 If the output does not exist, fallback to `.out` and then to the default.
2061
2062 # Inputs
2063
2064 `pkg`
2065
2066 : The package whose `dev` output will be retrieved.
2067
2068 # Type
2069
2070 ```
2071 getDev :: Derivation -> Derivation
2072 ```
2073
2074 # Examples
2075 :::{.example}
2076 ## `lib.attrsets.getDev` usage example
2077
2078 ```nix
2079 "${getDev pkgs.openssl}"
2080 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
2081 ```
2082
2083 :::
2084 */
2085 getDev = getOutput "dev";
2086
2087 /**
2088 Get a package's `include` output.
2089 If the output does not exist, fallback to `.dev`, then to `.out`, and then to the default.
2090
2091 # Inputs
2092
2093 `pkg`
2094
2095 : The package whose `include` output will be retrieved.
2096
2097 # Type
2098
2099 ```
2100 getInclude :: Derivation -> Derivation
2101 ```
2102
2103 # Examples
2104 :::{.example}
2105 ## `lib.attrsets.getInclude` usage example
2106
2107 ```nix
2108 "${getInclude pkgs.openssl}"
2109 => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r-dev"
2110 ```
2111
2112 :::
2113 */
2114 getInclude = getFirstOutput [
2115 "include"
2116 "dev"
2117 "out"
2118 ];
2119
2120 /**
2121 Get a package's `man` output.
2122 If the output does not exist, fallback to `.out` and then to the default.
2123
2124 # Inputs
2125
2126 `pkg`
2127
2128 : The package whose `man` output will be retrieved.
2129
2130 # Type
2131
2132 ```
2133 getMan :: Derivation -> Derivation
2134 ```
2135
2136 # Examples
2137 :::{.example}
2138 ## `lib.attrsets.getMan` usage example
2139
2140 ```nix
2141 "${getMan pkgs.openssl}"
2142 => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man"
2143 ```
2144
2145 :::
2146 */
2147 getMan = getOutput "man";
2148
2149 /**
2150 Pick the outputs of packages to place in `buildInputs`
2151
2152 # Inputs
2153
2154 `pkgs`
2155
2156 : List of packages.
2157
2158 # Type
2159
2160 ```
2161 chooseDevOutputs :: [Derivation] -> [Derivation]
2162 ```
2163 */
2164 chooseDevOutputs = map getDev;
2165
2166 /**
2167 Make various Nix tools consider the contents of the resulting
2168 attribute set when looking for what to build, find, etc.
2169
2170 This function only affects a single attribute set; it does not
2171 apply itself recursively for nested attribute sets.
2172
2173 # Inputs
2174
2175 `attrs`
2176
2177 : An attribute set to scan for derivations.
2178
2179 # Type
2180
2181 ```
2182 recurseIntoAttrs :: AttrSet -> AttrSet
2183 ```
2184
2185 # Examples
2186 :::{.example}
2187 ## `lib.attrsets.recurseIntoAttrs` usage example
2188
2189 ```nix
2190 { pkgs ? import <nixpkgs> {} }:
2191 {
2192 myTools = pkgs.lib.recurseIntoAttrs {
2193 inherit (pkgs) hello figlet;
2194 };
2195 }
2196 ```
2197
2198 :::
2199 */
2200 recurseIntoAttrs = attrs: attrs // { recurseForDerivations = true; };
2201
2202 /**
2203 Undo the effect of `recurseIntoAttrs`.
2204
2205 # Inputs
2206
2207 `attrs`
2208
2209 : An attribute set to not scan for derivations.
2210
2211 # Type
2212
2213 ```
2214 dontRecurseIntoAttrs :: AttrSet -> AttrSet
2215 ```
2216 */
2217 dontRecurseIntoAttrs = attrs: attrs // { recurseForDerivations = false; };
2218
2219 /**
2220 `unionOfDisjoint x y` is equal to `x // y`, but accessing attributes present
2221 in both `x` and `y` will throw an error. This operator is commutative, unlike `//`.
2222
2223 # Inputs
2224
2225 `x`
2226
2227 : 1\. Function argument
2228
2229 `y`
2230
2231 : 2\. Function argument
2232
2233 # Type
2234
2235 ```
2236 unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet
2237 ```
2238 */
2239 unionOfDisjoint =
2240 x: y:
2241 let
2242 intersection = builtins.intersectAttrs x y;
2243 collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
2244 mask = builtins.mapAttrs (
2245 name: value: throw "unionOfDisjoint: collision on ${name}; complete list: ${collisions}"
2246 ) intersection;
2247 in
2248 (x // y) // mask;
2249}