// operator with in specialisations

I’m experimenting with an idea I had about specialisations and making my home-manager configuration more lego-like without using more modules.

I am configuring 4 “profiles” that I can flip between. 2 have gui dependancies (theming and such). The other 2 differ by git credentials, and obviously the other 4 are mixtures of the previous 4

I was planning on setting up the below code.
The // operator is not working as it should.
When I build the configurations in guiThings are not built.
Unsure why.

{ config, lib, pkgs, ... }:
let
  guiThings = { configs with gui stuff and theming };
in
{
normal.config = "here";
default.configs.and = "things";
  home.specialisation = {
    gui-default = guiThings // {
      gui.specific.configs = "here";
    };
    gui-work = guiThings // {
      basically = [ work ] + gui;
    };
    work = {
      work.related.configs = "here";
    };
  };
}

You are probably seeing the effect of // doing a “shallow” merge, rather than a “deep” merge. Try using lib.attrsets.recursiveUpdate instead. More at this Stack Overflow question:

2 Likes

You’re right that it’s because // is not recursive, so e.g. { a.b = "c"; } // { a.d = "e"; } returns { a.d = "e"; } because it just replaces the entire a attrset with the one from the right hand side. But when using the module system, mkMerge tends to be better than recursiveUpdate, because it allows for the options to utilize their own merge strategy; e.g. lists being concatenated.

5 Likes

Thanks,
Not sure how I missed that article.
mkMerge seems cleaner imo so I’ll use that but this is good to know as well.