Accessing home-manager config in flakes

In a pre-flake home-manager setup, I’ve been using this trick

{ config, pkgs, ... }:

let
  link = config.lib.file.mkOutOfStoreSymlink;
in
{
  home.file.".config/XXX".source = link ../XXX;
  ...
}

to enable quick experimenting with the configuration of some given package (represented by XXX in this example) without having to build (veeeery slowly) a new home-manager generation with every tweak.

I’ve always been puzzled by where the config parameter comes from. When trying to migrate this setup to a flake-based one, I have to provide the arguments explicitly myself, when importing the function defined in home.nix.

What is config and how should I get my hands on it so than it can be passed in to this function?

config binds to the resulting home-manager configuration. It is used for accessing option values from other modules and etc. But you should use lib like this

{ lib, pkgs, ... }:

let
  link = lib.file.mkOutOfStoreSymlink;
in
{
  home.file.".config/XXX".source = link ../XXX;
  ...
}

. By the way, how are importing home.nix Are you using home-manager.lib.homeManagerConfiguration function?

1 Like

Yes, but it turns out that somewhere along the line some junk crept in, and it ended up fooling me into believeng that I had to supply the arguments explicitly myself. Very roughly, I had this

homeManagerConfiguration { configuration = import ./nixpkgs/home.nix { ... }; }

instead of this

homeManagerConfiguration { configuration = import ./nixpkgs/home.nix;         }

.

If I remove the junk, and just import the whole home.nix function, without trying to call it, everything makes so much more sense.

Hmm …

error: attribute 'file' missing

       at /nix/store/s8imyb0xwp25g1f1lhlq81y85k3mjy1c-source/nixpkgs/home.nix:15:10:

           14|
           15|   link = lib.file.mkOutOfStoreSymlink;
             |          ^
           16|
       Did you mean one of filter, fix, fix', fold or pipe?

It got moved to config.lib.mkOutOfStoreSymlink and doesn’t with flakes anymore if you use a nix path literal. You need to give it a string representing an absolute path on your filesystem.

To be honest, just use HM as it is meant to be used and pretend mkOutOfStoreSymlink to not exist at all.

Having to rebuild a new home-manager generation every time you tweak a setting in one of your config files, makes home-manager completely insufferable in such situations: it slows such explorations down by 2 to 3 orders of magnitude!

You can use it ‘as it is meant to be used’ most of the time, and resort to mkOutOfStoreSymlink only while you’re fiddling around with the configuration of some package, but mkOutOfStoreSymlink is crucial to making configuration exploration viable, so there is no way I’m going to forget that it exists.

1 Like

After one had “quickly iterated” one has to translate it into proper HM anyway, why not start like that?

Now I wonder what exactly you mean by “proper HM”. Do you mean use the various modules provided by HM to configure packages, rather than those packages’ native config files and syntaxes? If so, 2 reasons:

  • HM only provides modules for a subset of the packages that exist in the universe, and it lags in supporting the latest configurable features of those that it does support.
  • Having to search the HM docs to find how to configure aspect X of package Y, rather than package Y’s docs, is additional cognitive overload and a time sink that I simply cannot afford.

I did try doing it that way, and … no, just no!

So now I configure packages by writing their native config files in their native syntax, keep those in the same version-controlled repo as my home.nix and get home-manager to link those files to the location where the package expects to find them. I started off using immutable (in-store) links to these files by default, only switching to mutable (out-of-store) ones for config tweaking purposes. But that grew old pretty quickly, so I’ve got mutable (version-controlled in the same repo) ones for most things.

Though my new flake-based home-manager config gives me the impression of building new generations much more quickly that the old one, so maybe I can shift the balance towards more immutable links again. But I don’t see myself going back to using the HM modules, in favour of native config files any time soon.

To answer your question, it my scheme, after having quickly iterated, I don’t have to translate anything. In theory, I should switch from an out-of-store link to an in-store one, which requires almost zero effort on my behalf, and the silly amount of time it takes home-manager to create the new generation is the only thing that’s stopping me from taking that extra step.

1 Like

Yeah, I indeed speak about using and writing HM modules that generate the configuration files.

I’m oposed to all those home.file collectiöns that could have been done using stow as well…

Oh, the purist in me would like to do it the ‘proper’ way, which is why I tried it that way for quite some time. But in real life I just don’t have time for that extra overhead.

What do you do when you find that some HM module doesn’t yet support some option that you want to configure? (Hmm, there was some extraConfigs thing, wasn’t there? I ended up putting a lot of stuff in those!)

It also hinders sharing config snippets with those who don’t use Nix.

But the fact that changing anything, when using the HM module approach, is SO DAMN SLOW, that’s the real killer. I dunno, maybe you can read the docs of random packages, and get the right configuration first time. I’m afraid I have to go though many iterations of trial and error, and home-manager switch is just too slow for that.

Yeah, maybe it can be done in stow, but I don’t use stow I use Nix, and these links are, in my opinion, the best compromise between practicality and purity, in that context.

I usually try to find some way around it, usually by adding an option that wraps extraConfig or similar.

This is a situation I do not care for, and if I have to, I show them the generated config file.

Lets agree to disagree on this.

Sure.

What makes a best compromise depends on so many factors, so the optimal point will be different for different people. It will even be different for the same person at different times. If I ever get the luxury of being able to spend more time on understanding Nix and improving my use of it, I suspect my optimal point will shift closer to yours.