2009-02-09 16:51:03 +00:00
|
|
|
# Operations on attribute sets.
|
|
|
|
|
2009-03-06 23:21:14 +00:00
|
|
|
with {
|
2009-05-24 11:57:49 +01:00
|
|
|
inherit (builtins) head tail isString;
|
2009-03-06 23:21:14 +00:00
|
|
|
inherit (import ./default.nix) fold;
|
2009-03-10 15:18:38 +00:00
|
|
|
inherit (import ./strings.nix) concatStringsSep;
|
2009-06-11 17:03:33 +01:00
|
|
|
inherit (import ./lists.nix) concatMap;
|
2009-03-06 23:21:14 +00:00
|
|
|
};
|
2009-02-09 16:51:03 +00:00
|
|
|
|
|
|
|
rec {
|
|
|
|
inherit (builtins) attrNames listToAttrs hasAttr isAttrs;
|
|
|
|
|
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
/* Return an attribute from nested attribute sets. For instance
|
|
|
|
["x" "y"] applied to some set e returns e.x.y, if it exists. The
|
2009-05-24 11:57:41 +01:00
|
|
|
default value is returned otherwise. */
|
|
|
|
attrByPath = attrPath: default: e:
|
2009-02-09 16:51:03 +00:00
|
|
|
let attr = head attrPath;
|
|
|
|
in
|
|
|
|
if attrPath == [] then e
|
|
|
|
else if builtins ? hasAttr && hasAttr attr e
|
2009-05-24 11:57:49 +01:00
|
|
|
then attrByPath (tail attrPath) default (getAttr attr e)
|
2009-02-09 16:51:03 +00:00
|
|
|
else default;
|
|
|
|
|
2009-05-25 19:22:19 +01:00
|
|
|
|
2009-05-24 19:12:39 +01:00
|
|
|
/* Backwards compatibility hack: lib.attrByPath used to be called
|
|
|
|
lib.getAttr, which was confusing given that there was also a
|
|
|
|
builtins.getAttr. Eventually we'll drop this hack and
|
|
|
|
lib.getAttr will just be an alias for builtins.getAttr. */
|
|
|
|
getAttr = a: b: if isString a
|
|
|
|
then builtins.getAttr a b
|
|
|
|
else c: builtins.trace "Deprecated use of lib.getAttr!" (attrByPath a b c);
|
2009-05-24 11:57:41 +01:00
|
|
|
|
2009-03-06 23:21:14 +00:00
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
getAttrFromPath = attrPath: set:
|
|
|
|
let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
|
2009-05-24 11:57:41 +01:00
|
|
|
in attrByPath attrPath (abort errorMsg) set;
|
2009-03-10 15:18:38 +00:00
|
|
|
|
2009-03-06 23:21:14 +00:00
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
/* Return the specified attributes from a set.
|
2009-03-06 23:21:14 +00:00
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
Example:
|
|
|
|
attrVals ["a" "b" "c"] as
|
|
|
|
=> [as.a as.b as.c]
|
|
|
|
*/
|
|
|
|
attrVals = nameList: set:
|
2009-05-24 11:57:49 +01:00
|
|
|
map (x: getAttr x set) nameList;
|
2009-02-09 16:51:03 +00:00
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
|
|
|
|
/* Return the values of all attributes in the given set, sorted by
|
|
|
|
attribute name.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
attrValues {c = 3; a = 1; b = 2;}
|
|
|
|
=> [1 2 3]
|
|
|
|
*/
|
|
|
|
attrValues = attrs: attrVals (attrNames attrs) attrs;
|
|
|
|
|
|
|
|
|
|
|
|
/* Collect each attribute named `attr' from a list of attribute
|
|
|
|
sets. Sets that don't contain the named attribute are ignored.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
catAttrs "a" [{a = 1;} {b = 0;} {a = 2;}]
|
|
|
|
=> [1 2]
|
|
|
|
*/
|
2009-05-24 11:57:49 +01:00
|
|
|
catAttrs = attr: l: fold (s: l: if hasAttr attr s then [(getAttr attr s)] ++ l else l) [] l;
|
2009-03-10 15:18:38 +00:00
|
|
|
|
|
|
|
|
2009-06-11 17:03:33 +01:00
|
|
|
/* Recursively collect sets that verify a given predicate named `pred'
|
|
|
|
from the set `attrs'. The recursion is stopped when the predicate is
|
|
|
|
verified.
|
|
|
|
|
|
|
|
Type:
|
|
|
|
collect ::
|
|
|
|
(AttrSet -> Bool) -> AttrSet -> AttrSet
|
|
|
|
|
|
|
|
Example:
|
|
|
|
collect builtins.isList { a = { b = ["b"]; }; c = [1]; }
|
|
|
|
=> ["b" 1]
|
|
|
|
|
|
|
|
collect (x: x ? outPath)
|
|
|
|
{ a = { outPath = "a/"; }; b = { outPath = "b/"; }; }
|
|
|
|
=> [{ outPath = "a/"; } { outPath = "b/"; }]
|
|
|
|
*/
|
|
|
|
collect = pred: attrs:
|
|
|
|
if pred attrs then
|
|
|
|
[ attrs ]
|
|
|
|
else if builtins.isAttrs attrs then
|
|
|
|
concatMap (collect pred) (attrValues attrs)
|
|
|
|
else
|
|
|
|
[];
|
|
|
|
|
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
/* Utility function that creates a {name, value} pair as expected by
|
|
|
|
builtins.listToAttrs. */
|
|
|
|
nameValuePair = name: value: { inherit name value; };
|
|
|
|
|
|
|
|
|
|
|
|
/* Apply a function to each element in an attribute set. The
|
|
|
|
function takes two arguments --- the attribute name and its value
|
|
|
|
--- and returns the new value for the attribute. The result is a
|
|
|
|
new attribute set.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
mapAttrs (name: value: name + "-" + value)
|
|
|
|
{x = "foo"; y = "bar";}
|
|
|
|
=> {x = "x-foo"; y = "y-bar";}
|
|
|
|
*/
|
|
|
|
mapAttrs = f: set:
|
2009-05-24 11:57:49 +01:00
|
|
|
listToAttrs (map (attr: nameValuePair attr (f attr (getAttr attr set))) (attrNames set));
|
2009-03-10 15:18:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Like `mapAttrs', except that it recursively applies itself to
|
2009-03-30 14:19:57 +01:00
|
|
|
attribute sets. Also, the first argument of the argument
|
|
|
|
function is a *list* of the names of the containing attributes.
|
|
|
|
|
|
|
|
Type:
|
|
|
|
mapAttrsRecursive ::
|
|
|
|
([String] -> a -> b) -> AttrSet -> AttrSet
|
2009-03-10 15:18:38 +00:00
|
|
|
|
|
|
|
Example:
|
|
|
|
mapAttrsRecursive (path: value: concatStringsSep "-" (path ++ [value]))
|
|
|
|
{ n = { a = "A"; m = { b = "B"; c = "C"; }; }; d = "D"; }
|
|
|
|
=> { n = { a = "n-a-A"; m = { b = "n-m-b-B"; c = "n-m-c-C"; }; }; d = "d-D"; }
|
|
|
|
*/
|
2009-03-30 14:19:57 +01:00
|
|
|
mapAttrsRecursive = mapAttrsRecursiveCond (as: true);
|
|
|
|
|
|
|
|
|
|
|
|
/* Like `mapAttrsRecursive', but it takes an additional predicate
|
|
|
|
function that tells it whether to recursive into an attribute
|
|
|
|
set. If it returns false, `mapAttrsRecursiveCond' does not
|
|
|
|
recurse, but does apply the map function. It is returns true, it
|
|
|
|
does recurse, and does not apply the map function.
|
|
|
|
|
|
|
|
Type:
|
|
|
|
mapAttrsRecursiveCond ::
|
|
|
|
(AttrSet -> Bool) -> ([String] -> a -> b) -> AttrSet -> AttrSet
|
|
|
|
|
|
|
|
Example:
|
|
|
|
# To prevent recursing into derivations (which are attribute
|
|
|
|
# sets with the attribute "type" equal to "derivation"):
|
|
|
|
mapAttrsRecursiveCond
|
|
|
|
(as: !(as ? "type" && as.type == "derivation"))
|
|
|
|
(x: ... do something ...)
|
|
|
|
attrs
|
|
|
|
*/
|
|
|
|
mapAttrsRecursiveCond = cond: f: set:
|
2009-03-10 15:18:38 +00:00
|
|
|
let
|
2009-03-30 14:19:57 +01:00
|
|
|
recurse = path: set:
|
2009-03-10 15:18:38 +00:00
|
|
|
let
|
|
|
|
g =
|
|
|
|
name: value:
|
2009-03-30 14:19:57 +01:00
|
|
|
if isAttrs value && cond value
|
|
|
|
then recurse (path ++ [name]) value
|
2009-03-10 15:18:38 +00:00
|
|
|
else f (path ++ [name]) value;
|
|
|
|
in mapAttrs g set;
|
2009-03-30 14:19:57 +01:00
|
|
|
in recurse [] set;
|
2009-04-25 15:08:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* Check whether the argument is a derivation. */
|
|
|
|
isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
|
|
|
|
|
2009-03-10 15:18:38 +00:00
|
|
|
}
|