| 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.
|
|
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 {});
mkShell {
buildInputs = [
gnumake sbcl multimarkdown python3Full emacs-nox toot nawk mandoc libxml2
];
}
```
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 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.
|