How are overlays supposed to work with multi-level flake dependencies?

I’m converting a few projects to flakes as an excuse to learn them and am a bit puzzled over something. Might be holding it wrong.

I have 3 flaked packages: hag depends on shellswain which then depends on comity.

When I wire up the overlays the ~naive way, the shellswain flake builds fine, but then I get eval failures on the hag flake like:

Function called without required argument "comity" at /nix/store/gpmcl4zrj35m19hxdcvb4a5aa0hk5724-source/shellswain.nix:4

I can:

  1. fix this at the hag level by fishing the comity overlay out of shellswain’s inputs, but that’s a pretty gross containment breach
  2. re-output the comity overlay at the shellswain level and then use builtin.attrValues to pull in all of shellswain’s output overlays, but it’s leaking an implementation detail of one flake into its consumers for incidental reasons
  3. ??? hold it right ???

Both of these options sound like they’d turn into an absolute fragile nightmare in a complex graph of flake-to-flake dependencies–and violate the ~implementation-detail-containment expectations we come to Nix for in the first place.

Am I doing it wrong? Are flakes ~wrong, here?

Your shellswain overlay could use nixpkgs’ composeExtensions function to include the comity overlay in its default overlay.

  overlays.default = nixpkgs.lib.composeExtensions comity.overlays.default (final: prev: {
    ...
  });

Or if you don’t want to rely on a nixpkgs input, composeExtensions is a tiny function to copy in:

  composeExtensions =
    f: g: final: prev:
      let fApplied = f final prev;
          prev' = prev // fApplied;
      in fApplied // g final prev';

This way you just have to include shellswain’s default overlay, and it includes comity’s on your behalf.

1 Like

That makes sense. Thank you.

(Though the status quo still smells like a footgun?)