Simple reproduzierbare Entwicklungsumgebungen mit Nix

Sebastian hatte in seinem Blogpost Python-Abhängigkeiten projektbezogen verwalten das Problem, bestimmte Shell-Tools reproduzierbar für alle Entwickler bereitstellen zu müssen. In seinem Fall ging es dabei nur um awscli und awsebcli, beides Python-Tools von PyPI. Das geht relativ angenehm über seine genannte Methode mit pip und virtualenv. Selbst mit der Einschränkung auf PyPI als Quelle für die Abhängigkeiten zeigen sich jedoch schon die Vorteile von Nix.

Eine einfache shell.nix

Um die beiden Tools auf der CLI ausführen zu können, genügt es zunächst, eine einfache shell.nix zu schreiben – vorausgesetzt Nix ist installiert:

with import  {};
 
stdenv.mkDerivation {
  name = "test-project";
 
  buildInputs = [ awscli awsebcli ];
}

Dabei werden durch Zeile 1 die Pakete vom System-nixpkgs, d.h. aus dem NIX_PATH, in den Scope geholt. Daraus wird in Zeile 3 eine Derivation mit dem notwendig anzugebendem Namen „test-project“ erstellt. In Zeile 6 werden letztendlich den gewünschten CLI-Tools angegeben. Angewendet sieht das dann folgendermaßen aus:

$ which aws
aws not found
$ which eb
eb not found
$ nix-shell
[nix-shell:~/dev/test-project]$ which aws
/nix/store/vgishl8jcsnnqdmpgiyjchajr203jfz5-python2.7-awscli-1.14.41/bin/aws
[nix-shell:~/dev/test-project]$ which eb
/nix/store/rg5zj779vbk0m7lvnrvshzd3cbkyrh6n-awsebcli-3.12.3/bin/eb

Hier ist schön zu sehen, dass im System die Kommandos aws und eb nicht vorhanden sind. Sobald aber die nix-shell ausgeführt wird, ist beides im PATH. Damit ist das erste Ziel erreicht: Die Tools können in einem Shell-Environment ausgeführt werden, müssen aber nicht im System installiert werden. Noch hängt das allerdings vom lokalen NIX_PATH und dem damit verbundenen Nix-Channel oder lokalem nixpkgs-Checkout ab.

Den vollständigen Code dazu findet ihr auf GitHub: mayflower/nix-shell-env-example/tree/step-1

Reproduzierbare Versionen

Es hat sich in der Nix-Community eine Option etabliert, reproduzierbar eine feste nixpkgs-Version zu importieren ohne den NIX_PATH zu benutzen. Seit Nix 2 kann dafür builtins.fetchTarball benutzt werden.

diff --git a/shell.nix b/shell.nix
--- a/shell.nix                                                                                
+++ b/shell.nix                                                                                
@@ -1,4 +1,12 @@                                                                               
-with import  {};                                                                     
+let                                                                                           
+  fetchNixpkgs = import ./fetchNixpkgs.nix;                                                   
+  rev = "0e7c9b32817e5cbe61212d47a6cf9bcd71789322"; # 18.03-beta as of 22-Mar-2018            
+  nixpkgs = builtins.fetchTarball {                                                           
+    url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";                           
+    sha256 = "1dm777cmlhqcwlrq8zl9q2d87h3p70rclpvq36y43kp378f3pd0y";                          
+  };                                                                                          
+in                                                                                            
+with import nixpkgs { config = {}; overlays = []; };                                          

 stdenv.mkDerivation {
   name = "test-project";

Mit dieser Änderung wird nixpkgs jetzt auf einen festen Commit gepinnt – in diesem Fall auf den Stand von 18.03-beta am 22. März 2018. Um den Hash zu bekommen, kann man mit einem falschen Hash folgendes ausführen:

$ nix-shell   
error: store path mismatch in file downloaded from 'https://github.com/NixOS/nixpkgs/archive/0e7c9b32817e5cbe61212d47a6cf9bcd71789322.tar.gz'
nix
$ nix-prefetch-url --unpack https://github.com/NixOS/nixpkgs/archive/0e7c9b32817e5cbe61212d47a6cf9bcd71789322.tar.gz
unpacking...
path is '/nix/store/95crnqqa3qml6dmbpsh8cs5ax7v7vkzw-0e7c9b32817e5cbe61212d47a6cf9bcd71789322.tar.gz'
1dm777cmlhqcwlrq8zl9q2d87h3p70rclpvq36y43kp378f3pd0y

Den vollständigen Code zu diesem Beispiel findet ihr im Step 2 auf GitHub: mayflower/nix-shell-env-example/tree/step-2

Zusätzlicher Tipp: shellHook

Oft werden noch zusätzliche Bootstrap-Schritte gebraucht, um das lokale Setup auf einem Stand zu haben auf dem entwickelt werden kann. Das kann ein yarn install sein, das Linken von Git-Hooks in .git oder das setzen eines Shell-Alias, wie im folgenden Beispiel. Der shellHook wird dabei einfach beim Öffnen der nix-shell ausgeführt.

diff --git a/shell.nix b/shell.nix
index c43c49f..0c5b2ff 100644
--- a/shell.nix
+++ b/shell.nix
@@ -11,4 +11,9 @@ stdenv.mkDerivation {
   name = "test-project";
  
   buildInputs = [ awscli awsebcli ];
+
+  shellHook = ''
+    alias hi="echo Hello nix-shell User!"
+    hi
+  '';
 }</pre>

Ausgeführt sieht das dann so aus:

$ nix-shell           
Hello nix-shell User!
 
[nix-shell:~/dev/test-project]$ hi
Hello nix-shell User!
 
[nix-shell:~/dev/test-project]$ alias
alias hi='echo Hello nix-shell User!‘

Auch hier findet ihr den Code wieder auf GitHub: mayflower/nix-shell-env-example/tree/step-3

Für neue Blogupdates anmelden:


5 Gedanken zu “Simple reproduzierbare Entwicklungsumgebungen mit Nix

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.