Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to record a reproducible profile in nix (especially from nix-env)?

Tags:

nix

So, finally starting to get a stable nix environment that I can basically do all of my development in. Hooray!

Now I want to make it reproducible, as in yarn.lock (for those familiar with npm/yarn in javascript land) or Pipfile.lock (very similar for Python).

Basically the idea is that I would have a way to generate a similar lock file whenever I run nix-env -if my-env.nix, or after running this command, if that is how it would work. From this lock file, I could then exactly restore my nix profile, down to the exact versions of dependencies and sub-dependencies of the installed profile. This could be checked into git or whatever after testing out new improvements, and so a record of the environment would be maintained.

It seems to me this would be one of the most obvious use cases for Nix, and one of the major advantages over just using Docker (though the two aren't mutually exclusive), so I apologize if I've missed some relevant documentation.

like image 680
bbarker Avatar asked Mar 06 '23 06:03

bbarker


1 Answers

What you're probably looking for is a shell.nix file like this:

let
  pkgs = import (fetchTarball {
    url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
    sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
  }) {};
in pkgs.mkShell {
  buildInputs = with pkgs; [
    git
    hello
  ];
}

Upon calling nix-shell (which by default uses the shell.nix file in the current directory), you'll be in an environment with git and hello from the specific given nixpkgs revision. This can be reproduced among all nix users (okay almost*). I can really recommend using shell.nix files for all development.

Alternatively, there's also the lesser known -r flag to nix-env, which states that

--remove-all, -r

Remove all previously installed packages first. This is equivalent to running nix-env -e '.*' first, except that everything happens in a single transaction.

You can effectively use it to replace the stateful ~/.nix-profile/manifest.nix. Create a file env.nix containing:

let
  pkgs = import <nixpkgs> {};
in {
  inherit (pkgs) git hello;
}

Now running nix-env -ir env.nix will install exactly git and hello and remove everything else, so you can reproduce your nix-env installations with this single file. To install additional things: Add it to the file and run the command again. You can also pin nixpkgs to a specific version as in the file above to not care about your nix-channel setup (which is also stateful).

Edit: It's also possible to get some packages from your channel and some of a specific nixpkgs revision:

let
  pkgs = import <nixpkgs> {};
  fixed = import (fetchTarball {
    url = "https://github.com/NixOS/nixpkgs/archive/696c6bed4e8e2d9fd9b956dea7e5d49531e9d13f.tar.gz";
    sha256 = "1v3yrpj542niyxp0h3kffsdjwlrkvj0mg4ljb85d142gyn3sdzd4";
  }) {};
in {
  inherit (pkgs) git;
  inherit (fixed) hello;
}

*: The nix config, overlays and your system (Linux/Mac) can still influence this. It's a good idea to use import <nixpkgs> { config = {}; overlays = []; } for development to avoid this.

like image 90
Silvan Mosberger Avatar answered May 16 '23 06:05

Silvan Mosberger