niv icon indicating copy to clipboard operation
niv copied to clipboard

Create default.nix during niv init

Open nmattia opened this issue 5 years ago • 14 comments

The niv init command used to create a few files (default.nix, shell.nix, etc) which some people didn't like. Some people now complain that they want it back. I think the best solution here is to have niv init create a single extra file, default.nix, which

  1. shows how to import nix/sources.nix
  2. builds a single (pkgs.hello) package,
  3. potentially create a shell if inNixShell

nmattia avatar Jun 18 '19 08:06 nmattia

Why not just have options to niv init? e.g. niv init --sources --default --shell for everything.

michaelpj avatar Jun 18 '19 09:06 michaelpj

I'll be honest, requiring extra options is less than ideal. Instead have nix init check for a ./shell.nix file and a ./nix/default.nix file. If there is only a ./shell.nix then create a ./nix/default.nix that has comments at the top on how to import nix/sources.nix. If there is already a ./nix/default.nix, don't modify it and tell the user. Otherwise, generate everything.

Skyfold avatar Jul 02 '19 09:07 Skyfold

I gave this some thoughts over the past few days and came up with this (feedback welcome):

niv init generates nix/sources.json, nix/sources.nix and default.nix (unless they exist, of course). The default.nix would look like this:

let
  sources = import ./nix/sources.nix;
  pkgs = import sources.nixpkgs {};
in pkgs.hello

should be simple enough that people might actually use it, and still it showcases how to use niv.

nmattia avatar Jul 02 '19 09:07 nmattia

I agree that having a simple enough example to build off of is a good idea. I would extend this idea by also generating a shell.nix that imports everything from sources.nix. However, I just realized if you wanted to import every attribute (package) into your buildInputs then the way you generate sources.nix would need to be adjusted to be {nixpkgs = nixpkgs; buildInputs = [snack niv]; } instead of making each package a top level attribute. To be fair you could filter out nixpkgs and import the rest, but it would complicate the resulting shell.nix.

Skyfold avatar Jul 02 '19 10:07 Skyfold

So I think there are two big use cases for niv:

  • A repository specific package that has a default.nix that defines just that package.
  • A repository full of nix expressions for doing various things, maybe including packages, library functions, etc.

Importing dependencies and using them in buildInputs makes sense for the first kind and no sense at all for the second kind (e.g. nixpkgs). I don't think we should make assumptions about what people put in there, so I'm against doing anything with a source except importing it as a (mystery) attribute.

michaelpj avatar Jul 02 '19 11:07 michaelpj

Why not have both? Keep the existing behavior of sources.nix and just tack on an extra attribute called buildInputs to make creating a shell.nix easy (or have niv generate the shell.nix with an extra flag). So you could do:

{ sources ? ./nix/sources.nix }:
  pkgs.mkShell {
    buildInputs = (import sources).buildInputs;
  }

Skyfold avatar Jul 02 '19 12:07 Skyfold

I end up setting up every repo I use niv in using an interesting method. I originally took inspiration for it from @nmattia's homies and have taken small ideas from other repos as well. I have a nix/default.nix that essentially acts as the standard "prelude" import. That is, let pkgs = import ./nix {}; imports the pinned nixpkgs. However, I also end up defining any overlays, nixpkgs configuration, and "globally available util stuff" in nix/default.nix which makes my life really convenient.

Recently, I've also taken to adding "sources" as an overlay so I can do pkgs.sources.my-niv-managed-dependency but I only do that to save on line-noise in the rest of the nix files.

So it seems to me that default.nix and shell.nix aren't really the biggest things I end up setting up every time but actually nix/default.nix. Specifically, something like:

# nix/default.nix
{ sources ? import ./sources.nix, system ? builtins.currentSystem }:
let
  srcs = self: super: { inherit sources; };
  overlays = [ srcs ];
  config = { };
in import sources.nixpkgs { inherit overlays config system; }

is essentially my starter boilerplate in nix/. Then, should niv want to bootstrap the default and the shell, they can be:

