Nix 2.8.0 released

Hi,

I’m pleased to announce the availability of Nix 2.8.0. It will be available from Download Nix / NixOS | Nix & NixOS.

Here are the release notes:

  • New experimental command: nix fmt, which applies a formatter defined by the formatter.<system> flake output to the Nix expressions in a flake.

  • Various Nix commands can now read expressions from standard input using --file -.

  • New experimental builtin function builtins.fetchClosure that copies a closure from a binary cache at evaluation time and rewrites it to content-addressed form (if it isn’t already). Like builtins.storePath, this allows importing pre-built store paths; the difference is that it doesn’t require the user to configure binary caches and trusted public keys.

    This function is only available if you enable the experimental feature fetch-closure.

  • New experimental feature: impure derivations. These are derivations that can produce a different result every time they’re built. Here is an example:

    stdenv.mkDerivation {
      name = "impure";
      __impure = true; # marks this derivation as impure
      buildCommand = "date > $out";
    }
    

    Running nix build twice on this expression will build the derivation twice, producing two different content-addressed store paths. Like fixed-output derivations, impure derivations have access to the network. Only fixed-output derivations and impure derivations can depend on an impure derivation.

  • nix store make-content-addressable has been renamed to nix store make-content-addressed.

  • The nixosModule flake output attribute has been renamed consistent with the .default renames in Nix 2.7.

    • nixosModulenixosModules.default

    As before, the old output will continue to work, but nix flake check will issue a warning about it.

  • nix run is now stricter in what it accepts: members of the apps flake output are now required to be apps (as defined in the manual), and members of packages or legacyPackages must be derivations (not apps).

27 Likes

In your first presentation of flakes during NixCon 2019 you drafted an example of a flake file where an edition attribute is present, and I thought at the time that it’s main “reason d’etre” was to track changes to the format like these… Is there still the intention to introduce it at some point in the future? Because without it and if you cannot pin down the version of Nix that is going to read the flake there could be some issues… or I’m getting it wrong and it’s a “non issue”?

4 Likes

I will reiterate my concern about the nix fmt command. This command does one of two things. 1) It provides a requested flake and runs the executable to format Nix code. This is indistinguishable from the purpose of nix run. 2) It downloads a default formatter executable and runs that. This means a bog-standard command must download code from an external source, which may not even be available if the derivation isn’t cached.

IMO this is foolish. Either use nix run or don’t. There’s no need for a command that claims to be internally implemented when in fact it must reach the network and use untrusted code.

17 Likes

I agree that such a fundamental command should use built-in utilities only. But there is an RFC on the flight, and IIRC eelco did express interest in bundling something like this within Nix.

I kind of don’t agree with run vs fmt though. They serve different purposes.

@azazel75 The edition field actually was implemented, but I removed it.The main use case was to support future language changes, but but this creates a circular problem: you have to parse/evaluate flake.nix to get the edition, but you can’t do that if you don’t know the edition…

@ElvishJerricco Yes, nix fmt is a convenience command that could also be done using nix run. But that also applies to e.g. cargo fmt. The eventual goal is to establish a blessed, default formatting style (see RFC 101). At that point the formatter could be included in Nix itself.

7 Likes

So? We should emulate the mistakes of others?

I’d love to have something included in Nix itself for this purpose. But this is not the way to do it.

3 Likes

Impure derivations looks like it would be a good fit for stuff like nixGL, that has to inspect the host system at build time:

Currently if you build that from a flake you have to manually specify nix build --impure.

Also, any chance we could get --file - support for nix store add-file? It doesn’t seem to be there yet and that would be quite nice.

1 Like

I have mixed feelings about nix fmt as well. You are more than welcome to propose a new way to implement a similar feature, I am sure that would be more helpful than just saying “this isn’t the correct way to do it”.

4 Likes

It appears 2.8 updates the profile manifest.json to version “2” which is not compatible with 2.7. I think this should be added to the release notes because it means downgrading from 2.8 to 2.7 may require rolling back any profiles that had their manifest.json version updated.

4 Likes

