Lorsqu'on travaille sur un projet on l'on est obligé d'installer sur son système des dépendances, quelles soient strictement pour la production ou le développement même. Il peut arriver ce moment douloureux où une dépendance tire la moitié des dépôts de la Terre, polue l'installation et nous laisse des paquets qu'on oubliera de nettoyer. C'est une sensation que, personellement,  je déteste et qui a été une de mes motivations pour migrer sur NixOS.

Dans un monde parfait et idéal, les dépendances resteraient confinées dans chaque projets et seraient chargées uniquement lorsqu'on en a besoin. Faisable…? Oui !

Sans rentrer trop dans les détails deux briques sont nécessaires :

  1. Nix
  2. Direnv

Nix

Nix est un gestionnaire de paquet fonctionnel et reproductible, c'est sur ces fondations qu'est construit NixOS. Il possède de nombreuses fonctionnalités très utiles tel que le ramasse-miettes ("garbage collect") permettant de supprimer tout les «paquets» qui ne sont plus «utilisés».

Ce gestionnaire de paquet s'installe très facilement et ne modifie jamais le système déjà existant ; le rendant très simple à désinstaller.

La fonctionnalité utilisée sera le nix-shell, un shell  temporaire contenant uniquement les paquets demandés (ainsi que tout ce qui est naturellement présent dans le $PATH).

Imaginons que l'on souhaite travailler sur un projet à base JavaScript et que le gestionnaire de projet est Yarn, le fichier shell.nix minimaliste ressemblera à ça :

{ pkgs ? import <nixpkgs> {} }:

with pkgs;

mkShell {
  buildInputs = [
    yarn
  ];
}

Avec un shell actif dans le même répertoire que ce fichier, on peut l'invoquer avec la command nix-shell (ou nix-shell /chemin/du/fichier.nix) et le paquet Yarn devient disponible. Victoire !

Direnv

Cette brique n'est pas obligatoire mais simplifiera la vie pour utiliser les nix-shell. Penser à invoquer le shell en rentrant dans un projet et le quitter est une habitude et une charge mentale. Pour ne pas y penser l'outil direnv a été créé, il s'occupera tout seul de charger ce qu'il faut.

Si direnv est déjà installé avec le shell hook (documentation officiel) , il faut mettre use nix dans le fichier .envrc à la racine du projet, à côté du fichier shell.nix. Un coup de direnv allow puis le shell nix se chargera à chaque entrée dans le projet et se déchargera à chaque sortie du projet.

Une implémentation plus rapide de use_nix a été faite (dépôt GitHub).

direnv peut être installé via Nix !(nix-env -iA direnv). Ce n'est pas incompatible et retire une dépendance du gestionnaire de paquet du système

Bonus : Emacs

Un défaut de la méthode  nix-shell (+ direnv) est que l'éditeur de texte n'a plus les dépendances de développement dans son $PATH, pouvant par exemple contenir les linters ou formatter de code.

Le paquet direnv ou lorri (Doom Emacs) permet à Emacs d'avoir connaissance des dépendances et fonctionner à son plein potentiel ! (il ne faut pas oublier d'activer les modes majeurs, spécifiques aux langages)