Nix function to merge attributes / records recursively and concatenate arrays


#1

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

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.


#3

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)