A function which returns a flake?

Hello all,

I work at a company where we have multiple clients, and where the latest version of a product is obtainable by a bookmark (like a git branch, a pointer to a particular rev) in mercurial. So we have flakes that start with

{
  inputs = {
    our-product = hg+https://our-repo.com/our-product?ref=client-a;
  }
  ...
}

My question would be, is it possible to write a function which abstracts over a flake, so that the client bookmark - client-a above - can be passed as an argument to said function, and it then returns a flake? I’m assuming not, since the nix package manager presumably wants a fully-formed flake as an entrypoint, but I thought I’d ask.

1 Like

No, there’s nothing like that. It would be pretty hard to make that interact sanely with the locking system.

Short answer: no

Long answer:
There are a couple possibilities depending on what you want to do

  • You can use the existing flake with --override-input whenever you want to use something other then the predefined our-product
  • You can create another flake that overrides the current flake using inputs.*.follows. This allows you to define multiple instances of the existing flake and use it almost like a function
  • If the our-product is not a flake, you can make the current flake generic over its inputs and just apply it with different sources called with fetchhg, it is also possible if our-product is a flake with builtins.getFlake but you are probably better off with the previous solution if that’s the case.

On a side note, unquoted URLs are being deprecated as per RFC 45

2 Likes

Thank you! That second approach seems like the most viable one.

Could I check - the second option here, how would that work? If I understand correctly, you can only have one flake per thing you want to build, since:

  • You cannot have multiple flakes sitting side-by-side in the root of a repo, and
  • If you put flakes in a sub-directory of that repo, they cannot build code at a lower level of the repo - ie, you cannot do, say src = ../..

If you put flakes in a sub-directory of that repo, they cannot build code at a lower level of the repo

You can get around that by having the flake in the sub-directory generic over the source dir, e.g. as a function argument

Another way is just to have two separate repositories for two separate flakes

Now that I think about it, if you already need a function, you can just have one flake and apply that function to multiple inputs

Sorry, I don’t quite get what you mean by that one. One flake would act as a single function, and then I would (somehow) pass it the inputs?

What I meant is that you can access ../. by having the output of the flake in the subdirectory (I will call it a) accept a path, e.g., packages.x86_64-linux = src: stdenv.mkDerivation { inherit src; /* ... */ };, and the actual flake at the root level would use a.packages.x86_64-linux self since it has access to this directory. this example is overly simplified, you might actually want to do overrides instead so stuff like nix flake show would work

Thank you - seems like there are some good options for solving this - I’ve actually gone with the approach of having a script to edit the lockfile, but appreciate your help.