Partie 5 : Externaliser les sources
Bonjour à toutes et tous! 😀
Cinquième article sur Nix.
Aujourd'hui nous allons utiliser des sources qui ne sont pas dans la dérivation, cela rendra notre dérivation plus souple.
Plus de sources !
Jusqu'à présent notre dérivation ressemble à ceci:
with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "pkgs.bash/bin/bash";
args = [
"-c"
''
gcc $SOURCE -o $out
''
];
PATH = "pkgs.gcc/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
void main() {
printf("Hello World\n");
}
'';
}
Nous utilisons la varaible d'environnement "$SOURCE" pour stocker un chemin de fichier local que l'on génère directement à partir de la fonction toFile
.
C'est très bien si l'on a qu'un seul fichier mais si l'on commence à faire grandir le projet ça va devenir de plus en plus compliqué de suivre la cadence.
Exemple deux fichiers de sources nous donne:
with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "pkgs.bash/bin/bash";
args = [
"-c"
''
mkdir src
cd src
ln -s $SOURCE main.c
ln -s $SOURCE2 hello.c
gcc main.c -o $out
''
];
PATH = "pkgs.gcc/bin:pkgs.coreutils/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
#include "hello.c"
void main() {
printf("%s\n", hello());
}
'';
SOURCE2 = builtins.toFile "hello.c" ''
const char* hello() {
return "Hello World";
}
'';
}
- On introduit la dérivations
pkgs.coreutils
qui contient les commandesln
etmkdir
. - On créé un dossier "src" et on rentre dedans
- On symlink les sources dedans
Et si on veut le faire de manière cannonique, il faut en plus rajouter un header.
with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "pkgs.bash/bin/bash";
args = [
"-c"
''
mkdir src
cd src
ln -s $SOURCE main.c
ln -s $SOURCE2 hello.c
ln -s $HEADER hello.h
gcc main.c hello.c -o $out
''
];
PATH = "pkgs.gcc/bin:pkgs.coreutils/bin";
SOURCE = builtins.toFile "main.c" ''
#include "stdio.h"
#include "hello.h"
void main() {
printf("%s\n", hello());
}
'';
HEADER = builtins.toFile "hello.h" ''
const char* hello();
'';
SOURCE2 = builtins.toFile "hello.c" ''
#include "hello.h"
const char* hello() {
return "Hello World";
}
'';
}
Si en plus, nous voulons respecter les standards, on peut même se créer le Makefile. 😇
Mais pour ce faire nous allons déporter nos sources.
Fetch
Pour tester cela, j'ai créé un projet sur github.
Nous avons appris de notre erreur, il nous faut quelque chose de stable dans le temps, de reproductible.
L'intérêt de git est de créer des signatures uniques pour chaque modification. Nous allons utiliser cette propriété pour s'assurer de la stabilité de notre dérivation.
Sur github, il est possible de voir tous les commits d'une branche.
Et ainsi récupérer le SHA1 de ce commit.
On peut alors récupérer les sources sous la forme d'une archive via une URL formatée comme suit:
https://github.com/<projet>/archive/<SHA1>.tar.gz
Mon commit est le 639841dcbc59ed24a461a9dadf6234073cdafad0
.
Essayons de récupérer les sources, pour cela nous allons réutiliser la commande fetchTarball
.
nix-repl> fetchTarball "https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz"
"/nix/store/83z8gfh3lmi8psikgv39fpl67awkg4fg-source"
$ ls -l /nix/store/83z8gfh3lmi8psikgv39fpl67awkg4fg-source
-r--r--r-- 1 root root 70 janv. 1 1970 hello.c
-r--r--r-- 1 root root 20 janv. 1 1970 hello.h
-r--r--r-- 1 root root 1295 janv. 1 1970 LICENSE
-r--r--r-- 1 root root 90 janv. 1 1970 main.c
-r--r--r-- 1 root root 42 janv. 1 1970 Makefile
-r--r--r-- 1 root root 83 janv. 1 1970 README.md
Magnifique, nous avons nos sources. 😃
Pour les construire, nous allons utiliser la méthode standard du Makefile.
Pour constuire les sources, il faut s'y déplacer puis lancer la commande make
.
Le Makefile ressemble à ceci:
:
On remarque le ${out}
qui est directement défini par la dérivation. La sortie de compilation sera au bon endroit.
Nous pouvons créer la dérivation qui va bien.
nix-repl> :b with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
cd $SOURCE
make
''
];
PATH = "${pkgs.gcc}/bin:${pkgs.coreutils}/bin:${pkgs.gnumake}/bin";
SOURCE = fetchTarball "https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz";
}
This derivation produced the following outputs:
out -> /nix/store/mbx1qs39fgqiyfiikfx98gbs9vvqqxnm-hello-world
$ /nix/store/mbx1qs39fgqiyfiikfx98gbs9vvqqxnm-hello-world
Hello world!
De cette manière les sources de la dérivations ne sont plus contenues par elle, mais déportées tout en conservant l'aspect de reproductibilité.
En parlant de reproductibilité, nous pouvons faire mieux. 😃
Checksum
Nix propose un outil nix-prefetch-url
pour calculer la somme de contrôle ou checksum de ce que l'on télécharge.
$ nix-prefetch-url --unpack https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz
path is '/nix/store/livh28m4dpk96q347s8j17fv2k5drb8g-639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz'
0pvjw2kf0fwv569j2caqc983qk3x78znj52brr1a0av8f2c8rwjl
Attention!
L'argument
--unpack
est important, car sinon c'est la signature n'est pas correcte, en effet lefetchTarball
procède au désarchivage du tar.gz après son téléchargement.Sans
--unpack
on calcule la signature de l'archive pas de son contenu$ nix-prefetch-url https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz path is '/nix/store/qi5nmqi9np2jbjw4f52zakr10pa6j4pr-639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz' 1wh3vf4ydvvxyiw18wwdyr1xgcqpxnlrl0wl2wcjsysflbrxlhgp
D'ailleurs, si l'on utilise le mauvais checksum:
nix-repl> :b with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
cd $SOURCE
make
''
];
PATH = "${pkgs.gcc}/bin:${pkgs.coreutils}/bin:${pkgs.gnumake}/bin";
SOURCE = fetchTarball {
url = "https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz";
sha256 = "1wh3vf4ydvvxyiw18wwdyr1xgcqpxnlrl0wl2wcjsysflbrxlhgp";
};
}
error: hash mismatch in file downloaded from 'https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz':
specified: sha256:1wh3vf4ydvvxyiw18wwdyr1xgcqpxnlrl0wl2wcjsysflbrxlhgp
got: sha256:0pvjw2kf0fwv569j2caqc983qk3x78znj52brr1a0av8f2c8rwjl
Le système signale une incohérence entre le checksum calculé d'une part et le checksum spécifié, d'autre part.
Si le SHA1 correspond, le build est possible.
nix-repl> :b with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz") {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "${pkgs.bash}/bin/bash";
args = [
"-c"
''
cd $SOURCE
make
''
];
PATH = "${pkgs.gcc}/bin:${pkgs.coreutils}/bin:${pkgs.gnumake}/bin";
SOURCE = fetchTarball {
url = "https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz";
sha256 = "0pvjw2kf0fwv569j2caqc983qk3x78znj52brr1a0av8f2c8rwjl";
};
}
This derivation produced the following outputs:
out -> /nix/store/mbx1qs39fgqiyfiikfx98gbs9vvqqxnm-hello-world
Et on peut faire de de même avec le nixpkgs
.
$ nix-prefetch-url --unpack https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz
1xk1f62n00z7q5i3pf4c8c4rlv5k4jwpgh0pqgzw1l40vhdkixk9
On peut alors fixé également spécifier le SHA1 du nixpkgs
dans la dérivation.
with import (fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/release-21.11.tar.gz";
sha256 = "1xk1f62n00z7q5i3pf4c8c4rlv5k4jwpgh0pqgzw1l40vhdkixk9";
}) {};
derivation {
name = "hello-world";
system = "x86_64-linux";
builder = "pkgs.bash/bin/bash";
args = [
"-c"
''
cd $SOURCE
make
''
];
PATH = "pkgs.gcc/bin:pkgs.coreutils/bin:pkgs.gnumake/bin";
SOURCE = fetchTarball {
url = "https://github.com/Akanoa/nix-hello/archive/639841dcbc59ed24a461a9dadf6234073cdafad0.tar.gz";
sha256 = "0pvjw2kf0fwv569j2caqc983qk3x78znj52brr1a0av8f2c8rwjl";
};
}
Là on commence à avoir quelque chose qui a de la gueule! 🤩
Ainsi, même si les données pointée par l'URL changent, nous sommes capable de le détecter et d'annuler la réalisation de la dérivation.
Ce mécanisme permet de s'assurer que les sources n'ont pas été corrompues d'une manière ou d'une autre.
Conclusion
Nous commençons à nous rapprocher d'une dérivation qui est utilisable pour de vrais projets.
Dans la partie 6, nous verrons comment construire des projets plus normalisés via mkDerivation
.
Merci de votre lecture ❤️
Ce travail est sous licence CC BY-NC-SA 4.0.