python312Packages.dissect-fat: 3.10 -> 3.11 (#357040)
[NixPkgs.git] / lib / attrsets.nix
blob3001e4ec93b5699b4b9c5c157924a0322a3c8966
1 /**
2   Operations on attribute sets.
3 */
4 { lib }:
6 let
7   inherit (builtins) head length;
8   inherit (lib.trivial) oldestSupportedReleaseIsAtLeast mergeAttrs warn warnIf;
9   inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
10   inherit (lib.lists) filter foldr foldl' concatMap elemAt all partition groupBy take foldl;
13 rec {
14   inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr removeAttrs intersectAttrs;
17   /**
18     Return an attribute from nested attribute sets.
20     Nix has an [attribute selection operator `. or`](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:
22     ```nix
23     (x.a.b or 6) == attrByPath ["a" "b"] 6 x
24     # and
25     (x.${f p}."example.com" or 6) == attrByPath [ (f p) "example.com" ] 6 x
26     ```
29     # Inputs
31     `attrPath`
33     : A list of strings representing the attribute path to return from `set`
35     `default`
37     : Default value if `attrPath` does not resolve to an existing value
39     `set`
41     : The nested attribute set to select values from
43     # Type
45     ```
46     attrByPath :: [String] -> Any -> AttrSet -> Any
47     ```
49     # Examples
50     :::{.example}
51     ## `lib.attrsets.attrByPath` usage example
53     ```nix
54     x = { a = { b = 3; }; }
55     # ["a" "b"] is equivalent to x.a.b
56     # 6 is a default value to return if the path does not exist in attrset
57     attrByPath ["a" "b"] 6 x
58     => 3
59     attrByPath ["z" "z"] 6 x
60     => 6
61     ```
63     :::
64   */
65   attrByPath =
66     attrPath:
67     default:
68     set:
69     let
70       lenAttrPath = length attrPath;
71       attrByPath' = n: s: (
72         if n == lenAttrPath then s
73         else (
74           let
75             attr = elemAt attrPath n;
76           in
77           if s ? ${attr} then attrByPath' (n + 1) s.${attr}
78           else default
79         )
80       );
81     in
82       attrByPath' 0 set;
84   /**
85     Return if an attribute from nested attribute set exists.
87     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:
89     ```nix
90     (x?a.b) == hasAttrByPath ["a" "b"] x
91     # and
92     (x?${f p}."example.com") == hasAttrByPath [ (f p) "example.com" ] x
93     ```
95     **Laws**:
96      1.  ```nix
97          hasAttrByPath [] x == true
98          ```
101     # Inputs
103     `attrPath`
105     : A list of strings representing the attribute path to check from `set`
107     `e`
109     : The nested attribute set to check
111     # Type
113     ```
114     hasAttrByPath :: [String] -> AttrSet -> Bool
115     ```
117     # Examples
118     :::{.example}
119     ## `lib.attrsets.hasAttrByPath` usage example
121     ```nix
122     x = { a = { b = 3; }; }
123     hasAttrByPath ["a" "b"] x
124     => true
125     hasAttrByPath ["z" "z"] x
126     => false
127     hasAttrByPath [] (throw "no need")
128     => true
129     ```
131     :::
132   */
133   hasAttrByPath =
134     attrPath:
135     e:
136     let
137       lenAttrPath = length attrPath;
138       hasAttrByPath' = n: s: (
139         n == lenAttrPath || (
140           let
141             attr = elemAt attrPath n;
142           in
143           if s ? ${attr} then hasAttrByPath' (n + 1) s.${attr}
144           else false
145         )
146       );
147     in
148       hasAttrByPath' 0 e;
150   /**
151     Return the longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets.
153     Can be used after [`mapAttrsRecursiveCond`](#function-library-lib.attrsets.mapAttrsRecursiveCond) to apply a condition,
154     although this will evaluate the predicate function on sibling attributes as well.
156     Note that the empty attribute path is valid for all values, so this function only throws an exception if any of its inputs does.
158     **Laws**:
159     1.  ```nix
160         attrsets.longestValidPathPrefix [] x == []
161         ```
163     2.  ```nix
164         hasAttrByPath (attrsets.longestValidPathPrefix p x) x == true
165         ```
168     # Inputs
170     `attrPath`
172     : A list of strings representing the longest possible path that may be returned.
174     `v`
176     : The nested attribute set to check.
178     # Type
180     ```
181     attrsets.longestValidPathPrefix :: [String] -> Value -> [String]
182     ```
184     # Examples
185     :::{.example}
186     ## `lib.attrsets.longestValidPathPrefix` usage example
188     ```nix
189     x = { a = { b = 3; }; }
190     attrsets.longestValidPathPrefix ["a" "b" "c"] x
191     => ["a" "b"]
192     attrsets.longestValidPathPrefix ["a"] x
193     => ["a"]
194     attrsets.longestValidPathPrefix ["z" "z"] x
195     => []
196     attrsets.longestValidPathPrefix ["z" "z"] (throw "no need")
197     => []
198     ```
200     :::
201   */
202   longestValidPathPrefix =
203     attrPath:
204     v:
205     let
206       lenAttrPath = length attrPath;
207       getPrefixForSetAtIndex =
208         # The nested attribute set to check, if it is an attribute set, which
209         # is not a given.
210         remainingSet:
211         # The index of the attribute we're about to check, as well as
212         # the length of the prefix we've already checked.
213         remainingPathIndex:
215           if remainingPathIndex == lenAttrPath then
216             # All previously checked attributes exist, and no attr names left,
217             # so we return the whole path.
218             attrPath
219           else
220             let
221               attr = elemAt attrPath remainingPathIndex;
222             in
223             if remainingSet ? ${attr} then
224               getPrefixForSetAtIndex
225                 remainingSet.${attr}      # advance from the set to the attribute value
226                 (remainingPathIndex + 1)  # advance the path
227             else
228               # The attribute doesn't exist, so we return the prefix up to the
229               # previously checked length.
230               take remainingPathIndex attrPath;
231     in
232       getPrefixForSetAtIndex v 0;
234   /**
235     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
238     # Inputs
240     `attrPath`
242     : A list of strings representing the attribute path to set
244     `value`
246     : The value to set at the location described by `attrPath`
248     # Type
250     ```
251     setAttrByPath :: [String] -> Any -> AttrSet
252     ```
254     # Examples
255     :::{.example}
256     ## `lib.attrsets.setAttrByPath` usage example
258     ```nix
259     setAttrByPath ["a" "b"] 3
260     => { a = { b = 3; }; }
261     ```
263     :::
264   */
265   setAttrByPath =
266     attrPath:
267     value:
268     let
269       len = length attrPath;
270       atDepth = n:
271         if n == len
272         then value
273         else { ${elemAt attrPath n} = atDepth (n + 1); };
274     in atDepth 0;
276   /**
277     Like `attrByPath`, but without a default value. If it doesn't find the
278     path it will throw an error.
280     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:
282     ```nix
283     x.a.b == getAttrByPath ["a" "b"] x
284     # and
285     x.${f p}."example.com" == getAttrByPath [ (f p) "example.com" ] x
286     ```
289     # Inputs
291     `attrPath`
293     : A list of strings representing the attribute path to get from `set`
295     `set`
297     : The nested attribute set to find the value in.
299     # Type
301     ```
302     getAttrFromPath :: [String] -> AttrSet -> Any
303     ```
305     # Examples
306     :::{.example}
307     ## `lib.attrsets.getAttrFromPath` usage example
309     ```nix
310     x = { a = { b = 3; }; }
311     getAttrFromPath ["a" "b"] x
312     => 3
313     getAttrFromPath ["z" "z"] x
314     => error: cannot find attribute `z.z'
315     ```
317     :::
318   */
319   getAttrFromPath =
320     attrPath:
321     set:
322     attrByPath attrPath (abort ("cannot find attribute `" + concatStringsSep "." attrPath + "'")) set;
324   /**
325     Map each attribute in the given set and merge them into a new attribute set.
328     # Inputs
330     `f`
332     : 1\. Function argument
334     `v`
336     : 2\. Function argument
338     # Type
340     ```
341     concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet
342     ```
344     # Examples
345     :::{.example}
346     ## `lib.attrsets.concatMapAttrs` usage example
348     ```nix
349     concatMapAttrs
350       (name: value: {
351         ${name} = value;
352         ${name + value} = value;
353       })
354       { x = "a"; y = "b"; }
355     => { x = "a"; xa = "a"; y = "b"; yb = "b"; }
356     ```
358     :::
359   */
360   concatMapAttrs = f: v:
361     foldl' mergeAttrs { }
362       (attrValues
363         (mapAttrs f v)
364       );
367   /**
368     Update or set specific paths of an attribute set.
370     Takes a list of updates to apply and an attribute set to apply them to,
371     and returns the attribute set with the updates applied. Updates are
372     represented as `{ path = ...; update = ...; }` values, where `path` is a
373     list of strings representing the attribute path that should be updated,
374     and `update` is a function that takes the old value at that attribute path
375     as an argument and returns the new
376     value it should be.
378     Properties:
380     - Updates to deeper attribute paths are applied before updates to more
381       shallow attribute paths
383     - Multiple updates to the same attribute path are applied in the order
384       they appear in the update list
386     - If any but the last `path` element leads into a value that is not an
387       attribute set, an error is thrown
389     - If there is an update for an attribute path that doesn't exist,
390       accessing the argument in the update function causes an error, but
391       intermediate attribute sets are implicitly created as needed
393     # Type
395     ```
396     updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet
397     ```
399     # Examples
400     :::{.example}
401     ## `lib.attrsets.updateManyAttrsByPath` usage example
403     ```nix
404     updateManyAttrsByPath [
405       {
406         path = [ "a" "b" ];
407         update = old: { d = old.c; };
408       }
409       {
410         path = [ "a" "b" "c" ];
411         update = old: old + 1;
412       }
413       {
414         path = [ "x" "y" ];
415         update = old: "xy";
416       }
417     ] { a.b.c = 0; }
418     => { a = { b = { d = 1; }; }; x = { y = "xy"; }; }
419     ```
421     :::
422   */
423   updateManyAttrsByPath = let
424     # When recursing into attributes, instead of updating the `path` of each
425     # update using `tail`, which needs to allocate an entirely new list,
426     # we just pass a prefix length to use and make sure to only look at the
427     # path without the prefix length, so that we can reuse the original list
428     # entries.
429     go = prefixLength: hasValue: value: updates:
430       let
431         # Splits updates into ones on this level (split.right)
432         # And ones on levels further down (split.wrong)
433         split = partition (el: length el.path == prefixLength) updates;
435         # Groups updates on further down levels into the attributes they modify
436         nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
438         # Applies only nested modification to the input value
439         withNestedMods =
440           # Return the value directly if we don't have any nested modifications
441           if split.wrong == [] then
442             if hasValue then value
443             else
444               # Throw an error if there is no value. This `head` call here is
445               # safe, but only in this branch since `go` could only be called
446               # with `hasValue == false` for nested updates, in which case
447               # it's also always called with at least one update
448               let updatePath = (head split.right).path; in
449               throw
450               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
451               + "not exist in the given value, but the first update to this "
452               + "path tries to access the existing value.")
453           else
454             # If there are nested modifications, try to apply them to the value
455             if ! hasValue then
456               # But if we don't have a value, just use an empty attribute set
457               # as the value, but simplify the code a bit
458               mapAttrs (name: go (prefixLength + 1) false null) nested
459             else if isAttrs value then
460               # If we do have a value and it's an attribute set, override it
461               # with the nested modifications
462               value //
463               mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
464             else
465               # However if it's not an attribute set, we can't apply the nested
466               # modifications, throw an error
467               let updatePath = (head split.wrong).path; in
468               throw
469               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
470               + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
471               + "of the given value is not an attribute set, so we can't "
472               + "update an attribute inside of it.");
474         # We get the final result by applying all the updates on this level
475         # after having applied all the nested updates
476         # We use foldl instead of foldl' so that in case of multiple updates,
477         # intermediate values aren't evaluated if not needed
478       in foldl (acc: el: el.update acc) withNestedMods split.right;
480   in updates: value: go 0 true value updates;
482   /**
483     Return the specified attributes from a set.
486     # Inputs
488     `nameList`
490     : The list of attributes to fetch from `set`. Each attribute name must exist on the attrbitue set
492     `set`
494     : The set to get attribute values from
496     # Type
498     ```
499     attrVals :: [String] -> AttrSet -> [Any]
500     ```
502     # Examples
503     :::{.example}
504     ## `lib.attrsets.attrVals` usage example
506     ```nix
507     attrVals ["a" "b" "c"] as
508     => [as.a as.b as.c]
509     ```
511     :::
512   */
513   attrVals =
514     nameList:
515     set: map (x: set.${x}) nameList;
518   /**
519     Return the values of all attributes in the given set, sorted by
520     attribute name.
522     # Type
524     ```
525     attrValues :: AttrSet -> [Any]
526     ```
528     # Examples
529     :::{.example}
530     ## `lib.attrsets.attrValues` usage example
532     ```nix
533     attrValues {c = 3; a = 1; b = 2;}
534     => [1 2 3]
535     ```
537     :::
538   */
539   attrValues = builtins.attrValues;
542   /**
543     Given a set of attribute names, return the set of the corresponding
544     attributes from the given set.
547     # Inputs
549     `names`
551     : A list of attribute names to get out of `set`
553     `attrs`
555     : The set to get the named attributes from
557     # Type
559     ```
560     getAttrs :: [String] -> AttrSet -> AttrSet
561     ```
563     # Examples
564     :::{.example}
565     ## `lib.attrsets.getAttrs` usage example
567     ```nix
568     getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }
569     => { a = 1; b = 2; }
570     ```
572     :::
573   */
574   getAttrs =
575     names:
576     attrs: genAttrs names (name: attrs.${name});
578   /**
579     Collect each attribute named `attr` from a list of attribute
580     sets.  Sets that don't contain the named attribute are ignored.
582     # Inputs
584     `attr`
586     : The attribute name to get out of the sets.
588     `list`
590     : The list of attribute sets to go through
592     # Type
594     ```
595     catAttrs :: String -> [AttrSet] -> [Any]
596     ```
598     # Examples
599     :::{.example}
600     ## `lib.attrsets.catAttrs` usage example
602     ```nix
603     catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
604     => [1 2]
605     ```
607     :::
608   */
609   catAttrs = builtins.catAttrs;
612   /**
613     Filter an attribute set by removing all attributes for which the
614     given predicate return false.
617     # Inputs
619     `pred`
621     : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
623     `set`
625     : The attribute set to filter
627     # Type
629     ```
630     filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet
631     ```
633     # Examples
634     :::{.example}
635     ## `lib.attrsets.filterAttrs` usage example
637     ```nix
638     filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
639     => { foo = 1; }
640     ```
642     :::
643   */
644   filterAttrs =
645     pred:
646     set:
647     removeAttrs set (filter (name: ! pred name set.${name}) (attrNames set));
649   /**
650     Filter an attribute set recursively by removing all attributes for
651     which the given predicate return false.
654     # Inputs
656     `pred`
658     : Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
660     `set`
662     : The attribute set to filter
664     # Type
666     ```
667     filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet
668     ```
670     # Examples
671     :::{.example}
672     ## `lib.attrsets.filterAttrsRecursive` usage example
674     ```nix
675     filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
676     => { foo = {}; }
677     ```
679     :::
680   */
681   filterAttrsRecursive =
682     pred:
683     set:
684     listToAttrs (
685       concatMap (name:
686         let v = set.${name}; in
687         if pred name v then [
688           (nameValuePair name (
689             if isAttrs v then filterAttrsRecursive pred v
690             else v
691           ))
692         ] else []
693       ) (attrNames set)
694     );
696    /**
697     Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets.
698     Iterates over every name-value pair in the given attribute set.
699     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`.
701     Attention:
703     There is a completely different function `lib.foldAttrs`
704     which has nothing to do with this function, despite the similar name.
707     # Inputs
709     `f`
711     : 1\. Function argument
713     `init`
715     : 2\. Function argument
717     `set`
719     : 3\. Function argument
721     # Type
723     ```
724     foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
725     ```
727     # Examples
728     :::{.example}
729     ## `lib.attrsets.foldlAttrs` usage example
731     ```nix
732     foldlAttrs
733       (acc: name: value: {
734         sum = acc.sum + value;
735         names = acc.names ++ [name];
736       })
737       { sum = 0; names = []; }
738       {
739         foo = 1;
740         bar = 10;
741       }
742     ->
743       {
744         sum = 11;
745         names = ["bar" "foo"];
746       }
748     foldlAttrs
749       (throw "function not needed")
750       123
751       {};
752     ->
753       123
755     foldlAttrs
756       (acc: _: _: acc)
757       3
758       { z = throw "value not needed"; a = throw "value not needed"; };
759     ->
760       3
762     The accumulator doesn't have to be an attrset.
763     It can be as simple as a number or string.
765     foldlAttrs
766       (acc: _: v: acc * 10 + v)
767       1
768       { z = 1; a = 2; };
769     ->
770       121
771     ```
773     :::
774   */
775   foldlAttrs = f: init: set:
776     foldl'
777       (acc: name: f acc name set.${name})
778       init
779       (attrNames set);
781   /**
782     Apply fold functions to values grouped by key.
785     # Inputs
787     `op`
789     : A function, given a value and a collector combines the two.
791     `nul`
793     : The starting value.
795     `list_of_attrs`
797     : A list of attribute sets to fold together by key.
799     # Type
801     ```
802     foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any
803     ```
805     # Examples
806     :::{.example}
807     ## `lib.attrsets.foldAttrs` usage example
809     ```nix
810     foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }]
811     => { a = [ 2 3 ]; }
812     ```
814     :::
815   */
816   foldAttrs =
817     op:
818     nul:
819     list_of_attrs:
820     foldr (n: a:
821         foldr (name: o:
822           o // { ${name} = op n.${name} (a.${name} or nul); }
823         ) a (attrNames n)
824     ) {} list_of_attrs;
827   /**
828     Recursively collect sets that verify a given predicate named `pred`
829     from the set `attrs`. The recursion is stopped when the predicate is
830     verified.
833     # Inputs
835     `pred`
837     : Given an attribute's value, determine if recursion should stop.
839     `attrs`
841     : The attribute set to recursively collect.
843     # Type
845     ```
846     collect :: (AttrSet -> Bool) -> AttrSet -> [x]
847     ```
849     # Examples
850     :::{.example}
851     ## `lib.attrsets.collect` usage example
853     ```nix
854     collect isList { a = { b = ["b"]; }; c = [1]; }
855     => [["b"] [1]]
857     collect (x: x ? outPath)
858        { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
859     => [{ outPath = "a/"; } { outPath = "b/"; }]
860     ```
862     :::
863   */
864   collect =
865     pred:
866     attrs:
867     if pred attrs then
868       [ attrs ]
869     else if isAttrs attrs then
870       concatMap (collect pred) (attrValues attrs)
871     else
872       [];
874   /**
875     Return the cartesian product of attribute set value combinations.
878     # Inputs
880     `attrsOfLists`
882     : Attribute set with attributes that are lists of values
884     # Type
886     ```
887     cartesianProduct :: AttrSet -> [AttrSet]
888     ```
890     # Examples
891     :::{.example}
892     ## `lib.attrsets.cartesianProduct` usage example
894     ```nix
895     cartesianProduct { a = [ 1 2 ]; b = [ 10 20 ]; }
896     => [
897          { a = 1; b = 10; }
898          { a = 1; b = 20; }
899          { a = 2; b = 10; }
900          { a = 2; b = 20; }
901        ]
902     ```
904     :::
905   */
906   cartesianProduct =
907     attrsOfLists:
908     foldl' (listOfAttrs: attrName:
909       concatMap (attrs:
910         map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
911       ) listOfAttrs
912     ) [{}] (attrNames attrsOfLists);
915   /**
916     Return the result of function f applied to the cartesian product of attribute set value combinations.
917     Equivalent to using cartesianProduct followed by map.
919     # Inputs
921     `f`
923     : A function, given an attribute set, it returns a new value.
925     `attrsOfLists`
927     : Attribute set with attributes that are lists of values
929     # Type
931     ```
932     mapCartesianProduct :: (AttrSet -> a) -> AttrSet -> [a]
933     ```
935     # Examples
936     :::{.example}
937     ## `lib.attrsets.mapCartesianProduct` usage example
939     ```nix
940     mapCartesianProduct ({a, b}: "${a}-${b}") { a = [ "1" "2" ]; b = [ "3" "4" ]; }
941     => [ "1-3" "1-4" "2-3" "2-4" ]
942     ```
944     :::
946   */
947   mapCartesianProduct = f: attrsOfLists: map f (cartesianProduct attrsOfLists);
949   /**
950     Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`.
953     # Inputs
955     `name`
957     : Attribute name
959     `value`
961     : Attribute value
963     # Type
965     ```
966     nameValuePair :: String -> Any -> { name :: String; value :: Any; }
967     ```
969     # Examples
970     :::{.example}
971     ## `lib.attrsets.nameValuePair` usage example
973     ```nix
974     nameValuePair "some" 6
975     => { name = "some"; value = 6; }
976     ```
978     :::
979   */
980   nameValuePair =
981     name:
982     value:
983     { inherit name value; };
986   /**
987     Apply a function to each element in an attribute set, creating a new attribute set.
989     # Inputs
991     `f`
993     : A function that takes an attribute name and its value, and returns the new value for the attribute.
995     `attrset`
997     : The attribute set to iterate through.
999     # Type
1001     ```
1002     mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet
1003     ```
1005     # Examples
1006     :::{.example}
1007     ## `lib.attrsets.mapAttrs` usage example
1009     ```nix
1010     mapAttrs (name: value: name + "-" + value)
1011        { x = "foo"; y = "bar"; }
1012     => { x = "x-foo"; y = "y-bar"; }
1013     ```
1015     :::
1016   */
1017   mapAttrs = builtins.mapAttrs;
1020   /**
1021     Like `mapAttrs`, but allows the name of each attribute to be
1022     changed in addition to the value.  The applied function should
1023     return both the new name and value as a `nameValuePair`.
1026     # Inputs
1028     `f`
1030     : A function, given an attribute's name and value, returns a new `nameValuePair`.
1032     `set`
1034     : Attribute set to map over.
1036     # Type
1038     ```
1039     mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet
1040     ```
1042     # Examples
1043     :::{.example}
1044     ## `lib.attrsets.mapAttrs'` usage example
1046     ```nix
1047     mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
1048        { x = "a"; y = "b"; }
1049     => { foo_x = "bar-a"; foo_y = "bar-b"; }
1050     ```
1052     :::
1053   */
1054   mapAttrs' =
1055     f:
1056     set:
1057     listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
1060   /**
1061     Call a function for each attribute in the given set and return
1062     the result in a list.
1064     # Inputs
1066     `f`
1068     : A function, given an attribute's name and value, returns a new value.
1070     `attrs`
1072     : Attribute set to map over.
1074     # Type
1076     ```
1077     mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b]
1078     ```
1080     # Examples
1081     :::{.example}
1082     ## `lib.attrsets.mapAttrsToList` usage example
1084     ```nix
1085     mapAttrsToList (name: value: name + value)
1086        { x = "a"; y = "b"; }
1087     => [ "xa" "yb" ]
1088     ```
1090     :::
1091   */
1092   mapAttrsToList =
1093     f:
1094     attrs:
1095     map (name: f name attrs.${name}) (attrNames attrs);
1097   /**
1098     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).
1099     Each element of the resulting list is an attribute set with these attributes:
1100     - `name` (string): The name of the attribute
1101     - `value` (any): The value of the attribute
1103     The following is always true:
1104     ```nix
1105     builtins.listToAttrs (attrsToList attrs) == attrs
1106     ```
1108     :::{.warning}
1109     The opposite is not always true. In general expect that
1110     ```nix
1111     attrsToList (builtins.listToAttrs list) != list
1112     ```
1114     This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
1115     :::
1117     # Inputs
1119     `set`
1121     : The attribute set to deconstruct.
1123     # Type
1125     ```
1126     attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
1127     ```
1129     # Examples
1130     :::{.example}
1131     ## `lib.attrsets.attrsToList` usage example
1133     ```nix
1134     attrsToList { foo = 1; bar = "asdf"; }
1135     => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
1136     ```
1138     :::
1139   */
1140   attrsToList = mapAttrsToList nameValuePair;
1143   /**
1144     Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set:
1145     the second argument of the function will never be an attrset.
1146     Also, the first argument of the mapping function is a *list* of the attribute names that form the path to the leaf attribute.
1148     For a function that gives you control over what counts as a leaf, see `mapAttrsRecursiveCond`.
1150     :::{#map-attrs-recursive-example .example}
1151     # Map over leaf attributes
1153     ```nix
1154     mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
1155       { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
1156     ```
1157     evaluates to
1158     ```nix
1159     { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
1160     ```
1161     :::
1163     # Type
1164     ```
1165     mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
1166     ```
1167   */
1168   mapAttrsRecursive =
1169     f:
1170     set:
1171     mapAttrsRecursiveCond (as: true) f set;
1174   /**
1175     Like `mapAttrsRecursive`, but it takes an additional predicate that tells it whether to recurse into an attribute set.
1176     If the predicate returns false, `mapAttrsRecursiveCond` does not recurse, but instead applies the mapping function.
1177     If the predicate returns true, it does recurse, and does not apply the mapping function.
1179     :::{#map-attrs-recursive-cond-example .example}
1180     # Map over an leaf attributes defined by a condition
1182     Map derivations to their `name` attribute.
1183     Derivatons are identified as attribute sets that contain `{ type = "derivation"; }`.
1184     ```nix
1185     mapAttrsRecursiveCond
1186       (as: !(as ? "type" && as.type == "derivation"))
1187       (x: x.name)
1188       attrs
1189     ```
1190     :::
1192     # Type
1193     ```
1194     mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
1195     ```
1196   */
1197   mapAttrsRecursiveCond =
1198     cond:
1199     f:
1200     set:
1201     let
1202       recurse = path:
1203         mapAttrs
1204           (name: value:
1205             if isAttrs value && cond value
1206             then recurse (path ++ [ name ]) value
1207             else f (path ++ [ name ]) value);
1208     in
1209     recurse [ ] set;
1212   /**
1213     Generate an attribute set by mapping a function over a list of
1214     attribute names.
1217     # Inputs
1219     `names`
1221     : Names of values in the resulting attribute set.
1223     `f`
1225     : A function, given the name of the attribute, returns the attribute's value.
1227     # Type
1229     ```
1230     genAttrs :: [ String ] -> (String -> Any) -> AttrSet
1231     ```
1233     # Examples
1234     :::{.example}
1235     ## `lib.attrsets.genAttrs` usage example
1237     ```nix
1238     genAttrs [ "foo" "bar" ] (name: "x_" + name)
1239     => { foo = "x_foo"; bar = "x_bar"; }
1240     ```
1242     :::
1243   */
1244   genAttrs =
1245     names:
1246     f:
1247     listToAttrs (map (n: nameValuePair n (f n)) names);
1250   /**
1251     Check whether the argument is a derivation. Any set with
1252     `{ type = "derivation"; }` counts as a derivation.
1255     # Inputs
1257     `value`
1259     : Value to check.
1261     # Type
1263     ```
1264     isDerivation :: Any -> Bool
1265     ```
1267     # Examples
1268     :::{.example}
1269     ## `lib.attrsets.isDerivation` usage example
1271     ```nix
1272     nixpkgs = import <nixpkgs> {}
1273     isDerivation nixpkgs.ruby
1274     => true
1275     isDerivation "foobar"
1276     => false
1277     ```
1279     :::
1280   */
1281   isDerivation =
1282     value: value.type or null == "derivation";
1284    /**
1285     Converts a store path to a fake derivation.
1288     # Inputs
1290     `path`
1292     : A store path to convert to a derivation.
1294     # Type
1296     ```
1297     toDerivation :: Path -> Derivation
1298     ```
1299   */
1300    toDerivation =
1301      path:
1302      let
1303        path' = builtins.storePath path;
1304        res =
1305          { type = "derivation";
1306            name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
1307            outPath = path';
1308            outputs = [ "out" ];
1309            out = res;
1310            outputName = "out";
1311          };
1312     in res;
1315   /**
1316     If `cond` is true, return the attribute set `as`,
1317     otherwise an empty attribute set.
1320     # Inputs
1322     `cond`
1324     : Condition under which the `as` attribute set is returned.
1326     `as`
1328     : The attribute set to return if `cond` is `true`.
1330     # Type
1332     ```
1333     optionalAttrs :: Bool -> AttrSet -> AttrSet
1334     ```
1336     # Examples
1337     :::{.example}
1338     ## `lib.attrsets.optionalAttrs` usage example
1340     ```nix
1341     optionalAttrs (true) { my = "set"; }
1342     => { my = "set"; }
1343     optionalAttrs (false) { my = "set"; }
1344     => { }
1345     ```
1347     :::
1348   */
1349   optionalAttrs =
1350     cond:
1351     as:
1352     if cond then as else {};
1355   /**
1356     Merge sets of attributes and use the function `f` to merge attributes
1357     values.
1360     # Inputs
1362     `names`
1364     : List of attribute names to zip.
1366     `f`
1368     : A function, accepts an attribute name, all the values, and returns a combined value.
1370     `sets`
1372     : List of values from the list of attribute sets.
1374     # Type
1376     ```
1377     zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1378     ```
1380     # Examples
1381     :::{.example}
1382     ## `lib.attrsets.zipAttrsWithNames` usage example
1384     ```nix
1385     zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
1386     => { a = ["x" "y"]; }
1387     ```
1389     :::
1390   */
1391   zipAttrsWithNames =
1392     names:
1393     f:
1394     sets:
1395     listToAttrs (map (name: {
1396       inherit name;
1397       value = f name (catAttrs name sets);
1398     }) names);
1401   /**
1402     Merge sets of attributes and use the function f to merge attribute values.
1403     Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`.
1405     Implementation note: Common names appear multiple times in the list of
1406     names, hopefully this does not affect the system because the maximal
1407     laziness avoid computing twice the same expression and `listToAttrs` does
1408     not care about duplicated attribute names.
1410     # Type
1412     ```
1413     zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
1414     ```
1416     # Examples
1417     :::{.example}
1418     ## `lib.attrsets.zipAttrsWith` usage example
1420     ```nix
1421     zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
1422     => { a = ["x" "y"]; b = ["z"]; }
1423     ```
1425     :::
1426   */
1427   zipAttrsWith =
1428     builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets);
1431   /**
1432     Merge sets of attributes and combine each attribute value in to a list.
1434     Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function.
1436     # Type
1438     ```
1439     zipAttrs :: [ AttrSet ] -> AttrSet
1440     ```
1442     # Examples
1443     :::{.example}
1444     ## `lib.attrsets.zipAttrs` usage example
1446     ```nix
1447     zipAttrs [{a = "x";} {a = "y"; b = "z";}]
1448     => { a = ["x" "y"]; b = ["z"]; }
1449     ```
1451     :::
1452   */
1453   zipAttrs = zipAttrsWith (name: values: values);
1455   /**
1456     Merge a list of attribute sets together using the `//` operator.
1457     In case of duplicate attributes, values from later list elements take precedence over earlier ones.
1458     The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs.
1459     For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n).
1462     # Inputs
1464     `list`
1466     : 1\. Function argument
1468     # Type
1470     ```
1471     mergeAttrsList :: [ Attrs ] -> Attrs
1472     ```
1474     # Examples
1475     :::{.example}
1476     ## `lib.attrsets.mergeAttrsList` usage example
1478     ```nix
1479     mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]
1480     => { a = 0; b = 1; c = 2; d = 3; }
1481     mergeAttrsList [ { a = 0; } { a = 1; } ]
1482     => { a = 1; }
1483     ```
1485     :::
1486   */
1487   mergeAttrsList = list:
1488     let
1489       # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
1490       # Type: Int -> Int -> Attrs
1491       binaryMerge = start: end:
1492         # assert start < end; # Invariant
1493         if end - start >= 2 then
1494           # If there's at least 2 elements, split the range in two, recurse on each part and merge the result
1495           # The invariant is satisfied because each half will have at least 1 element
1496           binaryMerge start (start + (end - start) / 2)
1497           // binaryMerge (start + (end - start) / 2) end
1498         else
1499           # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
1500           elemAt list start;
1501     in
1502     if list == [ ] then
1503       # Calling binaryMerge as below would not satisfy its invariant
1504       { }
1505     else
1506       binaryMerge 0 (length list);
1509   /**
1510     Does the same as the update operator '//' except that attributes are
1511     merged until the given predicate is verified.  The predicate should
1512     accept 3 arguments which are the path to reach the attribute, a part of
1513     the first attribute set and a part of the second attribute set.  When
1514     the predicate is satisfied, the value of the first attribute set is
1515     replaced by the value of the second attribute set.
1518     # Inputs
1520     `pred`
1522     : 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.
1524     `lhs`
1526     : Left attribute set of the merge.
1528     `rhs`
1530     : Right attribute set of the merge.
1532     # Type
1534     ```
1535     recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
1536     ```
1538     # Examples
1539     :::{.example}
1540     ## `lib.attrsets.recursiveUpdateUntil` usage example
1542     ```nix
1543     recursiveUpdateUntil (path: l: r: path == ["foo"]) {
1544       # first attribute set
1545       foo.bar = 1;
1546       foo.baz = 2;
1547       bar = 3;
1548     } {
1549       #second attribute set
1550       foo.bar = 1;
1551       foo.quz = 2;
1552       baz = 4;
1553     }
1555     => {
1556       foo.bar = 1; # 'foo.*' from the second set
1557       foo.quz = 2; #
1558       bar = 3;     # 'bar' from the first set
1559       baz = 4;     # 'baz' from the second set
1560     }
1561     ```
1563     :::
1564   */
1565   recursiveUpdateUntil =
1566     pred:
1567     lhs:
1568     rhs:
1569     let f = attrPath:
1570       zipAttrsWith (n: values:
1571         let here = attrPath ++ [n]; in
1572         if length values == 1
1573         || pred here (elemAt values 1) (head values) then
1574           head values
1575         else
1576           f here values
1577       );
1578     in f [] [rhs lhs];
1581   /**
1582     A recursive variant of the update operator â€˜//’.  The recursion
1583     stops when one of the attribute values is not an attribute set,
1584     in which case the right hand side value takes precedence over the
1585     left hand side value.
1588     # Inputs
1590     `lhs`
1592     : Left attribute set of the merge.
1594     `rhs`
1596     : Right attribute set of the merge.
1598     # Type
1600     ```
1601     recursiveUpdate :: AttrSet -> AttrSet -> AttrSet
1602     ```
1604     # Examples
1605     :::{.example}
1606     ## `lib.attrsets.recursiveUpdate` usage example
1608     ```nix
1609     recursiveUpdate {
1610       boot.loader.grub.enable = true;
1611       boot.loader.grub.device = "/dev/hda";
1612     } {
1613       boot.loader.grub.device = "";
1614     }
1616     returns: {
1617       boot.loader.grub.enable = true;
1618       boot.loader.grub.device = "";
1619     }
1620     ```
1622     :::
1623   */
1624   recursiveUpdate =
1625     lhs:
1626     rhs:
1627     recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs;
1630   /**
1631     Recurse into every attribute set of the first argument and check that:
1632     - Each attribute path also exists in the second argument.
1633     - If the attribute's value is not a nested attribute set, it must have the same value in the right argument.
1636     # Inputs
1638     `pattern`
1640     : Attribute set structure to match
1642     `attrs`
1644     : Attribute set to check
1646     # Type
1648     ```
1649     matchAttrs :: AttrSet -> AttrSet -> Bool
1650     ```
1652     # Examples
1653     :::{.example}
1654     ## `lib.attrsets.matchAttrs` usage example
1656     ```nix
1657     matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
1658     => true
1659     ```
1661     :::
1662   */
1663   matchAttrs =
1664     pattern:
1665     attrs:
1666     assert isAttrs pattern;
1667     all
1668     ( # Compare equality between `pattern` & `attrs`.
1669       attr:
1670       # Missing attr, not equal.
1671       attrs ? ${attr} && (
1672         let
1673           lhs = pattern.${attr};
1674           rhs = attrs.${attr};
1675         in
1676         # If attrset check recursively
1677         if isAttrs lhs then isAttrs rhs && matchAttrs lhs rhs
1678         else lhs == rhs
1679       )
1680     )
1681     (attrNames pattern);
1683   /**
1684     Override only the attributes that are already present in the old set
1685     useful for deep-overriding.
1688     # Inputs
1690     `old`
1692     : Original attribute set
1694     `new`
1696     : Attribute set with attributes to override in `old`.
1698     # Type
1700     ```
1701     overrideExisting :: AttrSet -> AttrSet -> AttrSet
1702     ```
1704     # Examples
1705     :::{.example}
1706     ## `lib.attrsets.overrideExisting` usage example
1708     ```nix
1709     overrideExisting {} { a = 1; }
1710     => {}
1711     overrideExisting { b = 2; } { a = 1; }
1712     => { b = 2; }
1713     overrideExisting { a = 3; b = 2; } { a = 1; }
1714     => { a = 1; b = 2; }
1715     ```
1717     :::
1718   */
1719   overrideExisting =
1720     old:
1721     new:
1722     mapAttrs (name: value: new.${name} or value) old;
1725   /**
1726     Turns a list of strings into a human-readable description of those
1727     strings represented as an attribute path. The result of this function is
1728     not intended to be machine-readable.
1729     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
1732     # Inputs
1734     `path`
1736     : Attribute path to render to a string
1738     # Type
1740     ```
1741     showAttrPath :: [String] -> String
1742     ```
1744     # Examples
1745     :::{.example}
1746     ## `lib.attrsets.showAttrPath` usage example
1748     ```nix
1749     showAttrPath [ "foo" "10" "bar" ]
1750     => "foo.\"10\".bar"
1751     showAttrPath []
1752     => "<root attribute path>"
1753     ```
1755     :::
1756   */
1757   showAttrPath =
1758     path:
1759     if path == [] then "<root attribute path>"
1760     else concatMapStringsSep "." escapeNixIdentifier path;
1763   /**
1764     Get a package output.
1765     If no output is found, fallback to `.out` and then to the default.
1766     The function is idempotent: `getOutput "b" (getOutput "a" p) == getOutput "a" p`.
1769     # Inputs
1771     `output`
1773     : 1\. Function argument
1775     `pkg`
1777     : 2\. Function argument
1779     # Type
1781     ```
1782     getOutput :: String -> :: Derivation -> Derivation
1783     ```
1785     # Examples
1786     :::{.example}
1787     ## `lib.attrsets.getOutput` usage example
1789     ```nix
1790     "${getOutput "dev" pkgs.openssl}"
1791     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1792     ```
1794     :::
1795   */
1796   getOutput = output: pkg:
1797     if ! pkg ? outputSpecified || ! pkg.outputSpecified
1798       then pkg.${output} or pkg.out or pkg
1799       else pkg;
1801   /**
1802     Get the first of the `outputs` provided by the package, or the default.
1803     This function is alligned with `_overrideFirst()` from the `multiple-outputs.sh` setup hook.
1804     Like `getOutput`, the function is idempotent.
1806     # Inputs
1808     `outputs`
1810     : 1\. Function argument
1812     `pkg`
1814     : 2\. Function argument
1816     # Type
1818     ```
1819     getFirstOutput :: [String] -> Derivation -> Derivation
1820     ```
1822     # Examples
1823     :::{.example}
1824     ## `lib.attrsets.getFirstOutput` usage example
1826     ```nix
1827     "${getFirstOutput [ "include" "dev" ] pkgs.openssl}"
1828     => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r-dev"
1829     ```
1831     :::
1832   */
1833   getFirstOutput =
1834     candidates: pkg:
1835     let
1836       outputs = builtins.filter (name: hasAttr name pkg) candidates;
1837       output = builtins.head outputs;
1838     in
1839     if pkg.outputSpecified or false || outputs == [ ] then
1840       pkg
1841     else
1842       pkg.${output};
1844   /**
1845     Get a package's `bin` output.
1846     If the output does not exist, fallback to `.out` and then to the default.
1848     # Inputs
1850     `pkg`
1852     : The package whose `bin` output will be retrieved.
1854     # Type
1856     ```
1857     getBin :: Derivation -> Derivation
1858     ```
1860     # Examples
1861     :::{.example}
1862     ## `lib.attrsets.getBin` usage example
1864     ```nix
1865     "${getBin pkgs.openssl}"
1866     => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r"
1867     ```
1869     :::
1870   */
1871   getBin = getOutput "bin";
1874   /**
1875     Get a package's `lib` output.
1876     If the output does not exist, fallback to `.out` and then to the default.
1878     # Inputs
1880     `pkg`
1882     : The package whose `lib` output will be retrieved.
1884     # Type
1886     ```
1887     getLib :: Derivation -> Derivation
1888     ```
1890     # Examples
1891     :::{.example}
1892     ## `lib.attrsets.getLib` usage example
1894     ```nix
1895     "${getLib pkgs.openssl}"
1896     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib"
1897     ```
1899     :::
1900   */
1901   getLib = getOutput "lib";
1903   /**
1904     Get a package's `static` output.
1905     If the output does not exist, fallback to `.lib`, then to `.out`, and then to the default.
1907     # Inputs
1909     `pkg`
1911     : The package whose `static` output will be retrieved.
1913     # Type
1915     ```
1916     getStatic :: Derivation -> Derivation
1917     ```
1919     # Examples
1920     :::{.example}
1921     ## `lib.attrsets.getStatic` usage example
1923     ```nix
1924     "${lib.getStatic pkgs.glibc}"
1925     => "/nix/store/00000000000000000000000000000000-glibc-2.39-52-static"
1926     ```
1928     :::
1929   */
1930   getStatic = getFirstOutput [ "static" "lib" "out" ];
1933   /**
1934     Get a package's `dev` output.
1935     If the output does not exist, fallback to `.out` and then to the default.
1937     # Inputs
1939     `pkg`
1941     : The package whose `dev` output will be retrieved.
1943     # Type
1945     ```
1946     getDev :: Derivation -> Derivation
1947     ```
1949     # Examples
1950     :::{.example}
1951     ## `lib.attrsets.getDev` usage example
1953     ```nix
1954     "${getDev pkgs.openssl}"
1955     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1956     ```
1958     :::
1959   */
1960   getDev = getOutput "dev";
1962   /**
1963     Get a package's `include` output.
1964     If the output does not exist, fallback to `.dev`, then to `.out`, and then to the default.
1966     # Inputs
1968     `pkg`
1970     : The package whose `include` output will be retrieved.
1972     # Type
1974     ```
1975     getInclude :: Derivation -> Derivation
1976     ```
1978     # Examples
1979     :::{.example}
1980     ## `lib.attrsets.getInclude` usage example
1982     ```nix
1983     "${getInclude pkgs.openssl}"
1984     => "/nix/store/00000000000000000000000000000000-openssl-1.0.1r-dev"
1985     ```
1987     :::
1988   */
1989   getInclude = getFirstOutput [ "include" "dev" "out" ];
1992   /**
1993     Get a package's `man` output.
1994     If the output does not exist, fallback to `.out` and then to the default.
1996     # Inputs
1998     `pkg`
2000     : The package whose `man` output will be retrieved.
2002     # Type
2004     ```
2005     getMan :: Derivation -> Derivation
2006     ```
2008     # Examples
2009     :::{.example}
2010     ## `lib.attrsets.getMan` usage example
2012     ```nix
2013     "${getMan pkgs.openssl}"
2014     => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man"
2015     ```
2017     :::
2018   */
2019   getMan = getOutput "man";
2021   /**
2022     Pick the outputs of packages to place in `buildInputs`
2024     # Inputs
2026     `pkgs`
2028     : List of packages.
2030     # Type
2032     ```
2033     chooseDevOutputs :: [Derivation] -> [Derivation]
2034     ```
2035   */
2036   chooseDevOutputs = builtins.map getDev;
2038   /**
2039     Make various Nix tools consider the contents of the resulting
2040     attribute set when looking for what to build, find, etc.
2042     This function only affects a single attribute set; it does not
2043     apply itself recursively for nested attribute sets.
2046     # Inputs
2048     `attrs`
2050     : An attribute set to scan for derivations.
2052     # Type
2054     ```
2055     recurseIntoAttrs :: AttrSet -> AttrSet
2056     ```
2058     # Examples
2059     :::{.example}
2060     ## `lib.attrsets.recurseIntoAttrs` usage example
2062     ```nix
2063     { pkgs ? import <nixpkgs> {} }:
2064     {
2065       myTools = pkgs.lib.recurseIntoAttrs {
2066         inherit (pkgs) hello figlet;
2067       };
2068     }
2069     ```
2071     :::
2072   */
2073   recurseIntoAttrs =
2074     attrs:
2075     attrs // { recurseForDerivations = true; };
2077   /**
2078     Undo the effect of recurseIntoAttrs.
2081     # Inputs
2083     `attrs`
2085     : An attribute set to not scan for derivations.
2087     # Type
2089     ```
2090     dontRecurseIntoAttrs :: AttrSet -> AttrSet
2091     ```
2092   */
2093   dontRecurseIntoAttrs =
2094     attrs:
2095     attrs // { recurseForDerivations = false; };
2097   /**
2098     `unionOfDisjoint x y` is equal to `x // y // z` where the
2099     attrnames in `z` are the intersection of the attrnames in `x` and
2100     `y`, and all values `assert` with an error message.  This
2101      operator is commutative, unlike (//).
2104     # Inputs
2106     `x`
2108     : 1\. Function argument
2110     `y`
2112     : 2\. Function argument
2114     # Type
2116     ```
2117     unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet
2118     ```
2119   */
2120   unionOfDisjoint = x: y:
2121     let
2122       intersection = builtins.intersectAttrs x y;
2123       collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
2124       mask = builtins.mapAttrs (name: value: builtins.throw
2125         "unionOfDisjoint: collision on ${name}; complete list: ${collisions}")
2126         intersection;
2127     in
2128       (x // y) // mask;
2130   # DEPRECATED
2131   zipWithNames = warn
2132     "lib.zipWithNames is a deprecated alias of lib.zipAttrsWithNames." zipAttrsWithNames;
2134   # DEPRECATED
2135   zip = warn
2136     "lib.zip is a deprecated alias of lib.zipAttrsWith." zipAttrsWith;
2138   # DEPRECATED
2139   cartesianProductOfSets = warnIf (oldestSupportedReleaseIsAtLeast 2405)
2140     "lib.cartesianProductOfSets is a deprecated alias of lib.cartesianProduct." cartesianProduct;