Managing config files: why not use mkOutOfStoreSymlink for everything?

{
  systemd.tmpfiles.rules = [
    "L+ /home/matklad/.config/git/config - - - - /home/matklad/dotfiles/git/config"
  ];
}

You may want to check the docs for the way to set owner and group explicitely or whether L+ is really what you want or whether L is enough for your usecase, this is a quick copy from my own config.

4 Likes

Hjem also developed a tool specifically to do this with proper cleanups, which you could depend on in NixOS, or, y’know, not reinvent the wheel and just use hjem.

4 Likes

Does smfh actually delete old files just because you remove the directive to create it? It seems like it’s capable of deleting files, but only if you give it an order to do so… maybe I’m just not understanding it correctly.

1 Like

That’s my understanding of this PR. I have admittedly not looked in detail at smfh, but given the entire point of moving from tmpfiles.d to smfh was getting cleanup of unmanaged files…

1 Like

The parallel for installing packages globally with no extra config generated is a buildEnv, maybe with a symlink in /opt/nix-managed-tool or something in case of multi-user, not home-manager.

There’s a giant difference between buildEnv and linking dotfiles into $HOME.

If you use wrappers, as I suggest (which isn’t trivial, or outright impossible, for many applications), this does become feasible, though it also inherently does the opposite of what users of mkOutOfStoreSymlink want, which is zero-switch auto dotfile edits.

But you could. Then you still need to figure out how to get the binaries into your $PATH without symlinks - or the tools you claim aren’t essential.

You could use a cursed shell rcfile that nests your entire session in a nix shell, and I have seen people do so with mixed results. The environment pollution causes serious issues.

nix profile install and nix-env -i can technically also get there without the cursed rcfile, but every time I’ve sent a newbie down that path when they insisted on not wanting to use home-manager I’ve regretted telling them this is even an option. Even nix profile has pretty wonky behavior, let alone nix-env, and you’re still relying on the local distro’s shell rcfile to be set up in a specific way.

In either case, you end up having to reinvent some of what home-manager/hjem do. Which you are free to do, but being able to replace a tool with your own reimplementation is not as much of a gotcha as it may seem.

1 Like

If someone wants something lighter weight than home-manager on non-nixos, I always point them at Expression for a buildEnv-based declarative user environment. · GitHub. It’s no good for anything but installing packages in ~/.nix-profile (no dotfiles), but it is properly declarative, unlike nix-env and nix profile, and about as lightweight as you can get within that constraint.

2 Likes

That’s not true — using dotfiles normally and keeping them under version control, with paths pointing into the buildEnv result symlink when you need a store path to an executable, is not reimplementing what home-manager does, it is just skipping the config-generation-via-NixOS-module-system part.

Yes, it does. That’s the whole reason we bothered to move hjem from using systemd-tmpfiles to using smfh, as @TLATER said. (systemd-tmpfiles was always meant to be a stopgap measure until we wrote our own thing, since I was personally using systemd-tmpfiles in my own config at the time and was unsatisfied with it.) hjem generates a JSON manifest containing the current generation’s list of paths and operations, and smfh operates on said manifest when activating (in a systemd service, managed by hjem), comparing the old manifest with the new and performing the operations it needs to.

The delete operation is unrelated and for a somewhat niche use case: if a program (imperatively) creates a path that you want to delete on activation, you might find that operation useful.

2 Likes

Been using home-manager for a year or two, got so tired of constant rebuilding and lack of hot-reloading, so I ditched it altogether, put dotfiles in the same repo as NixOS config and create symlinks using systemd.tmpfiles.

Basically, same idea as yours, but a bit more low-level.

Been using that approach for two years and it’s great. System is more minimal and more understandable, everything is still in the same repo, hot-reloading, etc.

Yeah, deploying to remote machines won’t work without cloning the repo, but I use it only for local development machines where my intention is to clone my config repo.

I use symlinks with combination of nix-impermanence, so don’t have to care about deleting old symlinks as everything is recreated with each reboot anyway.

4 Likes

Fun fact, you actually can do wrappers with impurity. For example:

  symlinkJoin {
    name = "gh-wrapped";
    paths = [ pkgs.gh ];
    buildInputs = [ makeWrapper ];
    postBuild = /* bash */ ''
      wrapProgram $out/bin/gh \
        --set GH_CONFIG_DIR /home/some-user/location-of-gh-config-dir
    '';
    meta.mainProgram = "gh";
  };

This is only really useful with a toggle on the nix end to enable/disable the impurity - so you get a pure wrapped package on a random machine, but fast iteration on your own machine. I don’t use this personally, since wrapper iteration speeds are so fast with a devshell, but I make sure to support it in the collection of wrappers I maintain.