Merge pull request #270175 from ShamrockLee/backport-23.11-apptainer-localstatedir
[NixPkgs.git] / lib / attrsets.nix
blobbf6c90bf1be60890fabc953c589eee1afb0f0b0e
1 /* Operations on attribute sets. */
2 { lib }:
4 let
5   inherit (builtins) head tail length;
6   inherit (lib.trivial) id mergeAttrs;
7   inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
8   inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all partition groupBy take foldl;
9 in
11 rec {
12   inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr removeAttrs;
15   /* Return an attribute from nested attribute sets.
17      Example:
18        x = { a = { b = 3; }; }
19        # ["a" "b"] is equivalent to x.a.b
20        # 6 is a default value to return if the path does not exist in attrset
21        attrByPath ["a" "b"] 6 x
22        => 3
23        attrByPath ["z" "z"] 6 x
24        => 6
26      Type:
27        attrByPath :: [String] -> Any -> AttrSet -> Any
29   */
30   attrByPath =
31     # A list of strings representing the attribute path to return from `set`
32     attrPath:
33     # Default value if `attrPath` does not resolve to an existing value
34     default:
35     # The nested attribute set to select values from
36     set:
37     let attr = head attrPath;
38     in
39       if attrPath == [] then set
40       else if set ? ${attr}
41       then attrByPath (tail attrPath) default set.${attr}
42       else default;
44   /* Return if an attribute from nested attribute set exists.
46      Example:
47        x = { a = { b = 3; }; }
48        hasAttrByPath ["a" "b"] x
49        => true
50        hasAttrByPath ["z" "z"] x
51        => false
53     Type:
54       hasAttrByPath :: [String] -> AttrSet -> Bool
55   */
56   hasAttrByPath =
57     # A list of strings representing the attribute path to check from `set`
58     attrPath:
59     # The nested attribute set to check
60     e:
61     let attr = head attrPath;
62     in
63       if attrPath == [] then true
64       else if e ? ${attr}
65       then hasAttrByPath (tail attrPath) e.${attr}
66       else false;
69   /* Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
71      Example:
72        setAttrByPath ["a" "b"] 3
73        => { a = { b = 3; }; }
75      Type:
76        setAttrByPath :: [String] -> Any -> AttrSet
77   */
78   setAttrByPath =
79     # A list of strings representing the attribute path to set
80     attrPath:
81     # The value to set at the location described by `attrPath`
82     value:
83     let
84       len = length attrPath;
85       atDepth = n:
86         if n == len
87         then value
88         else { ${elemAt attrPath n} = atDepth (n + 1); };
89     in atDepth 0;
91   /* Like `attrByPath`, but without a default value. If it doesn't find the
92      path it will throw an error.
94      Example:
95        x = { a = { b = 3; }; }
96        getAttrFromPath ["a" "b"] x
97        => 3
98        getAttrFromPath ["z" "z"] x
99        => error: cannot find attribute `z.z'
101      Type:
102        getAttrFromPath :: [String] -> AttrSet -> Any
103   */
104   getAttrFromPath =
105     # A list of strings representing the attribute path to get from `set`
106     attrPath:
107     # The nested attribute set to find the value in.
108     set:
109     let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
110     in attrByPath attrPath (abort errorMsg) set;
112   /* Map each attribute in the given set and merge them into a new attribute set.
114      Type:
115        concatMapAttrs :: (String -> a -> AttrSet) -> AttrSet -> AttrSet
117      Example:
118        concatMapAttrs
119          (name: value: {
120            ${name} = value;
121            ${name + value} = value;
122          })
123          { x = "a"; y = "b"; }
124        => { x = "a"; xa = "a"; y = "b"; yb = "b"; }
125   */
126   concatMapAttrs = f: v:
127     foldl' mergeAttrs { }
128       (attrValues
129         (mapAttrs f v)
130       );
133   /* Update or set specific paths of an attribute set.
135      Takes a list of updates to apply and an attribute set to apply them to,
136      and returns the attribute set with the updates applied. Updates are
137      represented as `{ path = ...; update = ...; }` values, where `path` is a
138      list of strings representing the attribute path that should be updated,
139      and `update` is a function that takes the old value at that attribute path
140      as an argument and returns the new
141      value it should be.
143      Properties:
145      - Updates to deeper attribute paths are applied before updates to more
146        shallow attribute paths
148      - Multiple updates to the same attribute path are applied in the order
149        they appear in the update list
151      - If any but the last `path` element leads into a value that is not an
152        attribute set, an error is thrown
154      - If there is an update for an attribute path that doesn't exist,
155        accessing the argument in the update function causes an error, but
156        intermediate attribute sets are implicitly created as needed
158      Example:
159        updateManyAttrsByPath [
160          {
161            path = [ "a" "b" ];
162            update = old: { d = old.c; };
163          }
164          {
165            path = [ "a" "b" "c" ];
166            update = old: old + 1;
167          }
168          {
169            path = [ "x" "y" ];
170            update = old: "xy";
171          }
172        ] { a.b.c = 0; }
173        => { a = { b = { d = 1; }; }; x = { y = "xy"; }; }
175     Type: updateManyAttrsByPath :: [{ path :: [String]; update :: (Any -> Any); }] -> AttrSet -> AttrSet
176   */
177   updateManyAttrsByPath = let
178     # When recursing into attributes, instead of updating the `path` of each
179     # update using `tail`, which needs to allocate an entirely new list,
180     # we just pass a prefix length to use and make sure to only look at the
181     # path without the prefix length, so that we can reuse the original list
182     # entries.
183     go = prefixLength: hasValue: value: updates:
184       let
185         # Splits updates into ones on this level (split.right)
186         # And ones on levels further down (split.wrong)
187         split = partition (el: length el.path == prefixLength) updates;
189         # Groups updates on further down levels into the attributes they modify
190         nested = groupBy (el: elemAt el.path prefixLength) split.wrong;
192         # Applies only nested modification to the input value
193         withNestedMods =
194           # Return the value directly if we don't have any nested modifications
195           if split.wrong == [] then
196             if hasValue then value
197             else
198               # Throw an error if there is no value. This `head` call here is
199               # safe, but only in this branch since `go` could only be called
200               # with `hasValue == false` for nested updates, in which case
201               # it's also always called with at least one update
202               let updatePath = (head split.right).path; in
203               throw
204               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' does "
205               + "not exist in the given value, but the first update to this "
206               + "path tries to access the existing value.")
207           else
208             # If there are nested modifications, try to apply them to the value
209             if ! hasValue then
210               # But if we don't have a value, just use an empty attribute set
211               # as the value, but simplify the code a bit
212               mapAttrs (name: go (prefixLength + 1) false null) nested
213             else if isAttrs value then
214               # If we do have a value and it's an attribute set, override it
215               # with the nested modifications
216               value //
217               mapAttrs (name: go (prefixLength + 1) (value ? ${name}) value.${name}) nested
218             else
219               # However if it's not an attribute set, we can't apply the nested
220               # modifications, throw an error
221               let updatePath = (head split.wrong).path; in
222               throw
223               ( "updateManyAttrsByPath: Path '${showAttrPath updatePath}' needs to "
224               + "be updated, but path '${showAttrPath (take prefixLength updatePath)}' "
225               + "of the given value is not an attribute set, so we can't "
226               + "update an attribute inside of it.");
228         # We get the final result by applying all the updates on this level
229         # after having applied all the nested updates
230         # We use foldl instead of foldl' so that in case of multiple updates,
231         # intermediate values aren't evaluated if not needed
232       in foldl (acc: el: el.update acc) withNestedMods split.right;
234   in updates: value: go 0 true value updates;
236   /* Return the specified attributes from a set.
238      Example:
239        attrVals ["a" "b" "c"] as
240        => [as.a as.b as.c]
242      Type:
243        attrVals :: [String] -> AttrSet -> [Any]
244   */
245   attrVals =
246     # The list of attributes to fetch from `set`. Each attribute name must exist on the attrbitue set
247     nameList:
248     # The set to get attribute values from
249     set: map (x: set.${x}) nameList;
252   /* Return the values of all attributes in the given set, sorted by
253      attribute name.
255      Example:
256        attrValues {c = 3; a = 1; b = 2;}
257        => [1 2 3]
259      Type:
260        attrValues :: AttrSet -> [Any]
261   */
262   attrValues = builtins.attrValues or (attrs: attrVals (attrNames attrs) attrs);
265   /* Given a set of attribute names, return the set of the corresponding
266      attributes from the given set.
268      Example:
269        getAttrs [ "a" "b" ] { a = 1; b = 2; c = 3; }
270        => { a = 1; b = 2; }
272      Type:
273        getAttrs :: [String] -> AttrSet -> AttrSet
274   */
275   getAttrs =
276     # A list of attribute names to get out of `set`
277     names:
278     # The set to get the named attributes from
279     attrs: genAttrs names (name: attrs.${name});
281   /* Collect each attribute named `attr` from a list of attribute
282      sets.  Sets that don't contain the named attribute are ignored.
284      Example:
285        catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
286        => [1 2]
288      Type:
289        catAttrs :: String -> [AttrSet] -> [Any]
290   */
291   catAttrs = builtins.catAttrs or
292     (attr: l: concatLists (map (s: if s ? ${attr} then [s.${attr}] else []) l));
295   /* Filter an attribute set by removing all attributes for which the
296      given predicate return false.
298      Example:
299        filterAttrs (n: v: n == "foo") { foo = 1; bar = 2; }
300        => { foo = 1; }
302      Type:
303        filterAttrs :: (String -> Any -> Bool) -> AttrSet -> AttrSet
304   */
305   filterAttrs =
306     # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
307     pred:
308     # The attribute set to filter
309     set:
310     listToAttrs (concatMap (name: let v = set.${name}; in if pred name v then [(nameValuePair name v)] else []) (attrNames set));
313   /* Filter an attribute set recursively by removing all attributes for
314      which the given predicate return false.
316      Example:
317        filterAttrsRecursive (n: v: v != null) { foo = { bar = null; }; }
318        => { foo = {}; }
320      Type:
321        filterAttrsRecursive :: (String -> Any -> Bool) -> AttrSet -> AttrSet
322   */
323   filterAttrsRecursive =
324     # Predicate taking an attribute name and an attribute value, which returns `true` to include the attribute, or `false` to exclude the attribute.
325     pred:
326     # The attribute set to filter
327     set:
328     listToAttrs (
329       concatMap (name:
330         let v = set.${name}; in
331         if pred name v then [
332           (nameValuePair name (
333             if isAttrs v then filterAttrsRecursive pred v
334             else v
335           ))
336         ] else []
337       ) (attrNames set)
338     );
340    /*
341     Like [`lib.lists.foldl'`](#function-library-lib.lists.foldl-prime) but for attribute sets.
342     Iterates over every name-value pair in the given attribute set.
343     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`.
345     Attention:
346       There is a completely different function
347       `lib.foldAttrs`
348       which has nothing to do with this function, despite the similar name.
350     Example:
351       foldlAttrs
352         (acc: name: value: {
353           sum = acc.sum + value;
354           names = acc.names ++ [name];
355         })
356         { sum = 0; names = []; }
357         {
358           foo = 1;
359           bar = 10;
360         }
361       ->
362         {
363           sum = 11;
364           names = ["bar" "foo"];
365         }
367       foldlAttrs
368         (throw "function not needed")
369         123
370         {};
371       ->
372         123
374       foldlAttrs
375         (acc: _: _: acc)
376         3
377         { z = throw "value not needed"; a = throw "value not needed"; };
378       ->
379         3
381       The accumulator doesn't have to be an attrset.
382       It can be as simple as a number or string.
384       foldlAttrs
385         (acc: _: v: acc * 10 + v)
386         1
387         { z = 1; a = 2; };
388       ->
389         121
391     Type:
392       foldlAttrs :: ( a -> String -> b -> a ) -> a -> { ... :: b } -> a
393   */
394   foldlAttrs = f: init: set:
395     foldl'
396       (acc: name: f acc name set.${name})
397       init
398       (attrNames set);
400   /* Apply fold functions to values grouped by key.
402      Example:
403        foldAttrs (item: acc: [item] ++ acc) [] [{ a = 2; } { a = 3; }]
404        => { a = [ 2 3 ]; }
406      Type:
407        foldAttrs :: (Any -> Any -> Any) -> Any -> [AttrSets] -> Any
409   */
410   foldAttrs =
411     # A function, given a value and a collector combines the two.
412     op:
413     # The starting value.
414     nul:
415     # A list of attribute sets to fold together by key.
416     list_of_attrs:
417     foldr (n: a:
418         foldr (name: o:
419           o // { ${name} = op n.${name} (a.${name} or nul); }
420         ) a (attrNames n)
421     ) {} list_of_attrs;
424   /* Recursively collect sets that verify a given predicate named `pred`
425      from the set `attrs`.  The recursion is stopped when the predicate is
426      verified.
428      Example:
429        collect isList { a = { b = ["b"]; }; c = [1]; }
430        => [["b"] [1]]
432        collect (x: x ? outPath)
433           { a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
434        => [{ outPath = "a/"; } { outPath = "b/"; }]
436      Type:
437        collect :: (AttrSet -> Bool) -> AttrSet -> [x]
438   */
439   collect =
440   # Given an attribute's value, determine if recursion should stop.
441   pred:
442   # The attribute set to recursively collect.
443   attrs:
444     if pred attrs then
445       [ attrs ]
446     else if isAttrs attrs then
447       concatMap (collect pred) (attrValues attrs)
448     else
449       [];
451   /* Return the cartesian product of attribute set value combinations.
453     Example:
454       cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; }
455       => [
456            { a = 1; b = 10; }
457            { a = 1; b = 20; }
458            { a = 2; b = 10; }
459            { a = 2; b = 20; }
460          ]
461      Type:
462        cartesianProductOfSets :: AttrSet -> [AttrSet]
463   */
464   cartesianProductOfSets =
465     # Attribute set with attributes that are lists of values
466     attrsOfLists:
467     foldl' (listOfAttrs: attrName:
468       concatMap (attrs:
469         map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
470       ) listOfAttrs
471     ) [{}] (attrNames attrsOfLists);
474   /* Utility function that creates a `{name, value}` pair as expected by `builtins.listToAttrs`.
476      Example:
477        nameValuePair "some" 6
478        => { name = "some"; value = 6; }
480      Type:
481        nameValuePair :: String -> Any -> { name :: String; value :: Any; }
482   */
483   nameValuePair =
484     # Attribute name
485     name:
486     # Attribute value
487     value:
488     { inherit name value; };
491   /* Apply a function to each element in an attribute set, creating a new attribute set.
493      Example:
494        mapAttrs (name: value: name + "-" + value)
495           { x = "foo"; y = "bar"; }
496        => { x = "x-foo"; y = "y-bar"; }
498      Type:
499        mapAttrs :: (String -> Any -> Any) -> AttrSet -> AttrSet
500   */
501   mapAttrs = builtins.mapAttrs or
502     (f: set:
503       listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)));
506   /* Like `mapAttrs`, but allows the name of each attribute to be
507      changed in addition to the value.  The applied function should
508      return both the new name and value as a `nameValuePair`.
510      Example:
511        mapAttrs' (name: value: nameValuePair ("foo_" + name) ("bar-" + value))
512           { x = "a"; y = "b"; }
513        => { foo_x = "bar-a"; foo_y = "bar-b"; }
515      Type:
516        mapAttrs' :: (String -> Any -> { name :: String; value :: Any; }) -> AttrSet -> AttrSet
517   */
518   mapAttrs' =
519     # A function, given an attribute's name and value, returns a new `nameValuePair`.
520     f:
521     # Attribute set to map over.
522     set:
523     listToAttrs (map (attr: f attr set.${attr}) (attrNames set));
526   /* Call a function for each attribute in the given set and return
527      the result in a list.
529      Example:
530        mapAttrsToList (name: value: name + value)
531           { x = "a"; y = "b"; }
532        => [ "xa" "yb" ]
534      Type:
535        mapAttrsToList :: (String -> a -> b) -> AttrSet -> [b]
537   */
538   mapAttrsToList =
539     # A function, given an attribute's name and value, returns a new value.
540     f:
541     # Attribute set to map over.
542     attrs:
543     map (name: f name attrs.${name}) (attrNames attrs);
545   /*
546     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).
547     Each element of the resulting list is an attribute set with these attributes:
548     - `name` (string): The name of the attribute
549     - `value` (any): The value of the attribute
551     The following is always true:
552     ```nix
553     builtins.listToAttrs (attrsToList attrs) == attrs
554     ```
556     :::{.warning}
557     The opposite is not always true. In general expect that
558     ```nix
559     attrsToList (builtins.listToAttrs list) != list
560     ```
562     This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
563     :::
565     Example:
566       attrsToList { foo = 1; bar = "asdf"; }
567       => [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
569     Type:
570       attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
572   */
573   attrsToList = mapAttrsToList nameValuePair;
576   /* Like `mapAttrs`, except that it recursively applies itself to
577      the *leaf* attributes of a potentially-nested attribute set:
578      the second argument of the function will never be an attrset.
579      Also, the first argument of the argument function is a *list*
580      of the attribute names that form the path to the leaf attribute.
582      For a function that gives you control over what counts as a leaf,
583      see `mapAttrsRecursiveCond`.
585      Example:
586        mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
587          { n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
588        => { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
590      Type:
591        mapAttrsRecursive :: ([String] -> a -> b) -> AttrSet -> AttrSet
592   */
593   mapAttrsRecursive =
594     # A function, given a list of attribute names and a value, returns a new value.
595     f:
596     # Set to recursively map over.
597     set:
598     mapAttrsRecursiveCond (as: true) f set;
601   /* Like `mapAttrsRecursive`, but it takes an additional predicate
602      function that tells it whether to recurse into an attribute
603      set.  If it returns false, `mapAttrsRecursiveCond` does not
604      recurse, but does apply the map function.  If it returns true, it
605      does recurse, and does not apply the map function.
607      Example:
608        # To prevent recursing into derivations (which are attribute
609        # sets with the attribute "type" equal to "derivation"):
610        mapAttrsRecursiveCond
611          (as: !(as ? "type" && as.type == "derivation"))
612          (x: ... do something ...)
613          attrs
615      Type:
616        mapAttrsRecursiveCond :: (AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
617   */
618   mapAttrsRecursiveCond =
619     # A function, given the attribute set the recursion is currently at, determine if to recurse deeper into that attribute set.
620     cond:
621     # A function, given a list of attribute names and a value, returns a new value.
622     f:
623     # Attribute set to recursively map over.
624     set:
625     let
626       recurse = path:
627         let
628           g =
629             name: value:
630             if isAttrs value && cond value
631               then recurse (path ++ [name]) value
632               else f (path ++ [name]) value;
633         in mapAttrs g;
634     in recurse [] set;
637   /* Generate an attribute set by mapping a function over a list of
638      attribute names.
640      Example:
641        genAttrs [ "foo" "bar" ] (name: "x_" + name)
642        => { foo = "x_foo"; bar = "x_bar"; }
644      Type:
645        genAttrs :: [ String ] -> (String -> Any) -> AttrSet
646   */
647   genAttrs =
648     # Names of values in the resulting attribute set.
649     names:
650     # A function, given the name of the attribute, returns the attribute's value.
651     f:
652     listToAttrs (map (n: nameValuePair n (f n)) names);
655   /* Check whether the argument is a derivation. Any set with
656      `{ type = "derivation"; }` counts as a derivation.
658      Example:
659        nixpkgs = import <nixpkgs> {}
660        isDerivation nixpkgs.ruby
661        => true
662        isDerivation "foobar"
663        => false
665      Type:
666        isDerivation :: Any -> Bool
667   */
668   isDerivation =
669     # Value to check.
670     value: value.type or null == "derivation";
672    /* Converts a store path to a fake derivation.
674       Type:
675         toDerivation :: Path -> Derivation
676    */
677    toDerivation =
678      # A store path to convert to a derivation.
679      path:
680      let
681        path' = builtins.storePath path;
682        res =
683          { type = "derivation";
684            name = sanitizeDerivationName (builtins.substring 33 (-1) (baseNameOf path'));
685            outPath = path';
686            outputs = [ "out" ];
687            out = res;
688            outputName = "out";
689          };
690     in res;
693   /* If `cond` is true, return the attribute set `as`,
694      otherwise an empty attribute set.
696      Example:
697        optionalAttrs (true) { my = "set"; }
698        => { my = "set"; }
699        optionalAttrs (false) { my = "set"; }
700        => { }
702      Type:
703        optionalAttrs :: Bool -> AttrSet -> AttrSet
704   */
705   optionalAttrs =
706     # Condition under which the `as` attribute set is returned.
707     cond:
708     # The attribute set to return if `cond` is `true`.
709     as:
710     if cond then as else {};
713   /* Merge sets of attributes and use the function `f` to merge attributes
714      values.
716      Example:
717        zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
718        => { a = ["x" "y"]; }
720      Type:
721        zipAttrsWithNames :: [ String ] -> (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
722   */
723   zipAttrsWithNames =
724     # List of attribute names to zip.
725     names:
726     # A function, accepts an attribute name, all the values, and returns a combined value.
727     f:
728     # List of values from the list of attribute sets.
729     sets:
730     listToAttrs (map (name: {
731       inherit name;
732       value = f name (catAttrs name sets);
733     }) names);
736   /* Merge sets of attributes and use the function f to merge attribute values.
737      Like `lib.attrsets.zipAttrsWithNames` with all key names are passed for `names`.
739      Implementation note: Common names appear multiple times in the list of
740      names, hopefully this does not affect the system because the maximal
741      laziness avoid computing twice the same expression and `listToAttrs` does
742      not care about duplicated attribute names.
744      Example:
745        zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
746        => { a = ["x" "y"]; b = ["z"]; }
748      Type:
749        zipAttrsWith :: (String -> [ Any ] -> Any) -> [ AttrSet ] -> AttrSet
750   */
751   zipAttrsWith =
752     builtins.zipAttrsWith or (f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets);
755   /* Merge sets of attributes and combine each attribute value in to a list.
757      Like `lib.attrsets.zipAttrsWith` with `(name: values: values)` as the function.
759      Example:
760        zipAttrs [{a = "x";} {a = "y"; b = "z";}]
761        => { a = ["x" "y"]; b = ["z"]; }
763      Type:
764        zipAttrs :: [ AttrSet ] -> AttrSet
765   */
766   zipAttrs =
767     # List of attribute sets to zip together.
768     sets:
769     zipAttrsWith (name: values: values) sets;
771   /*
772     Merge a list of attribute sets together using the `//` operator.
773     In case of duplicate attributes, values from later list elements take precedence over earlier ones.
774     The result is the same as `foldl mergeAttrs { }`, but the performance is better for large inputs.
775     For n list elements, each with an attribute set containing m unique attributes, the complexity of this operation is O(nm log n).
777     Type:
778       mergeAttrsList :: [ Attrs ] -> Attrs
780     Example:
781       mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]
782       => { a = 0; b = 1; c = 2; d = 3; }
783       mergeAttrsList [ { a = 0; } { a = 1; } ]
784       => { a = 1; }
785   */
786   mergeAttrsList = list:
787     let
788       # `binaryMerge start end` merges the elements at indices `index` of `list` such that `start <= index < end`
789       # Type: Int -> Int -> Attrs
790       binaryMerge = start: end:
791         # assert start < end; # Invariant
792         if end - start >= 2 then
793           # If there's at least 2 elements, split the range in two, recurse on each part and merge the result
794           # The invariant is satisfied because each half will have at least 1 element
795           binaryMerge start (start + (end - start) / 2)
796           // binaryMerge (start + (end - start) / 2) end
797         else
798           # Otherwise there will be exactly 1 element due to the invariant, in which case we just return it directly
799           elemAt list start;
800     in
801     if list == [ ] then
802       # Calling binaryMerge as below would not satisfy its invariant
803       { }
804     else
805       binaryMerge 0 (length list);
808   /* Does the same as the update operator '//' except that attributes are
809      merged until the given predicate is verified.  The predicate should
810      accept 3 arguments which are the path to reach the attribute, a part of
811      the first attribute set and a part of the second attribute set.  When
812      the predicate is satisfied, the value of the first attribute set is
813      replaced by the value of the second attribute set.
815      Example:
816        recursiveUpdateUntil (path: l: r: path == ["foo"]) {
817          # first attribute set
818          foo.bar = 1;
819          foo.baz = 2;
820          bar = 3;
821        } {
822          #second attribute set
823          foo.bar = 1;
824          foo.quz = 2;
825          baz = 4;
826        }
828        => {
829          foo.bar = 1; # 'foo.*' from the second set
830          foo.quz = 2; #
831          bar = 3;     # 'bar' from the first set
832          baz = 4;     # 'baz' from the second set
833        }
835      Type:
836        recursiveUpdateUntil :: ( [ String ] -> AttrSet -> AttrSet -> Bool ) -> AttrSet -> AttrSet -> AttrSet
837   */
838   recursiveUpdateUntil =
839     # 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.
840     pred:
841     # Left attribute set of the merge.
842     lhs:
843     # Right attribute set of the merge.
844     rhs:
845     let f = attrPath:
846       zipAttrsWith (n: values:
847         let here = attrPath ++ [n]; in
848         if length values == 1
849         || pred here (elemAt values 1) (head values) then
850           head values
851         else
852           f here values
853       );
854     in f [] [rhs lhs];
857   /* A recursive variant of the update operator ‘//’.  The recursion
858      stops when one of the attribute values is not an attribute set,
859      in which case the right hand side value takes precedence over the
860      left hand side value.
862      Example:
863        recursiveUpdate {
864          boot.loader.grub.enable = true;
865          boot.loader.grub.device = "/dev/hda";
866        } {
867          boot.loader.grub.device = "";
868        }
870        returns: {
871          boot.loader.grub.enable = true;
872          boot.loader.grub.device = "";
873        }
875      Type:
876        recursiveUpdate :: AttrSet -> AttrSet -> AttrSet
877   */
878   recursiveUpdate =
879     # Left attribute set of the merge.
880     lhs:
881     # Right attribute set of the merge.
882     rhs:
883     recursiveUpdateUntil (path: lhs: rhs: !(isAttrs lhs && isAttrs rhs)) lhs rhs;
886   /* Returns true if the pattern is contained in the set. False otherwise.
888      Example:
889        matchAttrs { cpu = {}; } { cpu = { bits = 64; }; }
890        => true
892      Type:
893        matchAttrs :: AttrSet -> AttrSet -> Bool
894   */
895   matchAttrs =
896     # Attribute set structure to match
897     pattern:
898     # Attribute set to find patterns in
899     attrs:
900     assert isAttrs pattern;
901     all id (attrValues (zipAttrsWithNames (attrNames pattern) (n: values:
902       let pat = head values; val = elemAt values 1; in
903       if length values == 1 then false
904       else if isAttrs pat then isAttrs val && matchAttrs pat val
905       else pat == val
906     ) [pattern attrs]));
909   /* Override only the attributes that are already present in the old set
910     useful for deep-overriding.
912     Example:
913       overrideExisting {} { a = 1; }
914       => {}
915       overrideExisting { b = 2; } { a = 1; }
916       => { b = 2; }
917       overrideExisting { a = 3; b = 2; } { a = 1; }
918       => { a = 1; b = 2; }
920     Type:
921       overrideExisting :: AttrSet -> AttrSet -> AttrSet
922   */
923   overrideExisting =
924     # Original attribute set
925     old:
926     # Attribute set with attributes to override in `old`.
927     new:
928     mapAttrs (name: value: new.${name} or value) old;
931   /* Turns a list of strings into a human-readable description of those
932     strings represented as an attribute path. The result of this function is
933     not intended to be machine-readable.
934     Create a new attribute set with `value` set at the nested attribute location specified in `attrPath`.
936     Example:
937       showAttrPath [ "foo" "10" "bar" ]
938       => "foo.\"10\".bar"
939       showAttrPath []
940       => "<root attribute path>"
942     Type:
943       showAttrPath :: [String] -> String
944   */
945   showAttrPath =
946     # Attribute path to render to a string
947     path:
948     if path == [] then "<root attribute path>"
949     else concatMapStringsSep "." escapeNixIdentifier path;
952   /* Get a package output.
953      If no output is found, fallback to `.out` and then to the default.
955      Example:
956        getOutput "dev" pkgs.openssl
957        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
959      Type:
960        getOutput :: String -> Derivation -> String
961   */
962   getOutput = output: pkg:
963     if ! pkg ? outputSpecified || ! pkg.outputSpecified
964       then pkg.${output} or pkg.out or pkg
965       else pkg;
967   /* Get a package's `bin` output.
968      If the output does not exist, fallback to `.out` and then to the default.
970      Example:
971        getBin pkgs.openssl
972        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r"
974      Type:
975        getBin :: Derivation -> String
976   */
977   getBin = getOutput "bin";
980   /* Get a package's `lib` output.
981      If the output does not exist, fallback to `.out` and then to the default.
983      Example:
984        getLib pkgs.openssl
985        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-lib"
987      Type:
988        getLib :: Derivation -> String
989   */
990   getLib = getOutput "lib";
993   /* Get a package's `dev` output.
994      If the output does not exist, fallback to `.out` and then to the default.
996      Example:
997        getDev pkgs.openssl
998        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-dev"
1000      Type:
1001        getDev :: Derivation -> String
1002   */
1003   getDev = getOutput "dev";
1006   /* Get a package's `man` output.
1007      If the output does not exist, fallback to `.out` and then to the default.
1009      Example:
1010        getMan pkgs.openssl
1011        => "/nix/store/9rz8gxhzf8sw4kf2j2f1grr49w8zx5vj-openssl-1.0.1r-man"
1013      Type:
1014        getMan :: Derivation -> String
1015   */
1016   getMan = getOutput "man";
1018   /* Pick the outputs of packages to place in `buildInputs`
1020    Type: chooseDevOutputs :: [Derivation] -> [String]
1022   */
1023   chooseDevOutputs =
1024     # List of packages to pick `dev` outputs from
1025     drvs:
1026     builtins.map getDev drvs;
1028   /* Make various Nix tools consider the contents of the resulting
1029      attribute set when looking for what to build, find, etc.
1031      This function only affects a single attribute set; it does not
1032      apply itself recursively for nested attribute sets.
1034      Example:
1035        { pkgs ? import <nixpkgs> {} }:
1036        {
1037          myTools = pkgs.lib.recurseIntoAttrs {
1038            inherit (pkgs) hello figlet;
1039          };
1040        }
1042      Type:
1043        recurseIntoAttrs :: AttrSet -> AttrSet
1045    */
1046   recurseIntoAttrs =
1047     # An attribute set to scan for derivations.
1048     attrs:
1049     attrs // { recurseForDerivations = true; };
1051   /* Undo the effect of recurseIntoAttrs.
1053      Type:
1054        dontRecurseIntoAttrs :: AttrSet -> AttrSet
1055    */
1056   dontRecurseIntoAttrs =
1057     # An attribute set to not scan for derivations.
1058     attrs:
1059     attrs // { recurseForDerivations = false; };
1061   /* `unionOfDisjoint x y` is equal to `x // y // z` where the
1062      attrnames in `z` are the intersection of the attrnames in `x` and
1063      `y`, and all values `assert` with an error message.  This
1064       operator is commutative, unlike (//).
1066      Type: unionOfDisjoint :: AttrSet -> AttrSet -> AttrSet
1067   */
1068   unionOfDisjoint = x: y:
1069     let
1070       intersection = builtins.intersectAttrs x y;
1071       collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
1072       mask = builtins.mapAttrs (name: value: builtins.throw
1073         "unionOfDisjoint: collision on ${name}; complete list: ${collisions}")
1074         intersection;
1075     in
1076       (x // y) // mask;
1078   # DEPRECATED
1079   zipWithNames = zipAttrsWithNames;
1081   # DEPRECATED
1082   zip = builtins.trace
1083     "lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;