I personally love that nix fmt establishes a protocol for nix formatters without rigidly enforcing a particular implementation (E.g. Potentially one with bugs).

It’s just plain annoying when a project doesn’t pin their formatters: you end up with a slightly different version of the formatter and everyone gets a slightly different result. That, or CI rejects the PR because the formatting it expects produces a diff.

nix run works ok, but I can’t remap my editor shortcuts to nix run .#format for one project and nix run .#fmt for another one.

To my mind this is even marginally better than bundling the formatter with nix because now I don’t have to worry about whether I’m getting the formatting variation bundled with nix 2.8 or the formatting variation bundled with nix 2.9.

Just give me whatever formatting variation the author of XYZ project is using.

EDIT: along with any flags they might be choosing to pass as arguments, say for example something like --sort-inputs. Though, at the moment I believe this would require a bit of writeScript wrapper boilerplate

(It might be nice to have an extraArgs = [ ] convenience in formatters (and run commands in general)?).

3 Likes

But… Are they guaranteed to run on the host system? Can a remote builder build them?

No, that definitely wouldn’t do the thing. Maybe there needs to be something that blocks an impure build from being run remotely at all?

@thufschmitt @edolstra may I ask what’s the reasoning behind providing builtins only if the corresponding experimental feature is enabled (rather than throwing an eval-error when using these without the necessary feature flags)[1]? We used to have this behavior a while ago and after a discussion decided to remove it in libexpr: throw a more helpful eval-error if a builtin is not available due to a missing feature-flag by Ma27 · Pull Request #5301 · NixOS/nix · GitHub.

I’d be curious in why you changed your mind :slight_smile:

[1] Only provide builtins is the corresponding experimental feature is enabled by edolstra · Pull Request #6314 · NixOS/nix · GitHub

4 Likes

It’s so you can write backwards-compatible code like:

if builtins ? fetchClosure then
  builtins.fetchClosure { fromPath = /nix/store/abcd...; }
else
  builtins.storePath /nix/store/abcd...

If fetchClosure throws an error, there is no way to do this.

4 Likes

Isn’t that exactly what we considered to be potentially impure? (ref libexpr: throw a more helpful eval-error if a builtin is not available due to a missing feature-flag by Ma27 · Pull Request #5301 · NixOS/nix · GitHub). I haven’t taken a close look at 2.8 yet, so I don’t know if this applies to your example, but it’s at least an issue with CA-related stuff.

Or more generally, if the implementation isn’t different I don’t see why an if is needed and if it is different, then this expression is impure since it depends on the Nix used to instantiate it, correct?

1 Like

So… suppose I want to package a nodejs app for deployment and I’m not too bothered about reproducibility.

Can impure derivations be used to e.g. package a node_modules directory produced by npm with network access and then grab the output as a fixed output for deployment?

So maybe a script that checks if the hash of package-lock.json changed, and if so, it builds the impure derivation and updates the output hash in the “real” package description?

Or was something like that already possible?

1 Like

--impure in Nix does not apply to derivations; it applies to evaluation. It allows an evaluation to refer to environmental information like environment variables or NIX_PATH entries or builtins.currentSystem. Derivations built this way will still be sandboxed on linux by default, meaning no network access unless you make it a fixed-output derivation with a pre-calculated hash. If you really must, you can pass --no-sandbox to disable this limitation but… don’t.

As an example similar to what you’re talking about, even in pure evaluation mode we can give a Cargo.lock file to the rust infrastructure in nixpkgs and it’ll read that file to determine the hashes of all the necessary dependencies’ sources at eval time, which it can use to evaluate fixed output derivations that download all those sources when built. No need for impurity or for disabling sandboxing.

3 Likes

Hmm ok. The problem with the nodejs ecosystem is that node modules aren’t read-only (with many modules downloading binaries etc during install) and can’t be easily symlinked.

There are a few projects that try to make Nix expressions for the modules but they often fail.

I suppose the only option is a derivation that copies an already prepared modules directory.

Wouldn’t it be more clear to name it —impure-eval then?

1 Like