# default.nix (at repo root)
let pkgs = import ./nix {};
in pkgs.hello
# shell.nix (at repo root)
let pkgs = import ./nix {};
in pkgs.stdenv.mkShell {
  buildInputs = [ pkgs.hello ];
}

How well do you think that pattern would work?

One thing I'd be concerned about is adding a bunch of extra utility to the nix/default.nix or nix/sources.nix, but only really for keeping maintenance burden to a minimum.


edit: updated proposed default.nix to account for system.

hazelweakly avatar Jan 08 '20 14:01 hazelweakly

👍 , I think that's close to the perfect nix/default.nix! One thing that we may add as well is a system parameter, if you want to build stuff on a difference architecture (through a remote builder):

{ sources ? ...
, system ? builtins.currentSystem
}: 
...
in sources.nixpkgs { inherit overlays config system; }

I think we should just go for it, maybe hiding it behind a flag (e.g. niv init --full).

nmattia avatar Jan 08 '20 16:01 nmattia

I find injecting the niv sources into nixpkgs via an overlay feels somewhat unhygienic: the sources aren't packages, and I usually want to manage them separately. A matter of taste, I guess, I appreciate the appeal of "everything is all in one attribute set".

I want something different from nix/default.nix, which is just to give me a shortcut to precisely the bits managed by niv, i.e. sources.nix. So it's usually exactly import sources.nix.

michaelpj avatar Jan 08 '20 17:01 michaelpj

(One small rant: importing nixpkgs is pretty non-trivial (it has a lot of significant arguments), and the number of things that do it wrong (e.g. not passing system as you're doing here), is high. I really wish tools would let me do it the way I want to do it and pass it in, rather than trying to import nixpkgs for me and doing it wrong.)

michaelpj avatar Jan 08 '20 17:01 michaelpj

@michaelpj the nix flakes branch actually does a lot of that for you, they replace 80% of what niv does (sorry nmattia), creates a standard entrypoint for repositories, handles system and a few other things. You can test it by setting nix.package = pkgs.nixFlakes; in NixOS.

zimbatm avatar Jan 08 '20 21:01 zimbatm

(One small rant: importing nixpkgs is pretty non-trivial (it has a lot of significant arguments), and the number of things that do it wrong (e.g. not passing system as you're doing here), is high.

You're absolutely right, my apologies; I didn't actually know I should include system as I've only seen it done once in someone's config online. Is there a wiki page for "how to import nixpkgs properly" or is it a sort of cult knowledge that's acquired by making mistakes over time?

I really wish tools would let me do it the way I want to do it and pass it in, rather than trying to import nixpkgs for me and doing it wrong.)

Fortunately, even if niv had a default.nix, it can easily be replaced or modified to suit your needs.

Although, since niv includes nixpkgs by default in its init, that actually suggests to me that it's even more important that niv's init also come with a way to fully correctly import nixpkgs. Otherwise it's far too easy to just make the mistake of writing the naive let sources = import ./nix/sources.nix; pkgs = import sources.nixpkgs {}; and then, whoops, that'll no longer work correctly on mac systems as you've pointed out.

hazelweakly avatar Jan 08 '20 21:01 hazelweakly

I know about flakes :) my feeling is rather that niv does 80% of what flakes do...

Is there a wiki page for "how to import nixpkgs properly" or is it a sort of cult knowledge that's acquired by making mistakes over time?

I got it the latter way :sweat_smile:

Although, since niv includes nixpkgs by default in its init, that actually suggests to me that it's even more important that niv's init also come with a way to fully correctly import nixpkgs.

Is it? I like that niv does one thing: get me a set of sources. It could do more, and be a full-fledged Nix project scaffolding manager. But I, personally, would prefer if it continued just doing the one thing well.

michaelpj avatar Jan 09 '20 22:01 michaelpj

Hey guys, would love your feedback on https://github.com/nmattia/niv/issues/272

nmattia avatar Aug 22 '20 16:08 nmattia