diff --git a/lib/attrsets.nix b/lib/attrsets.nix index 0a4c3c8ebcf4..8b5c0ef4cea6 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -3,7 +3,7 @@ let inherit (builtins) head tail length; - inherit (lib.trivial) id; + inherit (lib.trivial) flip id mergeAttrs pipe; inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName; inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all partition groupBy take foldl; in @@ -77,6 +77,25 @@ rec { let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'"; in attrByPath attrPath (abort errorMsg); + /* Map each attribute in the given set and merge them into a new attribute set. + + Type: + concatMapAttrs :: + (String -> a -> AttrSet) + -> AttrSet + -> AttrSet + + Example: + concatMapAttrs + (name: value: { + ${name} = value; + ${name + value} = value; + }) + { x = "a"; y = "b"; } + => { x = "a"; xa = "a"; y = "b"; yb = "b"; } + */ + concatMapAttrs = f: flip pipe [ (mapAttrs f) attrValues (foldl' mergeAttrs { }) ]; + /* Update or set specific paths of an attribute set. diff --git a/lib/default.nix b/lib/default.nix index 8bb06954518b..cc4bedc5869b 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -78,7 +78,7 @@ let inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs filterAttrsRecursive foldAttrs collect nameValuePair mapAttrs - mapAttrs' mapAttrsToList mapAttrsRecursive mapAttrsRecursiveCond + mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 31c938a8ffda..b73da4f1010d 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -478,6 +478,23 @@ runTests { # ATTRSETS + testConcatMapAttrs = { + expr = concatMapAttrs + (name: value: { + ${name} = value; + ${name + value} = value; + }) + { + foo = "bar"; + foobar = "baz"; + }; + expected = { + foo = "bar"; + foobar = "baz"; + foobarbaz = "baz"; + }; + }; + # code from the example testRecursiveUpdateUntil = { expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {