Worth using a derivation for automatic installPhase updates?

I’m struggling to write my first derivation based on this answer from Reynier suggesting an “automatic method” (see below). His argument for using a derivation here is that it would automatically update the config.kdl file.

Suggested derivation from the reference above:

file = let
  myConfig = pkgs.stdenv.mkDerivation {
    name = "custom-yazelix-config";
    src = pkgs.fetchFromGitHub {
      owner = "luccahuguet";
      repo = "yazelix";
      rev = "1093c18c22d9d9858f4cf5813bd9aa7578660af8";
      hash = "sha256-+6Mq8mR/tF1Z+GyooMz9fWGV57bFhbHXBVBDkHpUMDA=";
    };
    installPhase = ''
      mkdir -p $out/zellij
      cp ${self}/apps/yazelix/config.kdl $out/zellij/config.kdl
    '';
  };
in {
  ".config/yazelix".source = myConfig;
};

The “file = let” leads me to believe that this should go in home.nix, but I’m also not sure where or how to define “self”. I also tried using this in my flake.nix, configuration.nix, and as a flake but I haven’t had any luck.

Is this really the way? Any suggestions on how to get this working?

you are correct about file =, it should be in home.nix, but it can be done like

home.file.".config/yazelix".source = pkgs.stdenv.mkDerivation {
  ...
};

Here ${self} is the path of the flake providing the home configuration.

you can use relative paths like cp ${./apps/yazelix/config.kdl}.

Using relative paths in postFetch will not reflect if your file changes because that is inside a FOD (fetchFromGithub) and fod hashes are cached. But in a mkDerivation’s installPhase using relative paths should be ok, as it is not a fod.

Also, I see that in that mkDerivation solution the src is not being used, you should do something like cp -r $src $out before doing anything.

I second this recommendation. Avoid using references to self in derivations, as these derivations will get rebuilt every single time you change anything in your flake.

src gets extracted to the current working dir, and CWD is in the top-level of the fetched src, so I’d rather suggest cp -r ./whatever $out (especially if something happened in patching phases or so on).

2 Likes

thanks, this is new to me.

when I did cp -r $src $out; ls -l $out I see directories don’t have write permissions so the next step cp ${./apps/yazelix/config.kdl} $out/zellij/config.kdl fails.

Whereas cp -r . $out; ls -l $out does give directories write permissions.

so @guttermonk this works

  home.file.".config/yazelix".source = pkgs.stdenv.mkDerivation {
    name = "custom-yazelix-config";
    src = pkgs.fetchFromGitHub {
      owner = "luccahuguet";
      repo = "yazelix";
      rev = "1093c18c22d9d9858f4cf5813bd9aa7578660af8";
      hash = "sha256-+6Mq8mR/tF1Z+GyooMz9fWGV57bFhbHXBVBDkHpUMDA=";
    };
    installPhase = ''
      mkdir -p $out
      cp -r ./yazi ./zellij $out # or do cp -r . $out for everything
      cp ${./apps/yazelix/config.kdl} $out/zellij/config.kdl
    '';
  };
2 Likes

That worked! Nix feels like magic. I was also able to write my own derivation for zide as well. Thank you both for teaching a man to fish - You’re awesome.

1 Like

I’m curious what you both think about the other solution on that thread, regarding using runCommandNoCC instead of a derivation.

runCommandNoCC is a derivation.

Simpler to use if all you need to do is copy files, without taking advantage of the phases of stdenv/stdenvNoCC. (and runCommandNoCC is just an alias of runCommand since by default you wouldn’t need a C compiler.)

@waffle8946 Would runCommandNoCC be better to use here, since I’m just copying that github repo and putting them in my config directory and adding my own config file to it?

runCommand is fine. (The NoCC is redundant.) It’s simply down to whether you find it more convenient than stdenv.mkDerivation for your use case, there’s no objective “better” here.

1 Like