nmattia / niv

Easy dependency management for Nix projects
https://github.com/nmattia/niv
MIT License
1.52k stars 74 forks source link

feat: Add an `eject` command to convert project to flakes #404

Open 414owen opened 2 weeks ago

414owen commented 2 weeks ago

This adds a niv eject command, which prints the niv sources.json in flake input format.

We ended up not actually switching to flakes at all, but maaaaybe this will save someone a lot of time, so I thought I'd make it public.

It's far from perfect, but it'll get you 95% of the way there.

nmattia commented 2 weeks ago

thanks @414owen ! Actually last weekend @zimbatm and I were talking about whether it'd be feasible to use niv to edit a flake.nix. This would require a nix parser, but it would make life so much easier (nix flake lock --update-input foo vs niv update foo).

Do you think that would make sense? When working on ejecting the flake, did you see any issue that might prevent niv from handling a flake.nix?

414owen commented 2 weeks ago

Hmmm, I ran a few tests, and the flake format is pretty strict. It (and the input attr) has to be a literal set, it can't be imported, or used from a let.

For example, this doesn't work:

  inputs = let a = { url = "https://duckduckgo.com"; flake = false; }; in {
    inherit a;
  };

So it should always be possible to edit flake inputs purely based on the AST.

I guess separating out the parser from hnix would be a good first step...

414owen commented 2 weeks ago

Using niv to implement nix flake lock --update-input foo would be pretty easy though. You shouldn't need to read or edit nix, right? Just JSON?

Actually you could totally cheat and get niv to call nix...

nmattia commented 2 weeks ago

Hmmm, I ran a few tests, and the flake format is pretty strict.

Nice! I think that's the conclusion we also reached. That'd mean that the parsing should be "pretty" straightforward.

You shouldn't need to read or edit nix, right? Just JSON?

That's the one bit I'm not sure about though. Can you e.g. specify a branch in the flake.lock itself? For instance, if the flake.nix and flake.lock are tracking github.com/nixos/nixpkgs (master), what would happen in this case?

$ niv update nixpkgs -b unstable
<couple days pass>
$ niv update nixpkgs

In niv land, first the branch would be changed to point to unstable, and then the second call would grab the latest commit on that unstable branch. In flake land, I was under the impression that the branch was tracked in flake.nix, meaning we couldn't just get away with editing flake.lock.

414owen commented 2 weeks ago

@nmattia Ah, yes, you're right. We would need to read the flake.nix. FWIW I think later versions of nix actually have a nix flake update <input-name> command, so maybe we should just handle niv things for now.

Of course this might include converting sources.json to/from flake.{nix,lock}. But I'd be inclined to KISS and just print the flake inputs to stdout, as I've done here. It's something you'll probably only do once per project, and the automation provided is already 100x better than doing it by hand...

nmattia commented 2 weeks ago

later versions of nix actually have a nix flake update command

Ah, that's amazing!

we should just handle niv things for now.

Sure, that makes sense. I like the idea of eject and I'll look at the implementation later this week!