Nix function to merge attributes / records recursively and concatenate arrays

Does someone know such function that merges list of records

  • if all values to merge are records - merge them recursively
  • if all values to merge are arrays - concatenate arrays
  • If values can’t be merged - the latter value is preferred

Example 1:

recursiveMergeAttrs [
  { a = "x"; c = "m"; list = [1]; }
  { a = "y"; b = "z"; list = [2]; }
]

returns

{ a = "y"; b = "z"; c="m"; list = [1 2] }

Example 2

recursiveMergeAttrs [
  {
    boot.loader.grub.enable = true;
    boot.loader.grub.device = "/dev/hda";
  }
  {
    boot.loader.grub.device = "";
  }
]

returns

{
  boot.loader.grub.enable = true;
  boot.loader.grub.device = "";
}

P.S.

recursiveUpdate is not working

recursiveMergeAttrs = listOfAttrsets: lib.fold (attrset: acc: lib.recursiveUpdate attrset acc) {} listOfAttrsets

recursiveMergeAttrs [ { a = "x"; c = "m"; list = [1]; } { a = "y"; b = "z"; list = [2]; } ]

returns 

{ a = "y"; b = "z"; c = "m"; list = [ 2 ]; }

2 Likes

The nixos module system does this. But you need to declare types of the fields, as on different occasions you need “different kind” of merging.

1 Like

This would be a nice addition next to lib.recursiveUpdate
The module system, yes, requires type declaration, and in some cases leads to infinite recursion
(I recently hit i.r. trying to do

config = 
  lib.mkMerge (map (x: { networking = { .......; }; })
                   config.henet-tunnelbroker.tunnels
              );

while a simple merge function could work here, so I ended up with lib.recursiveUpdate + ad-hoc handling of arrays)

1 Like

Has anything been added to lib since? Seems like a useful function to have to merge deeply nested attrsets with lists.

edit: I guess a PR would be the way to go if not.

3 Likes

I would really need this! I don’t have the capacities to create the PR myself right now, though. Does it make sense to create a feature request on GitHub?

Use lib.mkMerge. As said above, the module system handles this.

You might be interested in infuse, which can do this (and many other things) without dragging in the whole module system.