| Title: How to pin a nix-shell environment using niv | |
| Author: Solène | |
| Date: 12 January 2022 | |
| Tags: nix nixos shell | |
| Description: I'll explain how to use niv to pin the nixpkgs version | |
| used for a nix-shell environment per project. | |
| # Introduction | |
| In the past I shared a bit about Nix nix-shell tool, allowing to have a | |
| "temporary" environment with a specific set of tools available. I'm | |
| using it on my blog to get all the dependencies required to rebuild it | |
| without having to remember what programs to install. | |
| But while this method was practical, as I'm running NixOS development | |
| version (called unstable channel), I have to download the new versions | |
| of the dependencies every time I use the nix shell. This is long on my | |
| DSL line, and also a waste of bandwidth. | |
| There is a way to pin the version of the packages, so I always use the | |
| exact same environment, whatever the version of my nix. | |
| # Use niv tool | |
| Let's introduce you to niv, a program to manage nix dependencies, for | |
| this how-to I will only use a fraction of its features. We just want | |
| it to init a directory with a default configuration pinning the nixpkgs | |
| repository to a branch / commit ID, and we will tell the shell to use | |
| this version. | |
| niv project GitHub homepage | |
| Let's start by running niv (you can get niv from nix package manager) | |
| in your directory: | |
| ```shell command | |
| niv init | |
| ``` | |
| It will create a nix/ directory with two files: sources.json and | |
| sources.nix, looking at the content is not fascinating here (you can | |
| take a look if you are curious though). The default is to use the | |
| latest nixpkgs release. | |
| # Create a shell.nix file | |
| My previous shell.nix file looked like this: | |
| ```shell.nix file content | |
| with (import <nixpkgs> {}); | |
| mkShell { | |
| buildInputs = [ | |
| gnumake sbcl multimarkdown python3Full emacs-nox toot nawk mandoc libxm… | |
| ]; | |
| } | |
| ``` | |
| Yes, I need all of this for my blog to work because I have texts in | |
| org-mode/markdown/mandoc/gemtext/custom. The blog also requires toot | |
| (for mastodon), sbcl (for the generator), make (for building and | |
| publishing). | |
| Now, I will make a few changes to use the nix/sources.nix file to tell | |
| it where to get the nixpkgs information, instead of <nixpkgs> which is | |
| the system global. | |
| ```shell.nix file content | |
| let | |
| sources = import ./nix/sources.nix; | |
| pkgs = import sources.nixpkgs {}; | |
| in | |
| with pkgs; | |
| pkgs.mkShell { | |
| buildInputs = [ | |
| gnumake sbcl multimarkdown python3Full emacs-nox | |
| toot nawk mandoc libxml2 | |
| ]; | |
| } | |
| ``` | |
| That's all! Now, when I run nix-shell in the directory, I always get | |
| the exact same shell and set of packages every day. | |
| # How to update? | |
| Because it's important to update from time to time, you can easily | |
| manage this using niv, it will bump the latest commit id of the branch | |
| of the nixpkgs repository: | |
| ```shell command | |
| niv update nixpkgs -b master | |
| ``` | |
| When a new release is out, you can switch to the new branch using: | |
| ```shell command | |
| niv modify nixpkgs -a branch=release-21.11 | |
| ``` | |
| # Using niv with configuration.nix | |
| It's possible to use niv to pin the git revision you want to use to | |
| build your system, it's very practical for many reasons like following | |
| the development version on multiple machines with the exact same | |
| revision. The snippet to use sources.nix for rebuilding the system is | |
| a bit different. | |
| Replace "{ pkgs, config, ... }:" with: | |
| ```configuration.nix code | |
| { | |
| sources ? import ./nix/sources.nix, | |
| pkgs ? import sources.nixpkgs {}, | |
| config, ... | |
| }: | |
| ``` | |
| Of course, you need to run "niv init" in /etc/nixos/ before if you want | |
| to manage your system with niv. | |
| # Extra tip: automatically run nix-shell with direnv | |
| It's particularly comfortable to have your shell to automatically load | |
| the environment when you cd into a project requiring a nix-shell, this | |
| is doable with the direnv program. | |
| nixos documentation about direnv usage | |
| direnv project homepage | |
| This can be done in 3 steps after you installed direnv in your profile: | |
| 1. create a file .envrc in the directory with the content "use nix" | |
| (without double quotes of course) | |
| 2. execute "direnv allow" | |
| 3. create the hook in your shell, so it knows how to do with direnv (do | |
| this only once) | |
| How to hook direnv in your shell | |
| Everytime you will cd into the directory, nix-shell will be | |
| automatically started. |