Un Dev Lambda

Nix Shell, pour un environnement de développement reproductible

Je travaille sur beaucoup de projets de développement qui nécessitent tous une bonne dose d'installation manuelle d'outillage. Prenons un projet Java, il faut télécharger et installer le bon JDK, installer un outil de build comme Maven. Imaginez aussi devoir jongler entre plusieurs projets, qui ont des versions de JDK & Maven différentes d'un projet à l'autre, ça devient assez compliqué à installer sur la machine, sans devoir faire des scripts maisons plus ou moins robustes.

Il existe un outil qui permet de remédier à cela, nix-shell. Une petite note pour le lecteur, je découvre nix au moment où j'écris cet article, il se peut donc qu'il ne soit pas précis et peu clair, n'hésitez pas à m'en faire part par courriel (adresse sur la page d'accueil).

nix-shell fait partie d'un projet beaucoup plus gros : Nix. Ce dernier est plusieurs choses :

Nix, l'idée générale

Nix est issue de travaux de recherches menés par Eelco Dolstra, ce dernier ayant rédigé une thèse sur la problématique que résout Nix. (La thèse).

L'idée de Nix est de proposer une solution pour permettre une répétabilité d'installation d'environnement, et de faire cohabiter plusieurs versions différentes d'un même programme, d'une même bibliothèque sur une machine.

Nix, la distribution Linux

Nix fournit une distribution Linux, appelée NixOS, permettant à l'utilisateur de déclarer grâce à un fichier de configuration quels sont les programmes, les configurations qui composent la machine de cet utilisateur. Cela permet donc de versionner (avec git par exemple) le fichier de configuration, de pouvoir répéter une installation Linux autant que nécessaire. Ce fichier de configuration est écrit dans un langage particulier, le langage Nix.

Nix, le langage

Nix est aussi un langage de programmation, dont le principal rôle est de déclarer des dépendances entre programmes, des configurations de construction de programme. Il a une syntaxe particulière, que je ne présenterai pas dans cet article.

Nix, un ensemble de programmes

Nix fournit plusieurs utilitaires : nix, nix-env, nix-shell. Nous nous attarderons sur nix-shell. Cette commande permet de démarrer un nouveau shell, en mettant à disposition dans le PATH toutes les dépendances que vous aurez déclaré dans un fichier appelé "shell.nix". En dehors de ce shell, vous n'auriez pas accès aux dépendances déclarées.

Installation de nix-shell

Pour profiter de nix-shell, il n'est pas nécessaire d'utiliser la distribution NixOS, il suffit juste d'installer l'utilitaire nix. Vous trouverez le lien ci-dessous pour l'installation.

Installation de Nix

Quelques informations concernant Nix

Quand nous utilisons ou installons un paquet Nix, ce dernier est stocké dans le dossier "/nix/store". Nix, de par son fonctionnement, a besoin de compiler toutes les dépendances que vous allez utiliser. Ceci peut provoquer d'énormes temps d'attente lorsqu'on demande des grosses dépendances, dû au temps de compilation. Pour pallier à ce problème, beaucoup de paquets nix ont déjà été compilés, et présent sur le site cache.nixos.org, que nix interroge systématiquement à l'installation de chaque paquet.

Cache nix officiel

Exemples d'utilisation

Exemple 1, installation d'une stack de développement Java

Je souhaite pouvoir travailler sur mon projet qui nécessite un JDK 11 ainsi que Maven. Imaginons n'avoir ni le JDK ni Maven d'installé.

Voici donc ce que j'obtiens si je lance :

$> java -version
bash: java: command not found

$> mvn --version
bash: mvn: command not found

Nous allons donc créer un fichier appelé "shell.nix", dont voici le contenu :

{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  nativeBuildInputs = [
    pkgs.jdk11
    pkgs.maven
  ];
}

Une fois le fichier créé, nous pouvons lancer la commande "nix-shell", qui va créer un shell dont le PATH aura été modifié pour accéder au JDK et à Maven.

Si je lance les commandes lancées ci-dessus j'obtiens :

$> java -version
openjdk version "11.0.15" 2022-04-19
OpenJDK Runtime Environment (build 11.0.15+0-adhoc..source)
OpenJDK 64-Bit Server VM (build 11.0.15+0-adhoc..source, mixed mode)

$> mvn --version
Apache Maven 3.8.5 (3599d3414f046de2324203b78ddcf9b5e4388aa0)
Maven home: /nix/store/gklahzzg3ahb5ksfk5bpbrw6c39mchjp-apache-maven-3.8.5/maven
Java version: 11.0.15, vendor: Oracle Corporation, runtime: /nix/store/9zby8a36ila90fkygxwwd10rdnlxrb98-openjdk-11.0.15+10/lib/openjdk
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.4.4-arch1-1", arch: "amd64", family: "unix"

On peut remarquer que le chemin de Maven et du JDK sont issues du dossier géré par Nix.

Si vous quittez ensuite le shell créé par "nix-shell" et que vous essayez de lancer les commandes ci-dessus, elle ne seront plus accessibles.

Nous pouvons maintenant versionner le fichier "shell.nix" avec le code du projet, ainsi les autres développeurs y auront accès, et pourront bénéficier des outils automatiquement, sans devoir les installer manuellement.

Exemple 2, découverte d'un outil quelconque

Je souhaite découvrir le langage purescript, et je m'aperçois dans la documentation qu'il faut installer un "node module" de manière globale, mais je n'ai pas envie de polluer mes "node modules" globaux pour un test. Je peux utiliser nix-shell. Selon la documentation de purescript, je devrais avoir un binaire appelé "purs" qui est le compilateur du langage.

$> purs --version
zsh: command not found: purs

Je crée donc un fichier "shell.nix" comme suit :

$> mkdir /tmp/test-purescript
$> cd /tmp/test-purescript
$> touch shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  nativeBuildInputs = [
    pkgs.purescript
  ];
}
$> nix-shell
$> purs --version
0.15.2

L'article touche à sa fin, j'espère qu'il vous aura permis de découvrir un outil très pratique. Je vous souhaite une bonne découverte des capacités de Nix, et vous recommande chaudement de le découvrir à travers les "Nix pills", une série d'articles décrivant tous ses concepts. Attendez vous cependant à une courbe d'apprentissage assez élevée.

Liens utiles

Site officiel Nix Documentation de référence Documentation du langage Le dépôt de paquets Nix Pills, une série de tutoriels