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