\input texinfo
@c ===========================================================================
@c
@c This file was generated with po4a. Translate the source file.
@c
@c ===========================================================================

@c -*-texinfo-*-

@c %**start of header
@setfilename guix-cookbook.fr.info
@documentencoding UTF-8
@documentlanguage fr
@frenchspacing on
@settitle Livre de recettes de GNU Guix
@c %**end of header

@c Onion service for ci.guix.gnu.org.
@set SUBSTITUTE-TOR-URL https://4zwzi66wwdaalbhgnix55ea3ab4pvvw66ll2ow53kjub6se4q2bclcyd.onion

@copying
Copyright @copyright{} 2019, 2022 Ricardo Wurmus@*
Copyright @copyright{} 2019 Efraim Flashner@*
Copyright @copyright{} 2019 Pierre Neidhardt@*
Copyright @copyright{} 2020 Oleg Pykhalov@*
Copyright @copyright{} 2020 Matthew Brooks@*
Copyright @copyright{} 2020 Marcin Karpezo@*
Copyright @copyright{} 2020 Brice Waegeneire@*
Copyright @copyright{} 2020 André Batista@*
Copyright @copyright{} 2020 Christine Lemmer-Webber@*
Copyright @copyright{} 2021 Joshua Branson@*
Copyright @copyright{} 2022 Maxim Cournoyer*

Vous avez la permission de copier, distribuer ou modifier ce document sous
les termes de la Licence GNU Free Documentation, version 1.3 ou toute
version ultérieure publiée par la Free Software Foundation ; sans section
invariante, texte de couverture et sans texte de quatrième de couverture.
Une copie de la licence est incluse dans la section intitulée « GNU Free
Documentation License ».
@end copying

@dircategory Administration système
@direntry
* Livre de recettes de Guix: (guix-cookbook.fr).  Didacticiels et exemples 
                                                    pour GNU Guix.
@end direntry

@titlepage
@title Livre de recettes de GNU Guix
@subtitle Didacticiels et exemples d'utilisation du gestionnaire de paquets GNU Guix
@author Les développeurs de GNU Guix

@page
@vskip 0pt plus 1filll

@insertcopying
@end titlepage

@contents

@c *********************************************************************
@node Top
@top Livre de recettes de GNU Guix

Ce document propose des didacticiels et des exemples détaillés pour
GNU@tie{}Guix, un outil de gestion des paquets fonctionnel écrit pour le
système GNU. @pxref{Top,,, guix.fr, le manuel de référence de Guix} pour
plus de détails sur le système, son API et les concepts associés.

@c TRANSLATORS: You can replace the following paragraph with information on
@c how to join your own translation team and how to report issues with the
@c translation.
Ce manuel est aussi disponible en anglais (@pxref{Top,,, guix-cookbook, GNU
Guix Cookbook}) et en allemand (@pxref{Top,,, guix-cookbook.de,
GNU-Guix-Kochbuch}). Si vous désirez traduire ce document dans votre langue
maternelle, rejoignez
@uref{https://translate.fedoraproject.org/projects/guix/documentation-cookbook,
Weblate} (@pxref{Traduire Guix,,, guix.fr, le manuel de référence de Guix}).

@menu
* Didacticiels pour Scheme::  Découvrez votre nouveau langage préféré !
* Empaquetage::              Didacticiel d'empaquetage
* Configuration du système::  Personnalisation du système GNU
* Conteneurs::               Environnements isolés et systèmes imbriqués
* Gestion avancée des paquets::  Le pouvoir aux utilisateurs !
* Gestion de l'environnement::  Environnement de contrôle

* Remerciements::            Merci !
* La licence GNU Free Documentation::  La licence de ce document.
* Index des concepts::       Les concepts.

@detailmenu
 --- Liste détaillée des nœuds ---



Didacticiels pour Scheme



* Cours accéléré du langage Scheme::  Apprenez les bases du langage 
                                           Scheme

Empaquetage



* Didacticiel d'empaquetage::  Ajoutons un paquet à Guix !

Configuration du système



* Connexion automatique à un TTY donné::  Connecter automatiquement un 
                                              utilisateur sur un TTY donné
* Personnalisation du noyau::  Créer et utiliser un noyau Linux 
                                 personnalisé sur le système Guix.
* L'API de création d'images du système Guix::  Personnaliser des images 
                                                    pour des plateformes 
                                                    particulières.
* Utiliser des clés de sécurité::  Comment utiliser des clés de 
                                        sécurité avec le système Guix.
* Se connecter à un VPN Wireguard::  Se connecter à un VPN Wireguard.
* Personnaliser un gestionnaire de fenêtres::  Gérer la personnalisation 
                                                  d'un gestionnaire de 
                                                  fenêtres sur le système 
                                                  Guix.
* Lancer Guix sur un serveur Linode::  Lancer Guix sur un serveur Linode
* Mettre en place un montage dupliqué::  Mettre en place un montage 
                                            dupliqué dans une définition de 
                                            système de fichiers.
* Récupérer des substituts via Tor::  Configurer le démon Guix pour 
                                          récupérer les substituts via Tor.
* Configurer NGINX avec Lua::  Configurer le serveur web NGINX pour qu'il 
                                 charge des modules Lua.
* Serveur de musique avec l'audio bluetooth::  Lecteur de musique sans 
                                                 affichage avec entrée 
                                                 bluetooth.

@end detailmenu
@end menu

@c *********************************************************************
@node Didacticiels pour Scheme
@chapter Didacticiels pour Scheme

GNU@tie{}Guix est écrit dans le langage de programmation Scheme.  Nombre de
ses fonctionnalités peuvent être consultées et manipulées par
programmation. Vous pouvez utiliser Scheme entre autres pour générer des
définitions de paquets, pour les modifier, pour les compiler ou pour
déployer des systèmes d'exploitation entiers.

Connaître les bases de la programmation en Scheme vous permettra d'utiliser
de nombreuses fonctionnalités avancées de Guix --- et vous n'avez pas besoin
d'être un·e programmeur·euse chevronné·e !

C'est parti !

@node Cours accéléré du langage Scheme
@section Cours accéléré du langage Scheme

@cindex Scheme, cours accéléré

Guix utilise l'implémentation Guile du langage Scheme. Pour commencer à
jouer avec le langage, installez-le avec @code{guix install guile} et
démarrer une @dfn{BLÉA} (@dfn{REPL} en anglais), une
@uref{https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop,
@dfn{boucle de lecture, évaluation, affichage}}, en lançant @code{guile} sur
la ligne de commande.

Vous pouvez également lancer la commande @code{guix shell guile -- guile} si
vous préférez ne pas installer Guile dans votre profil utilisateur.

Dans les exemples suivants, les lignes montrent ce que vous devez taper sur
la REPL ; les lignes commençant par « @result{} » montrent le résultat de
l'évaluation, tandis que les lignes commençant par « @print{} » montrent ce
qui est affiché. @xref{Using Guile Interactively,,, guile, GNU Guile
Reference Manual}, pour plus d'information sur la REPL.

@itemize
@item
La syntaxe de Scheme se résume à un arbre d'expressions (ou une
@emph{s-expression} dans le jargon Lisp). Une expression peut être un
litéral comme un nombre ou une chaîne de caractères, ou composée d'une liste
d'autres éléments composés et litéraux, entourée de
parenthèses. @code{#true} et @code{#false} (abrégés @code{#t} et @code{#f})
correspondent aux booléens « vrai » et « faux ».

Voici des exemples d'expressions valides :

@lisp
"Bonjour le monde !"
@result{} "Bonjour le monde !"

17
@result{} 17

(display (string-append "Bonjour " "Guix" "\n"))
@print{} Bonjour Guix
@result{} #<unspecified>
@end lisp

@item
Ce dernier exemple est un appel de fonction imbriqué dans un autre appel de
fonction. Lorsqu'une expression parenthésée est évaluée, le premier élément
est la fonction et le reste sont les arguments passés à la fonction. Chaque
fonction renvoie la dernière expression évaluée.

@item
On peut déclarer des fonctions anonymes avec le terme @code{lambda} :

@lisp
(lambda (x) (* x x))
@result{} #<procedure 120e348 at <unknown port>:24:0 (x)>
@end lisp

La procédure ci-dessus renvoie le carré de son argument. Comme tout est une
expression, l'expression @code{lambda} renvoie une procédure anonyme, qui
peut ensuite être appliquée à un argument :

@lisp
((lambda (x) (* x x)) 3)
@result{} 9
@end lisp

@item
On peut assigner un nom global à tout ce qu'on veut avec @code{define} :

@lisp
(define a 3)
(define square (lambda (x) (* x x)))
(square a)
@result{} 9
@end lisp

@item
On peut définir des procédure de manière plus concise avec la syntaxe
suivante :

@lisp
(define (square x) (* x x))
@end lisp

@item
On peut créer une structure de liste avec la procédure @code{list} :

@lisp
(list 2 a 5 7)
@result{} (2 3 5 7)
@end lisp

@item
La @dfn{quote} (l'apostrophe) désactive l'évaluation d'une expression
parenthésée : le premier élément n'est pas appelé avec les autres éléments
en argument (@pxref{Expression Syntax, quote,, guile, GNU Guile Reference
Manual}). Donc, il renvoie une liste de termes.

@lisp
'(display (string-append "Bonjour " "Guix" "\n"))
@result{} (display (string-append "Bonjour " "Guix" "\n"))

'(2 a 5 7)
@result{} (2 a 5 7)
@end lisp

@item
La @dfn{quasiquote} (l'apostrophe à l'envers) désactive l'évaluation d'une
expression parenthésée jusqu'à ce qu'un @dfn{unquote} (une virgule) la
réactive. De cette manière, on garde un contrôle fin sur ce qui est évalué
et sur ce qui ne l'est pas.

@lisp
`(2 a 5 7 (2 ,a 5 ,(+ a 4)))
@result{} (2 a 5 7 (2 3 5 7))
@end lisp

Remarquez que le résultat ci-dessus est une liste d'éléments mixtes : des
nombres, des symboles (ici @code{a}) et le dernier élément est aussi une
liste.

@item
On peut nommer localement plusieurs variables avec @code{let} (@pxref{Local Bindings,,, guile, GNU Guile Reference Manual}) :

@lisp
(define x 10)
(let ((x 2)
      (y 3))
  (list x y))
@result{} (2 3)

x
@result{} 10

y
@error{} In procedure module-lookup: Unbound variable: y
@end lisp

On peut utiliser @code{let*} pour permettre au déclarations de variables
ultérieures d'utiliser les définitions précédentes.

@lisp
(let* ((x 2)
       (y (* x 3)))
  (list x y))
@result{} (2 6)
@end lisp

@item
On utilise typiquement des @dfn{mot-clés} pour identifier les paramètres
nommés d'une procédure. Ils sont précédés de @code{#:} (dièse, deux-points)
suivi par des caractères alphanumériques :
@code{#:comme-ça}. @xref{Keywords,,, guile, GNU Guile Reference Manual}.

@item
On utilise souvent le signe pourcent @code{%} pour les variables globales
non modifiables à l'étape de construction. Remarquez que ce n'est qu'une
convention, comme @code{_} en C. Scheme traite @code{%} de la même manière
que les autres lettres.

@item
On peut créer des modules avec @code{define-module} (@pxref{Creating Guile Modules,,, guile, GNU Guile Reference Manual}). Par exemple :

@lisp
(define-module (guix build-system ruby)
  #:use-module (guix store)
  #:export (ruby-build
            ruby-build-system))
@end lisp

défini le module @code{guix build-system ruby} qui doit se situer dans
@file{guix/build-system/ruby.scm} quelque part dans le chemin de recherche
de Guile. Il dépend du module @code{(guix store)} et exporte deux variables,
@code{ruby-build} et @code{ruby-build-system}.
@end itemize

@quotation Pour aller plus loin
Scheme est un langage qui a été beaucoup utilisé pour enseigner la
programmation et vous trouverez plein de supports qui l'utilisent. Voici une
liste de documents qui vous en apprendront plus sur le Scheme :

@itemize
@item
@uref{https://spritely.institute/static/papers/scheme-primer.html, @i{A
Scheme Primer}}, par Christine Lemmer-Webber et le Spritely Institute.

@item
@uref{http://www.troubleshooters.com/codecorn/scheme_guile/hello.htm, Scheme
at a Glance}, par Steve Litt.

@item
@uref{https://mitpress.mit.edu/sites/default/files/sicp/index.html,
@i{Structure and Interpretation of Computer Programs}}, par Harold Abelson
et Gerald Jay Sussman, avec Julie Sussman.  Souvent appelé ``SICP'', ce
livre est une référence.

Vous pouvez aussi l'installer et le lire sur votre ordinateur :

@example
guix install sicp info-reader
info sicp
@end example

Un @uref{https://sarabander.github.io/sicp/, ebook non officiel} est aussi
disponible.

@end itemize

Vous trouverez plus de livres, de didacticiels et d'autres ressources sur
@url{https://schemers.org/}.
@end quotation


@c *********************************************************************
@node Empaquetage
@chapter Empaquetage

@cindex empaquetage

Ce chapitre est conçu pour vous enseigner comment ajouter des paquets à la
collection de paquets de GNU Guix. Pour cela, vous devrez écrire des
définitions de paquets en Guile Scheme, les organiser en modules et les
construire.

@menu
* Didacticiel d'empaquetage::  Un didacticiel sur la manière d'ajouter des 
                                 paquets à Guix.
@end menu

@node Didacticiel d'empaquetage
@section Didacticiel d'empaquetage

GNU Guix se démarque des autres gestionnaire de paquets en étant
@emph{bidouillable}, surtout parce qu'il utilise
@uref{https://www.gnu.org/software/guile/,GNU Guile}, un langage de
programmation de haut-niveau puissant, l'un des dialectes
@uref{https://fr.wikipedia.org/wiki/Scheme, Scheme} de
@uref{https://fr.wikipedia.org/wiki/Lisp, la famille Lisp}.

Les définitions de paquets sont aussi écrites en Scheme, ce qui le rend plus
puissant de manière assez unique par rapport aux autres gestionnaires de
paquets qui utilisent des scripts shell ou des langages simples.

@itemize
@item
Vous pouvez utiliser des fonctions, des structures, des macros et toute
l'expressivité de Scheme dans vos définitions de paquets.

@item
L'héritage facilite la personnalisation d'un paquet en héritant d'un autre
et en modifiant uniquement les points nécessaires.

@item
Traitement par lot : la collection des paquets entière peut être analysée,
filtrée et traitée. Vous voulez construire un serveur sans interface
graphique ? C'est possible. Vous voulez tout reconstruire à partir des
sources avec des drapeaux d'optimisation spécifiques ? Passez l'argument
@code{#:make-flags "…"} à la liste des paquets. Ce ne serait pas aberrant de
penser @uref{https://wiki.gentoo.org/wiki/USE_flag, au drapeau USE de
Gentoo}, mais cela va plus loin : la personne qui crée les paquets n'a pas
besoin de penser à l'avance à ces changements, ils peuvent être
@emph{programmés} par l'utilisateur ou l'utilisatrice !
@end itemize

Le didacticiel suivant traite des bases de la création de paquets avec
Guix. Il ne présuppose aucune connaissance du système Guix ni du langage
Lisp. On ne s'attend qu'à ce que vous aillez une certaine familiarité avec
la ligne de commande et des connaissances de base en programmation.

@node Un paquet « hello world »
@subsection Un paquet « hello world »

La section « Définir des paquets » du manuel explique les bases de
l'empaquetage avec Guix (@pxref{Définir des paquets,,, guix.fr, le manuel de
référence de GNU Guix}). Dans la section suivante, nous reparlerons en
partie de ces bases.

GNU@tie{}Hello est un exemple de projet qui sert d'exemple idiomatique pour
l'empaquetage. Il utilise le système de construction de GNU
(@code{./configure && make && make install}). Guix fournit déjà une
définition de paquet qui est un parfait exemple pour commencer. Vous pouvez
voir sa déclaration avec @code{guix edit hello} depuis la ligne de
commande. Voyons à quoi elle ressemble :

@lisp
(define-public hello
  (package
    (name "hello")
    (version "2.10")
    (source (origin
              (method url-fetch)
              (uri (string-append "mirror://gnu/hello/hello-" version
                                  ".tar.gz"))
              (sha256
               (base32
                "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
    (build-system gnu-build-system)
    (synopsis "Hello, GNU world: An example GNU package")
    (description
     "GNU Hello prints the message \"Hello, world!\" and then exits.  It
serves as an example of standard GNU coding practices.  As such, it supports
command-line arguments, multiple languages, and so on.")
    (home-page "https://www.gnu.org/software/hello/")
    (license gpl3+)))
@end lisp

Comme vous pouvez le voir, la plus grosse partie est assez simple. Mais
examinons les champs ensemble :

@table @samp
@item name
Le nom du projet. Avec les conventions de Scheme, on préfère le laisser en
minuscule, sans tiret du bas, en séparant les mots par des tirets.

@item source
Ce champ contient une description de l'origine du code
source. L'enregistrement @code{origin} contient ces champs :

@enumerate
@item La méthode, ici @code{url-fetch} pour télécharger via HTTP/FTP, mais d'autres méthodes
    existent, comme @code{git-fetch} pour les dépôts Git.
@item L'URI, qui est typiquement un emplacement @code{https://} pour @code{url-fetch}. Ici
    le code spécial « mirror://gnu » fait référence à une ensemble
d'emplacements bien connus, qui peuvent tous être utilisés par Guix pour
récupérer la source, si l'un d'entre eux échoue.
@item La somme de contrôle @code{sha256} du fichier demandé. C'est essentiel pour s'assurer
    que la source n'est pas corrompue. Remarquez que Guix fonctionne avec des
chaînes en base32, d'où l'appel à la fonction @code{base32}.
@end enumerate

@item build-system

C'est ici que la puissance d'abstraction du langage Scheme brille de toute
sa splendeur : dans ce cas, le @code{gnu-build-system} permet d'abstraire
les fameuses invocations shell @code{./configure && make && make
install}. Parmi les autres systèmes de construction on trouve le
@code{trivial-build-system} qui ne fait rien et demande de programmer toutes
les étapes de construction, le @code{python-build-system},
@code{emacs-build-system} et bien d'autres (@pxref{Systèmes de construction,,, guix.fr, le manuel de référence de GNU Guix}).

@item synopsis
Le synopsis devrait être un résumé court de ce que fait le paquet. Pour
beaucoup de paquets, le slogan de la page d'accueil du projet est approprié
pour le synopsis.

@item description
Comme le synopsis, vous pouvez réutiliser la description de la page
d'accueil du projet. Remarquez que Guix utilise la syntaxe Texinfo.

@item home-page
Utilisez l'adresse en HTTPS si elle est disponible.

@item license
Voir @code{guix/licenses.scm} dans les sources du projet pour une liste
complète des licences disponibles.
@end table

Il est temps de construire notre premier paquet ! Rien de bien compliqué
pour l'instant : nous allons garder notre exemple avec @code{my-hello}, une
copie de la déclaration montrée plus haut.

Comme avec le rituel « Hello World » enseigné avec la plupart des langages
de programmation, ce sera sans doute l'approche la plus « manuelle »
d'empaquetage que vous utiliserez. Nous vous montrerons une configuration
idéale plus tard, pour l'instant nous allons suivre la voie la plus simple.

Enregistrez ce qui suit dans un fichier nommé @file{my-hello.scm}.

@lisp
(use-modules (guix packages)
             (guix download)
             (guix build-system gnu)
             (guix licenses))

(package
  (name "my-hello")
  (version "2.10")
  (source (origin
            (method url-fetch)
            (uri (string-append "mirror://gnu/hello/hello-" version
                                ".tar.gz"))
            (sha256
             (base32
              "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
  (build-system gnu-build-system)
  (synopsis "Hello, Guix world: An example custom Guix package")
  (description
   "GNU Hello prints the message \"Hello, world!\" and then exits.  It
serves as an example of standard GNU coding practices.  As such, it supports
command-line arguments, multiple languages, and so on.")
  (home-page "https://www.gnu.org/software/hello/")
  (license gpl3+))
@end lisp

Nous allons expliquer le code supplémentaire dans un moment.

Essayez de jouer avec les différentes valeurs des différents champs. Si vous
changez la source, vous devrez mettre à jour la somme de contrôle. En fait,
Guix refusera de construire quoi que ce soit si la somme de contrôle donnée
ne correspond pas à la somme de contrôle calculée de la source
téléchargée. Pour obtenir la bonne somme de contrôle pour une déclaration de
paquet, vous devrez télécharger la source, calculer la somme de contrôle
sha256 et la convertir en base32.

Heureusement, Guix peut automatiser cette tache pour nous ; tout ce qu'on
doit faire est de lui fournir l'URI :

@c TRANSLATORS: This is example shell output.
@example sh
$ guix download mirror://gnu/hello/hello-2.10.tar.gz

Starting download of /tmp/guix-file.JLYgL7
From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz...
following redirection to `https://mirror.ibcp.fr/pub/gnu/hello/hello-2.10.tar.gz'...
 …10.tar.gz  709KiB                                 2.5MiB/s 00:00 [##################] 100.0%
/gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz
0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i
@end example

Dans ce cas particulier, la sortie nous dit quel miroir a été choisi. Si le
résultat de la commande au-dessus n'est pas le même que ce qui est montré,
mettez à jour votre déclaration @code{my-hello} en fonction.

Remarquez que les archives des paquets GNU sont accompagnées de leur
signature OpenPGP, donc vous devriez vérifier la signature de cette archive
avec « gpg » pour l'authentifier avant d'aller plus loin :

@c TRANSLATORS: This is example shell output.
@example sh
$ guix download mirror://gnu/hello/hello-2.10.tar.gz.sig

Starting download of /tmp/guix-file.03tFfb
From https://ftpmirror.gnu.org/gnu/hello/hello-2.10.tar.gz.sig...
following redirection to `https://ftp.igh.cnrs.fr/pub/gnu/hello/hello-2.10.tar.gz.sig'...
 ….tar.gz.sig  819B                                                                                                                       1.2MiB/s 00:00 [##################] 100.0%
/gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig
0q0v86n3y38z17rl146gdakw9xc4mcscpk8dscs412j22glrv9jf
$ gpg --verify /gnu/store/rzs8wba9ka7grrmgcpfyxvs58mly0sx6-hello-2.10.tar.gz.sig /gnu/store/hbdalsf5lpf01x4dcknwx6xbn6n5km6k-hello-2.10.tar.gz
gpg: Signature faite le dim. 16 nov. 2014 13:08:37 CET
gpg:                avec la clef RSA A9553245FDE9B739
gpg: Bonne signature de « Sami Kerola (https://www.iki.fi/kerolasa/) <kerolasa@@iki.fi> » [inconnu]
gpg: Attention : cette clef n'est pas certifiée avec une signature de confiance.
gpg:             Rien n'indique que la signature appartient à son propriétaire.
Empreinte de clef principale : 8ED3 96E3 7E38 D471 A005  30D3 A955 3245 FDE9 B739
@end example

Vous pouvez ensuite lancer

@c TRANSLATORS: Do not translate this command
@example sh
$ guix package --install-from-file=my-hello.scm
@end example

Vous devriez maintenant avoir @code{my-hello} dans votre profil !

@c TRANSLATORS: Do not translate this command
@example sh
$ guix package --list-installed=my-hello
my-hello	2.10	out
/gnu/store/f1db2mfm8syb8qvc357c53slbvf1g9m9-my-hello-2.10
@end example

Nous sommes allés aussi loin que possible sans aucune connaissance de
Scheme. Avant de continuer sur des paquets plus complexes, il est maintenant
temps de vous renforcer sur votre connaissance du langage Scheme. @pxref{Cours accéléré du langage Scheme} pour démarrer.

@node Configuration
@subsection Configuration

Dans le reste de ce chapitre, nous nous appuierons sur vos connaissances de
base du langage Scheme. Maintenant voyons les différentes configurations
possibles pour travailler sur des paquets Guix.

Il y a plusieurs moyens de mettre en place un environnement d'empaquetage
pour Guix.

Nous vous recommandons de travailler directement dans le dépôt des sources
de Guix car ça facilitera la contribution au projet.

Mais d'abord, voyons les autres possibilités.

@node Fichier local
@subsubsection Fichier local

C'est ce que nous venons de faire avec @samp{my-hello}. Avec les bases de
Scheme que nous vous avons présentées, nous pouvons maintenant éclairer le
sens du début du fichier. Comme le dit @code{guix package --help} :

@example
  -f, --install-from-file=FICHIER
                         installer le paquet évalué par le code dans
                         FICHIER
@end example

Ainsi, la dernière expression @emph{doit} renvoyer un paquet, ce qui est le
cas dans notre exemple précédent.

L'expression @code{use-modules} indique quels modules sont nécessaires dans
le fichier. Les modules sont des collections de valeurs et de
procédures. Ils sont souvent appelés « bibliothèques » ou « paquets » dans
d'autres langages de programmation.

@node @samp{GUIX_PACKAGE_PATH}
@subsubsection @samp{GUIX_PACKAGE_PATH}

@emph{Remarque : à partir de Guix 0.16, les @dfn{canaux} plus flexibles sont
préférables et remplacent @samp{GUIX_PACKAGE_PATH}. Voir la section
suivante.}

Il peut être fastidieux de spécifier le fichier depuis la ligne de commande
par rapport à un appel à @code{guix package --install my-hello} comme on le
ferait pour les paquets officiels.

Guix permet d'uniformiser le processus en ajoutant autant de « répertoires
de déclaration de paquets » que vous le souhaitez.

Créez un répertoire, disons @file{~/guix-packages} et ajoutez-le à la
variable d'environnement @samp{GUIX_PACKAGE_PATH} :

@example
$ mkdir ~/guix-packages
$ export GUIX_PACKAGE_PATH=~/guix-packages
@end example

Pour ajouter plusieurs répertoires, séparez-les avec un deux-points
(@code{:}).

Notre @samp{my-hello} précédent doit être légèrement ajusté :

@lisp
(define-module (my-hello)
  #:use-module (guix licenses)
  #:use-module (guix packages)
  #:use-module (guix build-system gnu)
  #:use-module (guix download))

(define-public my-hello
  (package
    (name "my-hello")
    (version "2.10")
    (source (origin
              (method url-fetch)
              (uri (string-append "mirror://gnu/hello/hello-" version
                                  ".tar.gz"))
              (sha256
               (base32
                "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i"))))
    (build-system gnu-build-system)
    (synopsis "Hello, Guix world: An example custom Guix package")
    (description
     "GNU Hello prints the message \"Hello, world!\" and then exits.  It
serves as an example of standard GNU coding practices.  As such, it supports
command-line arguments, multiple languages, and so on.")
    (home-page "https://www.gnu.org/software/hello/")
    (license gpl3+)))
@end lisp

Remarquez que nous avons assigné la valeur du paquet à un nom de variable
exportée avec @code{define-public}. Cela assigne en fait le paquet à la
variable @code{my-hello} pour qu'elle puisse être utilisée, par exemple en
dépendance d'un autre paquet.

Si vous utilisez @code{guix package --install-from-file=my-hello.scm} avec
le fichier précédent, la commande échouera car la dernière expression,
@code{define-public}, ne renvoie pas un paquet. Si vous voulez utiliser
@code{define-public} dans ce cas tout de même, assurez-vous que le fichier
termine par une évaluation de @code{my-hello} :

@lisp
; ...
(define-public my-hello
  ; ...
  )

my-hello
@end lisp

Ce dernier exemple n'est pas très typique.

Maintenant @samp{my-hello} devrait faire partie de la collection de paquets
comme tous les paquets officiels. Vous pouvez le vérifier avec :

@example
$ guix package --show=my-hello
@end example

@node Canaux Guix
@subsubsection Canaux Guix

Guix 0.16 a introduit la notion de canaux, qui sont similaires à
@samp{GUIX_PACKAGE_PATH} mais fournit une meilleure intégration et un
meilleur suivi de la provenance. Les canaux ne sont pas nécessairement
locaux et ils peuvent être maintenus dans un dépôt Git public par
exemple. Bien sûr, vous pouvez utiliser plusieurs canaux en même temps.

@xref{Canaux,,, guix.fr, le manuel de référence de GNU Guix} pour des
détails sur la mise en place des canaux.

@node Bidouillage direct dans le dépôt git
@subsubsection Bidouillage direct dans le dépôt git

Nous vous recommandons de travailler directement sur le projet Guix : cela
réduit le travail nécessaire quand vous voudrez soumettre vos changements en
amont pour que la communauté puisse bénéficier de votre dur labeur !

Contrairement à la plupart des distributions logiciels, le dépôt Guix
contient à la fois les outils (dont le gestionnaire de paquets) et les
définitions des paquets. Nous avons fait ce choix pour permettre aux
développeurs et développeuses de profiter de plus de flexibilité pour
changer l'API sans rien casser, en mettant à jour tous les paquets en même
temps. Cela réduit l'inertie dans le développement.

Clonez le dépôt @uref{https://git-scm.com/, Git} officiel :

@example
$ git clone https://git.savannah.gnu.org/git/guix.git
@end example

Dans le reste de cet article, nous utiliserons @samp{$GUIX_CHECKOUT} pour
faire référence à l'emplacement de ce clone.


Suivez les instructions du manuel (@pxref{Contribuer,,, guix.fr, le manuel
de référence de GNU Guix}) pour mettre en place l'environnement du dépôt.

Une fois prêts, vous devriez pouvoir utiliser les définitions des paquets de
l'environnement du dépôt.

N'ayez pas peur de modifier les définitions des paquets que vous trouverez
dans @samp{$GUIX_CHECKOUT/gnu/packages}.

Le script @samp{$GUIX_CHECKOUT/pre-inst-env} vous permet d'utiliser
@samp{guix} sur la collection de paquets du dépôt (@pxref{Lancer Guix avant qu’il ne soit installé,,, guix.fr, le manuel de référence de GNU Guix}).

@itemize
@item
Recherchez des paquets, comme Ruby :

@example
  $ cd $GUIX_CHECKOUT
  $ ./pre-inst-env guix package --list-available=ruby
      ruby    1.8.7-p374      out     gnu/packages/ruby.scm:119:2
      ruby    2.1.6   out     gnu/packages/ruby.scm:91:2
      ruby    2.2.2   out     gnu/packages/ruby.scm:39:2
@end example

@item
Construisez un paquet, ici Ruby version 2.1 :

@example
  $ ./pre-inst-env guix build --keep-failed ruby@@2.1
  /gnu/store/c13v73jxmj2nir2xjqaz5259zywsa9zi-ruby-2.1.6
@end example

@item
Installez-le dans votre profil utilisateur :

@example
  $ ./pre-inst-env guix package --install ruby@@2.1
@end example

@item
Vérifiez que vous n'avez pas fait l'une des erreurs courantes :

@example
  $ ./pre-inst-env guix lint ruby@@2.1
@end example
@end itemize

Guix essaye de maintenir un bon standard d'empaquetage ; quand vous
contribuez au projet Guix, rappelez-vous de

@itemize
@item
suivre le style de code (@pxref{Style de code,,, guix.fr, le manuel de
référence de GNU Guix}),
@item
et de vérifier la check-list du manuel (@pxref{Envoyer des correctifs,,,
guix.fr, le manuel de référence de GNU Guix}).
@end itemize

Une fois que vous êtes satisfait du résultat, vous pouvez envoyer votre
contribution pour qu'elle rentre dans Guix. Ce processus est aussi détaillé
dans le manuel (@pxref{Contribuer,,, guix.fr, le manuel de référence de GNU
Guix})


Guix est un projet communautaire, donc plus on est de fous, plus on rit !

@node Exemple avancé
@subsection Exemple avancé

L'exemple « Hello World » précédent est le plus simple possible. Les paquets
peuvent devenir plus complexes que cela et Guix peut gérer des scénarios
plus avancés. Voyons un autre paquet plus sophistiqué (légèrement modifié à
partir des sources) :

@lisp
(define-module (gnu packages version-control)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix utils)
  #:use-module (guix packages)
  #:use-module (guix git-download)
  #:use-module (guix build-system cmake)
  #:use-module (gnu packages ssh)
  #:use-module (gnu packages web)
  #:use-module (gnu packages pkg-config)
  #:use-module (gnu packages python)
  #:use-module (gnu packages compression)
  #:use-module (gnu packages tls))

(define-public my-libgit2
  (let ((commit "e98d0a37c93574d2c6107bf7f31140b548c6a7bf")
        (revision "1"))
    (package
      (name "my-libgit2")
      (version (git-version "0.26.6" revision commit))
      (source (origin
                (method git-fetch)
                (uri (git-reference
                      (url "https://github.com/libgit2/libgit2/")
                      (commit commit)))
                (file-name (git-file-name name version))
                (sha256
                 (base32
                  "17pjvprmdrx4h6bb1hhc98w9qi6ki7yl57f090n9kbhswxqfs7s3"))
                (patches (search-patches "libgit2-mtime-0.patch"))
                (modules '((guix build utils)))
                ;; Suppression des logiciels embarqués.
                (snippet '(delete-file-recursively "deps"))))
      (build-system cmake-build-system)
      (outputs '("out" "debug"))
      (arguments
       `(#:tests? #true                         ; Lancer la suite de tests (c'est la valeur par défaut)
         #:configure-flags '("-DUSE_SHA1DC=ON") ; détection de collision SHA-1
         #:phases
         (modify-phases %standard-phases
           (add-after 'unpack 'fix-hardcoded-paths
             (lambda _
               (substitute* "tests/repo/init.c"
                 (("#!/bin/sh") (string-append "#!" (which "sh"))))
               (substitute* "tests/clar/fs.h"
                 (("/bin/cp") (which "cp"))
                 (("/bin/rm") (which "rm")))))
           ;; Lancer les tests avec plus de verbosité.
           (replace 'check
             (lambda _ (invoke "./libgit2_clar" "-v" "-Q")))
           (add-after 'unpack 'make-files-writable-for-tests
             (lambda _ (for-each make-file-writable (find-files "." ".*")))))))
      (inputs
       (list libssh2 http-parser python-wrapper))
      (native-inputs
       (list pkg-config))
      (propagated-inputs
       ;; Ces deux bibliothèques sont dans « Requires.private », dans libgit2.pc.
       (list openssl zlib))
      (home-page "https://libgit2.github.com/")
      (synopsis "Library providing Git core methods")
      (description
       "Libgit2 is a portable, pure C implementation of the Git core methods
provided as a re-entrant linkable library with a solid API, allowing you to
write native speed custom Git applications in any language with bindings.")
      ;; GPLv2 with linking exception
      (license license:gpl2))))
@end lisp

(Dans les cas où vous voulez seulement changer quelques champs d'une
définition de paquets, vous devriez utiliser l'héritage au lieu de tout
copier-coller. Voir plus bas.)

Parlons maintenant de ces champs en détail.

@subsubsection La méthode @code{git-fetch}

Contrairement à la méthode @code{url-fetch}, @code{git-fetch} a besoin d'un
@code{git-reference} qui prend un dépôt Git et un commit. Le commit peut
être n'importe quelle référence Git comme des tags, donc si la
@code{version} a un tag associé, vous pouvez l'utiliser directement. Parfois
le tag est précédé de @code{v}, auquel cas vous pouvez utiliser
@code{(commit (string-append "v" version))}.

Pour vous assurer que le code source du dépôt Git est stocké dans un
répertoire avec un nom descriptif, utilisez @code{(file-name (git-file-name
name version))}.

Vous pouvez utiliser la procédure @code{git-version} pour calculer la
version quand vous empaquetez des programmes pour un commit spécifique, en
suivant le guide de contribution (@pxref{Numéros de version,,, guix.fr, le
manuel de référence de GNU Guix}).

Comment obtenir le hash @code{sha256}, vous demandez-vous ? En invoquant
@command{guix hash} sur un clone du commit voulu, de cette manière :

@example
git clone https://github.com/libgit2/libgit2/
cd libgit2
git checkout v0.26.6
guix hash -rx .
@end example

@command{guix hash -rx} calcul un SHA256 sur le répertoire entier, en
excluant le sous-répertoire @file{.git} (@pxref{Invoquer guix hash,,,
guix.fr, le manuel de référence de GNU Guix}).

Dans le futur, @command{guix download} sera sans doute capable de faire cela
pour vous, comme il le fait pour les téléchargements directs.

@subsubsection Les bouts de code

Les bouts de code (snippet) sont des fragments quotés (c.-à-d. non évalués)
de code Scheme utilisés pour modifier les sources. C'est une alternative aux
fichiers @file{.patch} traditionnels, plus proche de l'esprit de Guix. À
cause de la quote, le code n'est évalué que lorsqu'il est passé au démon
Guix pour la construction. Il peut y avoir autant de bout de code que
nécessaire.

Les bouts de code on parfois besoin de modules Guile supplémentaires qui
peuvent être importés dans le champ @code{modules}.

@subsubsection Entrées

Il y a trois types d'entrées. En résumé :

@table @asis
@item native-inputs
Requis pour construire mais pas à l'exécution -- installer un paquet avec un
substitut n'installera pas ces entrées.
@item inputs
Installées dans le dépôt mais pas dans le profil, et présentes à la
construction.
@item propagated-inputs
Installées dans le dépôt et dans le profil, et présentes à la construction.
@end table

@xref{Référence de package,,, guix.fr, le manuel de référence de GNU Guix}
pour plus de détails.

La différence entre les différents types d'entrées est importante : si une
dépendance peut être utilisée comme @emph{entrée} plutôt que comme
@emph{entrée propagée}, il faut faire ça, sinon elle « polluera » le profil
utilisateur sans raison.

Par exemple, si vous installez un programme graphique qui dépend d'un outil
en ligne de commande, vous êtes probablement intéressé uniquement par la
partie graphique, donc inutile de forcer l'outil en ligne de commande à être
présent dans le profil utilisateur. Les dépendances sont gérés par les
paquets, pas par les utilisateurs et utilisatrices. Les @emph{entrées}
permettent de gérer les dépendances sans ennuyer les utilisateurs et
utilisatrices en ajoutant des fichiers exécutables (ou bibliothèque)
inutiles dans leur profil.

Pareil pour @emph{native-inputs} : une fois le programme installé, les
dépendances à la construction peuvent être supprimées sans problème par le
ramasse-miettes. Lorsqu'un substitut est disponible, seuls les
@emph{entrées} et les @emph{entrées propagées} sont récupérées : les
@emph{entrées natives} ne sont pas requises pour installer un paquet à
partir d'un substitut.

@quotation Remarque
Vous trouverez ici et là des extraits où les entrées des paquets sont
écrites assez différemment, comme ceci :

@lisp
;; « L'ancien style » pour les entrées.
(inputs
 `(("libssh2" ,libssh2)
   ("http-parser" ,http-parser)
   ("python" ,python-wrapper)))
@end lisp

C'est « l'ancien style », où chaque entrée est une liste que donne une
étiquette explicite (une chaine). C'est une méthode prise en charge mais
nous vous recommandons plutôt d'utiliser le style présenté plus
haut. @xref{Référence de package,,, guix.fr, le manuel de référence de GNU
Guix}, pour plus d'informations.
@end quotation

@subsubsection Sorties

De la même manière qu'un paquet peut avoir plusieurs entrées, il peut aussi
avoir plusieurs sorties.

Chaque sortie correspond à un répertoire différent dans le dépôt.

Vous pouvez choisir quelle sortie installer ; c'est utile pour préserver
l'espace disque et éviter de polluer le profil utilisateur avec des
exécutables et des bibliothèques inutiles.

La séparation des sorties est facultative. Lorsque le champ @code{outputs}
n'est pas spécifié, l'unique sortie par défaut (le paquet complet donc) est
@code{"out"}.

Les sorties séparées sont en général @code{debug} et @code{doc}.

Vous devriez séparer les sorties seulement si vous pouvez montrer que c'est
utile : si la taille de la sortie est importante (vous pouvez comparer avec
@code{guix size}) ou si le paquet est modulaire.

@subsubsection Arguments du système de construction

Le champ @code{arguments} est une liste de mot-clés et de valeurs utilisés
pour configurer le processus de construction.

L'argument le plus simple est @code{#:tests?} et on l'utilise pour
désactiver la suite de tests pendant la construction du paquet. C'est
surtout utile si le paquet n'a pas de suite de tests. Nous vous recommandons
fortement de laisser tourner la suite de tests s'il y en a une.

Un autre argument courant est @code{#:make-flags}, qui spécifie une liste de
drapeaux à ajouter en lançant make, comme ce que vous feriez sur la ligne de
commande. Par exemple, les drapeaux suivants

@lisp
#:make-flags (list (string-append "prefix=" (assoc-ref %outputs "out"))
                   "CC=gcc")
@end lisp

se traduisent en

@example
$ make CC=gcc prefix=/gnu/store/...-<out>
@end example

Cela indique que le compilateur C sera @code{gcc} et la variable
@code{prefix} (le répertoire d'installation pour Make) sera @code{(assoc-ref
%outputs "out")}, qui est une variable globale côté construction qui pointe
vers le répertoire de destination dans le dépôt (quelque chose comme
@file{/gnu/store/…-my-libgit2-20180408}).

De manière identique, vous pouvez indiquer les drapeaux de configuration :

@lisp
#:configure-flags '("-DUSE_SHA1DC=ON")
@end lisp

La variable @code{%build-inputs} est aussi générée dans cette portée. C'est
une liste d'association qui fait correspondre les noms des entrées à leur
répertoire dans le dépôt.

Le mot-clé @code{phases} liste la séquence d'étapes du système de
construction. Les phases usuelles sont @code{unpack}, @code{configure},
@code{build}, @code{install} et @code{check}. Pour en savoir plus, vous
devez trouver la bonne définition du système de construction dans
@samp{$GUIX_CHECKOUT/guix/build/gnu-build-system.scm} :

@lisp
(define %standard-phases
  ;; Standard build phases, as a list of symbol/procedure pairs.
  (let-syntax ((phases (syntax-rules ()
                         ((_ p ...) `((p . ,p) ...)))))
    (phases set-SOURCE-DATE-EPOCH set-paths install-locale unpack
            bootstrap
            patch-usr-bin-file
            patch-source-shebangs configure patch-generated-file-shebangs
            build check install
            patch-shebangs strip
            validate-runpath
            validate-documentation-location
            delete-info-dir-file
            patch-dot-desktop-files
            install-license-files
            reset-gzip-timestamps
            compress-documentation)))
@end lisp

Ou depuis la REPL :

@lisp
(add-to-load-path "/path/to/guix/checkout")
,use (guix build gnu-build-system)
(map first %standard-phases)
@result{} (set-SOURCE-DATE-EPOCH set-paths install-locale unpack bootstrap patch-usr-bin-file patch-source-shebangs configure patch-generated-file-shebangs build check install patch-shebangs strip validate-runpath validate-documentation-location delete-info-dir-file patch-dot-desktop-files install-license-files reset-gzip-timestamps compress-documentation)
@end lisp

Si vous voulez en apprendre plus sur ce qui arrive pendant ces phases,
consultez les procédures associées.

Par exemple, au moment d'écrire ces lignes, la définition de @code{unpack}
dans le système de construction de GNU est :

@lisp
(define* (unpack #:key source #:allow-other-keys)
  "Unpack SOURCE in the working directory, and change directory within the
source.  When SOURCE is a directory, copy it in a sub-directory of the current
working directory."
  (if (file-is-directory? source)
      (begin
        (mkdir "source")
        (chdir "source")

        ;; Preserve timestamps (set to the Epoch) on the copied tree so that
        ;; things work deterministically.
        (copy-recursively source "."
                          #:keep-mtime? #true))
      (begin
        (if (string-suffix? ".zip" source)
            (invoke "unzip" source)
            (invoke "tar" "xvf" source))
        (chdir (first-subdirectory "."))))
  #true)
@end lisp

Remarquez l'appel à @code{chdir} : il change de répertoire courant vers la
source qui vient d'être décompressée. Ainsi toutes les phases suivantes
utiliseront le répertoire des sources comme répertoire de travail, ce qui
explique qu'on peut travailler directement sur les fichiers sources. Du
moins, tant qu'une phase suivante ne change pas le répertoire de travail.

Nous modifions la liste des @code{%standard-phases} du système de
construction avec la macro @code{modify-phases} qui indique la liste des
modifications, sous cette formes :

@itemize
@item
@code{(add-before @var{phase} @var{nouvelle-phase} @var{procédure})} : Lance
une @var{procédure} nommée @var{nouvelle-phase} avant @var{phase}.
@item
@code{(add-after @var{phase} @var{nouvelle-phase} @var{procédure})} :
Pareil, mais après la @var{phase}.
@item
@code{(replace @var{phase} @var{procédure})}.
@item
@code{(delete @var{phase})}.
@end itemize

La @var{procédure} prend en charge les arguments @code{inputs} et
@code{outputs} sous forme de mot-clés. Les entrées (@emph{natives},
@emph{propagées} et simples) et répertoires de sortie sont référencés par
leur nom dans ces variables. Ainsi @code{(assoc-ref outputs "out")} est le
répertoire du dépôt de la sortie principale du paquet. Une procédure de
phase ressemble à cela :

@lisp
(lambda* (#:key inputs outputs #:allow-other-keys)
  (let ((bash-directory (assoc-ref inputs "bash"))
        (output-directory (assoc-ref outputs "out"))
        (doc-directory (assoc-ref outputs "doc")))
    ;; ...
    #true))
@end lisp

La procédure doit renvoyer @code{#true} si elle réussit. S'appuyer sur la
valeur de retour de la dernière expression n'est pas très solide parce qu'il
n'y a pas de garantie qu'elle sera @code{#true}. Donc le @code{#true} à la
fin permet de s'assurer que la bonne valeur est renvoyée si la phase
réussit.

@subsubsection Échelonnage du code

Si vous avez été attentif, vous aurez remarqué la quasi-quote et la virgule
dans le champ argument. En effet, le code de construction dans la
déclaration du paquet ne doit pas être évalué côté client, mais seulement
après avoir été passé au démon Guix. Ce mécanisme de passage de code entre
deux processus s'appelle @uref{https://arxiv.org/abs/1709.00833,
l'échelonnage de code}.

@subsubsection Fonctions utilitaires

Lorsque vous modifiez les @code{phases}, vous aurez souvent besoin d'écrire
du code qui ressemble aux invocation équivalentes (@code{make},
@code{mkdir}, @code{cp}, etc) couramment utilisées durant une installatio
plus standard dans le monde Unix.

Certaines comme @code{chmod} sont natives dans Guile. @xref{,,, guile, Guile
reference manual} pour une liste complète.

Guix fournit des fonctions utilitaires supplémentaires qui sont
particulièrement utiles pour la gestion des paquets.

Certaines de ces fonctions se trouvent dans
@samp{$GUIX_CHECKOUT/guix/guix/build/utils.scm}. La plupart copient le
comportement des commandes systèmes Unix traditionnelles :

@table @code
@item which
Fonctionne comme la commande système @samp{which}.
@item find-files
Fonctionne un peu comme la commande @samp{find}.
@item mkdir-p
Fonctionne comme @samp{mkdir -p}, qui crée tous les parents si besoin.
@item install-file
Fonctionne comme @samp{install} pour installer un fichier vers un répertoire
(éventuellement non existant). Guile a @code{copy-file} qui fonctionne comme
@samp{cp}.
@item copy-recursively
Fonctionne comme @samp{cp -r}.
@item delete-file-recursively
Fonctionne comme @samp{rm -rf}.
@item invoke
Lance un exécutable. Vous devriez utiliser cela à la place de
@code{system*}.
@item with-directory-excursion
Lance le corps dans un répertoire de travail différent, puis revient au
répertoire de travail précédent.
@item substitute*
Une fonction similaire à @command{sed}.
@end table

@xref{Utilitaires de construction,,, guix.fr, le manuel de référence de GNU
Guix}, pour plus d'informations sur ces utilitaires.

@subsubsection Préfixe de module

La licence dans notre dernier exemple a besoin d'un préfixe à cause de la
manière dont le module @code{licenses} a été importé dans le paquet, avec
@code{#:use-module ((guix licenses) #:prefix license:)}. Le mécanisme
d'import de module de Guile (@pxref{Using Guile Modules,,, guile, Guile
reference manual}) permet de contrôler complètement l'espace de nom. Cela
évite les conflits entre, disons, la variable @samp{zlib} de
@samp{licenses.scm} (un @emph{licence}) et la variable @samp{zlib} de
@samp{compression.scm} (un @emph{paquet}).

@node Autres systèmes de construction
@subsection Autres systèmes de construction

Ce que nous avons vu jusqu'ici couvre la majeur partie des paquets qui
utilisent un système de construction autre que
@code{trivial-build-system}. Ce dernier n'automatise rien et vous laisse
tout construire par vous-même. C'est plus exigeant et nous n'en parlerons
pas pour l'instant, mais heureusement il est rarement nécessaire d'aller
jusqu'à ces extrémités.

Pour les autres systèmes de construction, comme ASDF, Emacs, Perl, Ruby et
bien d'autres, le processus est très similaire à celui du système de
construction de GNU en dehors de quelques arguments spécialisés.

@xref{Systèmes de construction,,, guix.fr, le manuel de référence de GNU
Guix}, pour plus d'informations sur les systèmes de construction, ou voir le
code source dans les répertoires @samp{$GUIX_CHECKOUT/guix/build} et
@samp{$GUIX_CHECKOUT/guix/build-system}.

@node Définition programmable et automatisée
@subsection Définition programmable et automatisée

Nous ne le répéterons jamais assez : avoir un langage de programmation
complet à disposition nous permet de faire bien plus de choses que la
gestion de paquets traditionnelle.

Illustrons cela avec certaines fonctionnalités géniales de Guix !

@node Les importateurs récursifs
@subsubsection Les importateurs récursifs

Certains systèmes de constructions sont si bons qu'il n'y a presque rien à
écrire pour créer un paquet, au point que cela devient rapidement répétitif
et pénible. L'une des raisons d'être des ordinateurs est de remplacer les
êtres humains pour ces taches barbantes. Disons donc à Guix de faire cela
pour nous et de créer les définitions de paquets pour un paquet R venant de
CRAN (la sortie est coupée par souci de place) :

@example
$ guix import cran --recursive walrus

(define-public r-mc2d
    ; ...
    (license gpl2+)))

(define-public r-jmvcore
    ; ...
    (license gpl2+)))

(define-public r-wrs2
    ; ...
    (license gpl3)))

(define-public r-walrus
  (package
    (name "r-walrus")
    (version "1.0.3")
    (source
      (origin
        (method url-fetch)
        (uri (cran-uri "walrus" version))
        (sha256
          (base32
            "1nk2glcvy4hyksl5ipq2mz8jy4fss90hx6cq98m3w96kzjni6jjj"))))
    (build-system r-build-system)
    (propagated-inputs
      (list r-ggplot2 r-jmvcore r-r6 r-wrs2))
    (home-page "https://github.com/jamovi/walrus")
    (synopsis "Robust Statistical Methods")
    (description
      "This package provides a toolbox of common robust statistical
tests, including robust descriptives, robust t-tests, and robust ANOVA.
It is also available as a module for 'jamovi' (see
<https://www.jamovi.org> for more information).  Walrus is based on the
WRS2 package by Patrick Mair, which is in turn based on the scripts and
work of Rand Wilcox.  These analyses are described in depth in the book
'Introduction to Robust Estimation & Hypothesis Testing'.")
    (license gpl3)))
@end example

L'importateur récursif n'importera pas les paquets pour lesquels Guix a déjà
une définition, sauf pour le tout premier.

Toutes les applications ne peuvent pas être empaquetées de cette manière,
seules celles qui s'appuient sur un nombre restreint de systèmes pris en
charge le peuvent. Vous trouverez la liste complète des importateurs dans la
section dédiée du manuel (@pxref{Invoquer guix import,,, guix.fr, le manuel
de référence de GNU}).

@node Mise à jour automatique
@subsubsection Mise à jour automatique

Guix peut être assez intelligent pour vérifier s'il y a des mises à jour sur
les systèmes qu'il connaît. Il peut rapporter les paquets anciens avec

@example
$ guix refresh hello
@end example

La plupart du temps, mettre à jour un paquet vers une nouvelle version ne
demande pas beaucoup plus que de changer le numéro de version et la somme de
contrôle. Guix peut aussi le faire automatiquement :

@example
$ guix refresh hello --update
@end example

@node Héritage
@subsubsection Héritage

Si vous avez commencé à regarder des définitions de paquets existantes, vous
avez peut-être remarqué qu'un certain nombre d'entre elles ont un champ
@code{inherit} :

@lisp
(define-public adwaita-icon-theme
  (package (inherit gnome-icon-theme)
    (name "adwaita-icon-theme")
    (version "3.26.1")
    (source (origin
              (method url-fetch)
              (uri (string-append "mirror://gnome/sources/" name "/"
                                  (version-major+minor version) "/"
                                  name "-" version ".tar.xz"))
              (sha256
               (base32
                "17fpahgh5dyckgz7rwqvzgnhx53cx9kr2xw0szprc6bnqy977fi8"))))
    (native-inputs (list `(,gtk+ "bin")))))
@end lisp

Tous les champs non spécifiés héritent du paquet parent. C'est très pratique
pour créer un paquet alternatif, par exemple avec une source, une version ou
des options de compilation différentes.

@node Se faire aider
@subsection Se faire aider

Malheureusement, certaines applications peuvent être difficiles à
empaqueter. Parfois elles ont besoin d'un correctif pour fonctionner avec la
hiérarchie du système de fichiers non standard imposée par de dépôt. Parfois
les tests ne se lancent pas correctement (vous pouvez les passer mais ce
n'est pas recommandé). Parfois le paquet n'est pas reproductible.

Si vous êtes bloqué·e, incapable de trouver comme corriger un problème
d'empaquetage, n'hésitez pas à demander de l'aide à la communauté.

voir la @uref{https://guix.gnu.org/fr/contact/,la page d'accueil de Guix}
pour plus d'informations sur les listes de diffusion, IRC, etc.

@node Conclusion
@subsection Conclusion

Ce didacticiel vous a montré la gestion des paquets sophistiquée dont Guix
se targue. Maintenant, nous avons restreint cette introduction au système
@code{gnu-build-system} qui est un niveau d'abstraction essentiel sur lequel
des niveaux d'abstraction plus avancés se reposent.

Comment continuer ? Nous devrions ensuite disséquer le fonctionnement
interne des systèmes de construction en supprimant toutes les abstractions,
avec le @code{trivial-build-system} : cela vous permettra de bien comprendre
le processus avant de voir des techniques plus avancées et certains cas
particuliers.

D'autres fonctionnalités que vous devriez explorer sont l'édition
interactive et les possibilités de débogage de Guix fournies par la REPL de
Guile.

Ces fonctionnalités avancées sont complètement facultatives et peuvent
attendre ; maintenant vous devriez prendre une pause bien méritée. Avec ce
dont nous venons de parler ici vous devriez être bien armé·e pour empaqueter
de nombreux paquets. Vous pouvez commencer dès maintenant et on espère voir
votre contribution bientôt !

@node Références
@subsection Références

@itemize
@item
La
@uref{https://guix.gnu.org/manual/devel/fr/html_node/reference-de-package.html,
référence des paquets dans le manuel}

@item
@uref{https://gitlab.com/pjotrp/guix-notes/blob/master/HACKING.org, le guide
de bidouillage de GNU Guix de Pjotr}

@item
@uref{https://www.gnu.org/software/guix/guix-ghm-andreas-20130823.pdf, « GNU
Guix: Package without a scheme! »}, d'Andreas Enge
@end itemize

@c *********************************************************************
@node Configuration du système
@chapter Configuration du système

Guix propose un langage flexible pour déclarer la configuration de votre
système Guix. Cette flexibilité peut parfois paraître écrasante. Le but de
ce chapitre est de vous montrer quelques concepts de configuration avancés.

@pxref{Configuration du système,,, guix.fr, le manuel de référence de GNU
Guix} pour une référence complète.

@menu
* Connexion automatique à un TTY donné::  Connecter automatiquement un 
                                              utilisateur sur un TTY donné
* Personnalisation du noyau::  Créer et utiliser un noyau Linux 
                                 personnalisé sur le système Guix.
* L'API de création d'images du système Guix::  Personnaliser des images 
                                                    pour des plateformes 
                                                    particulières.
* Utiliser des clés de sécurité::  Comment utiliser des clés de 
                                        sécurité avec le système Guix.
* Se connecter à un VPN Wireguard::  Se connecter à un VPN Wireguard.
* Personnaliser un gestionnaire de fenêtres::  Gérer la personnalisation 
                                                  d'un gestionnaire de 
                                                  fenêtres sur le système 
                                                  Guix.
* Lancer Guix sur un serveur Linode::  Lancer Guix sur un serveur Linode
* Mettre en place un montage dupliqué::  Mettre en place un montage 
                                            dupliqué dans une définition de 
                                            système de fichiers.
* Récupérer des substituts via Tor::  Configurer le démon Guix pour 
                                          récupérer les substituts via Tor.
* Configurer NGINX avec Lua::  Configurer le serveur web NGINX pour qu'il 
                                 charge des modules Lua.
* Serveur de musique avec l'audio bluetooth::  Lecteur de musique sans 
                                                 affichage avec entrée 
                                                 bluetooth.
@end menu

@node Connexion automatique à un TTY donné
@section Connexion automatique à un TTY donné

Tandis que le manuel de Guix explique comment connecter automatiquement un
utilisateur sur @emph{tous} les TTY (@pxref{connexion automatique à un TTY,,, guix.fr, le manuel de référence de Guix}), vous pourriez préférer
avoir un utilisateur connecté sur un TTY et configurer les autres TTY pour
connecter d'autres utilisateurs ou personne. Remarquez que vous pouvez
connecter automatiquement un utilisateur sur n'importe quel TTY, mais il est
recommandé d'éviter @code{tty1}, car par défaut, il est utilisé pour
afficher les avertissements et les erreurs des journaux systèmes.

Voici comment on peut configurer la connexion d'un utilisateur sur un tty :

@lisp
(define (auto-login-to-tty config tty user)
  (if (string=? tty (mingetty-configuration-tty config))
        (mingetty-configuration
         (inherit config)
         (auto-login user))
        config))

(define %my-services
  (modify-services %base-services
    ;; @dots{}
    (mingetty-service-type config =>
                           (auto-login-to-tty
                            config "tty3" "alice"))))

(operating-system
  ;; @dots{}
  (services %my-services))
@end lisp

On peut aussi utiliser @code{compose} (@pxref{Higher-Order Functions,,,
guile, The Guile Reference Manual}) avec @code{auto-login-to-tty} pour
connecter plusieurs utilisateurs sur différents ttys.

Enfin, une mise en garde. Configurer la connexion automatique à un TTY
signifie que n'importe qui peut allumer votre ordinateur et lancer des
commandes avec votre utilisateur normal. Cependant, si vous avez une
partition racine chiffrée, et donc qu'il faut déjà saisir une phrase de
passe au démarrage du système, la connexion automatique peut être un choix
pratique.


@node Personnalisation du noyau
@section Personnalisation du noyau

Guix est, en son cœur, une distribution source avec des substituts
(@pxref{Substituts,,, guix.fr, le manuel de référence de GNU Guix}), et donc
construire des paquets à partir de leur code source est normal pendant les
installations et les mis à jour de paquets. Malgré tout, c'est aussi normal
d'essayer de réduire le temps passé à compiler des paquets, et les
changements récents et futurs concernant la construction et la distribution
des substituts continue d'être un sujet de discussion dans le projet Guix.

Le noyau, bien qu'il ne demande pas énormément de RAM pour être construit,
prend assez long à construire sur une machine usuelle. La configuration du
noyau officielle, comme avec la plupart des autres distributions GNU/Linux,
penche du côté de l'inclusivité, et c'est vraiment ça qui rend la
construction aussi longue à partir des sources.

Le noyau Linux, cependant, peut aussi être décrit comme un simple paquet
comme les autres, et peut donc être personnalisé comme n'importe quel autre
paquet. La procédure est un peu différente, même si c'est surtout dû à la
nature de la définition du paquet.

Le paquet du noyau @code{linux-libre} est en fait une procédure qui crée un
paquet.

@lisp
(define* (make-linux-libre* version gnu-revision source supported-systems
                            #:key
                            (extra-version #f)
                            ;; Un fonction qui prend une architecture et une variante
                            ;; Voir kernel-config si vous voulez un exemple.
                            (configuration-file #f)
                            (defconfig "defconfig")
                            (extra-options %default-extra-linux-options))
  ...)
@end lisp

Le paquet @code{linux-libre} actuel pour la série 5.15.x, est déclaré comme
ceci :

@lisp
(define-public linux-libre-5.15
  (make-linux-libre* linux-libre-5.15-version
                     linux-libre-5.15-gnu-revision
                     linux-libre-5.15-source
                     '("x86_64-linux" "i686-linux" "armhf-linux" "aarch64-linux" "riscv64-linux")
                     #:configuration-file kernel-config))
@end lisp

Les clés qui n'ont pas de valeur associée prennent leur valeur par défaut
dans la définition de @code{make-linux-libre}. Lorsque vous comparez les
deux bouts de code ci-dessus, remarquez le commentaire qui correspond à
@code{#:configuration-file}. À cause de cela, il n'est pas facile d'inclure
une configuration personnalisée du noyau à partir de la définition, mais ne
vous inquiétez pas, il y a d'autres moyens de travailler avec ce qu'on a.

Il y a deux manières de créer un noyau avec une configuration
personnalisée. La première consiste à fournir un fichier @file{.config}
standard au processus de construction en ajoutant un fichier @file{.config}
comme entrée native de notre noyau. Voici un bout de code correspondant à la
phase @code{'configure} de la définition de paquet @code{make-linux-libre} :

@lisp
(let ((build  (assoc-ref %standard-phases 'build))
      (config (assoc-ref (or native-inputs inputs) "kconfig")))

  ;; Use a custom kernel configuration file or a default
  ;; configuration file.
  (if config
      (begin
        (copy-file config ".config")
        (chmod ".config" #o666))
      (invoke "make" ,defconfig)))
@end lisp

Et voici un exemple de paquet de noyau. Le paquet @code{linux-libre} n'a
rien de spécial, on peut en hériter et remplacer ses champs comme n'importe
quel autre paquet :

@lisp
(define-public linux-libre/E2140
  (package
    (inherit linux-libre)
    (native-inputs
     `(("kconfig" ,(local-file "E2140.config"))
      ,@@(alist-delete "kconfig"
                      (package-native-inputs linux-libre))))))
@end lisp

Dans le même répertoire que le fichier définissant @code{linux-libre-E2140}
se trouve un fichier nommé @file{E2140.config}, qui est un fichier de
configuration du noyau. Le mot-clé @code{defconfig} de
@code{make-linux-libre} reste vide ici, donc la configuration du noyau dans
le paquet est celle qui sera incluse dans le champ @code{native-inputs}.

La deuxième manière de créer un noyau personnalisé est de passer une
nouvelle valeur au mot-clé @code{extra-options} de la procédure
@code{make-linux-libre}. Le mot-clé @code{extra-options} fonctionne avec une
autre fonction définie juste en dessous :

@lisp
(define %default-extra-linux-options
  `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html
   ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #true)
   ;; Modules required for initrd:
   ("CONFIG_NET_9P" . m)
   ("CONFIG_NET_9P_VIRTIO" . m)
   ("CONFIG_VIRTIO_BLK" . m)
   ("CONFIG_VIRTIO_NET" . m)
   ("CONFIG_VIRTIO_PCI" . m)
   ("CONFIG_VIRTIO_BALLOON" . m)
   ("CONFIG_VIRTIO_MMIO" . m)
   ("CONFIG_FUSE_FS" . m)
   ("CONFIG_CIFS" . m)
   ("CONFIG_9P_FS" . m)))

(define (config->string options)
  (string-join (map (match-lambda
                      ((option . 'm)
                       (string-append option "=m"))
                      ((option . #true)
                       (string-append option "=y"))
                      ((option . #false)
                       (string-append option "=n")))
                    options)
               "\n"))
@end lisp

Et dans le script configure personnalisé du paquet « make-linux-libre » :

@lisp
;; Appending works even when the option wasn't in the
;; file.  The last one prevails if duplicated.
(let ((port (open-file ".config" "a"))
      (extra-configuration ,(config->string extra-options)))
  (display extra-configuration port)
  (close-port port))

(invoke "make" "oldconfig")
@end lisp

Donc, en ne fournissant pas de fichier de configuration le fichier
@file{.config} est au départ vide et on écrit ensuite l'ensemble des
drapeaux que l'on veut. Voici un autre noyau personnalisé :

@lisp
(define %macbook41-full-config
  (append %macbook41-config-options
          %file-systems
          %efi-support
          %emulation
          (@@@@ (gnu packages linux) %default-extra-linux-options)))

(define-public linux-libre-macbook41
  ;; XXX: Accède à la procédure interne « make-linux-libre* », qui est privée
  ;; et n'est pas exportée, et pourrait changer dans le futur.
  ((@@@@ (gnu packages linux) make-linux-libre*)
   (@@@@ (gnu packages linux) linux-libre-version)
   (@@@@ (gnu packages linux) linux-libre-gnu-revision)
   (@@@@ (gnu packages linux) linux-libre-source)
   '("x86_64-linux")
   #:extra-version "macbook41"
   #:extra-options %macbook41-config-options))
@end lisp

Dans l'exemple ci-dessus @code{%fale-systems} est un ensemble de drapeaux
qui activent la prise en charge de différents systèmes de fichiers,
@code{%efi-support} active la prise en charge de l'EFI et @code{%emulation}
permet à une machine x86_64-linux de fonctionner aussi en mode
32-bits. @code{%default-extra-linux-options} sont l'ensemble de ces options
et elles devaient être ajoutées puisqu'elles ont été remplacées dans le
mot-clé @code{extra-options}.

Tout ça est bien beau, mais comment savoir quels modules sont requis pour un
système en particulier ? Il y a deux ressources qui peuvent être utiles pour
répondre à cette question : le
@uref{https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Kernel,
manuel de Gentoo} et la
@uref{https://www.kernel.org/doc/html/latest/admin-guide/README.html?highlight=localmodconfig,
documentation du noyau}. D'après la documentation du noyau, il semble que la
commande @code{make localmodconfig} soit la bonne.

Pour lancer @code{make localmodconfig} on doit d'abord récupérer et
décompresser le code source du noyau :

@example shell
tar xf $(guix build linux-libre --source)
@end example

Une fois dans le répertoire contenant le code source lancez @code{touch
.config} pour créer un fichier @file{.config} initialement vide pour
commencer. @code{make localmodconfig} fonctionne en remarquant que avec déjà
un @file{.config} et en vous disant ce qu'il vous manque. Si le fichier est
vide, il vous manquera tout ce qui est nécessaire. L'étape suivante consiste
à lancer :

@example shell
guix shell -D linux-libre -- make localmodconfig
@end example

et regardez la sortie. Remarquez que le fichier @file{.config} est toujours
vide. La sortie contient en général deux types d'avertissements. Le premier
commence par « WARNING » et peut être ignoré dans notre cas. Le deuxième dit
:

@example shell
module pcspkr did not have configs CONFIG_INPUT_PCSPKR
@end example

Pour chacune de ces lignes, copiez la partie @code{CONFIG_XXXX_XXXX} dans le
@file{.config} du répertoire et ajoutez @code{=m} pour qu'à la fin il
ressemble à cela :

@example shell
CONFIG_INPUT_PCSPKR=m
CONFIG_VIRTIO=m
@end example

Après avoir copié toutes les options de configuration, lancez @code{make
localmodconfig} de nouveau pour vous assurer que vous n'avez pas de sortie
commençant par « module ». Après tous ces modules spécifiques à la machine,
il y en a encore quelques uns que nous devons aussi
définir. @code{CONFIG_MODULES} est nécessaire pour que nous puissions
construire et charger les modules séparément et ne pas tout construire dans
le noyau. @code{CONFIG_BLK_DEV_SD} est requis pour lire les disques durs. Il
est possible que vous aillez besoin de quelques autres modules.

Cet article n'a pas pour but de vous guider dans la configuration de votre
propre noyau cependant, donc si vous décidez de construire un noyau
personnalisé vous devrez chercher d'autres guides pour créer un noyau qui
vous convient.

La deuxième manière de configurer le noyau utilise un peu plus les
fonctionnalités de Guix et vous permettent de partager des bouts de
configuration entre différents noyaux. Par exemple, toutes les machines avec
un démarrage EFI ont besoin d'un certain nombre de configurations. Tous les
noyaux vont probablement partager une liste de systèmes de fichiers à
prendre en charge. En utilisant des variables il est facile de voir du
premier coup quelles fonctionnalités sont activées pour vous assurer que
vous n'avez pas des fonctionnalités dans un noyau qui manquent dans un
autre.

Cependant, nous ne parlons pas de la personnalisation du disque de ram
initial. Vous devrez sans doute modifier le disque de ram initial sur les
machines qui utilisent un noyau personnalisé, puisque certains modules
attendus peuvent ne pas être disponibles.

@node L'API de création d'images du système Guix
@section L'API de création d'images du système Guix

Historiquement, le système Guix est centré sur une structure
@code{operating-system}. Cette structure contient divers champs qui vont du
chargeur d'amorçage et à la déclaration du noyau aux services à installer.

En fonction de la machine cible, qui peut aller d'une machine @code{x86_64}
standard à un petit ordinateur ARM sur carte unique comme le Pine64, les
contraintes sur l'image varient beaucoup. Les fabricants imposent différents
formats d'image avec plusieurs tailles de partitions et de positions.

Pour créer des images convenables pour toutes ces machines, une nouvelle
abstraction est nécessaire : c'est le but de l'enregistrement
@code{image}. Cet enregistrement contient toutes les informations requises
pour être transformé en une image complète, qui peut être directement
démarrée sur une machine cible.

@lisp
(define-record-type* <image>
  image make-image
  image?
  (name               image-name ;symbol
                      (default #f))
  (format             image-format) ;symbol
  (target             image-target
                      (default #f))
  (size               image-size  ;size in bytes as integer
                      (default 'guess))
  (operating-system   image-operating-system  ;<operating-system>
                      (default #f))
  (partitions         image-partitions ;list of <partition>
                      (default '()))
  (compression?       image-compression? ;boolean
                      (default #t))
  (volatile-root?     image-volatile-root? ;boolean
                      (default #t))
  (substitutable?     image-substitutable? ;boolean
                      (default #t)))
@end lisp

Cet enregistrement contient le système d'exploitation à instancier. Le champ
@code{format} défini le type d'image et peut être @code{efi-raw},
@code{qcow2} ou @code{iso9660} par exemple. Plus tard, on prévoit de
l'étendre à @code{docker} et aux autres types d'images.

Un nouveau répertoire dans les sources de Guix est dédié aux définitions des
images. Pour l'instant il y a quatre fichiers :

@itemize @bullet
@item @file{gnu/system/images/hurd.scm}
@item @file{gnu/system/images/pine64.scm}
@item @file{gnu/system/images/novena.scm}
@item @file{gnu/system/images/pinebook-pro.scm}
@end itemize

Regardons le fichier @file{pine64.scm}. Il contient la variable
@code{pine64-barebones-os} qui est une définition minimale d'un système
d'exploitation dédié à la carte @b{Pine A64 LTS}.

@lisp
(define pine64-barebones-os
  (operating-system
   (host-name "vignemale")
   (timezone "Europe/Paris")
   (locale "en_US.utf8")
   (bootloader (bootloader-configuration
                (bootloader u-boot-pine64-lts-bootloader)
                (targets '("/dev/vda"))))
   (initrd-modules '())
   (kernel linux-libre-arm64-generic)
   (file-systems (cons (file-system
                        (device (file-system-label "my-root"))
                        (mount-point "/")
                        (type "ext4"))
                       %base-file-systems))
   (services (cons (service agetty-service-type
                            (agetty-configuration
                             (extra-options '("-L")) ; no carrier detect
                             (baud-rate "115200")
                             (term "vt100")
                             (tty "ttyS0")))
                   %base-services))))
@end lisp

Les champs @code{kernel} et @code{bootloader} pointent vers les paquets
dédiés à cette carte.

Ci-dessous, la variable @code{pine64-image-type} est ainsi définie.

@lisp
(define pine64-image-type
  (image-type
   (name 'pine64-raw)
   (constructor (cut image-with-os arm64-disk-image <>))))
@end lisp

Elle utilise un enregistrement dont nous n'avons pas encore parlé,
l'enregistrement @code{image-type}, défini de cette façon :

@lisp
(define-record-type* <image-type>
  image-type make-image-type
  image-type?
  (name           image-type-name) ;symbol
  (constructor    image-type-constructor)) ;<operating-system> -> <image>
@end lisp

Le but principal de cet enregistrement est d'associer un nom à une procédure
transformant un @code{operating-system} en une image. Pour comprendre
pourquoi c'est nécessaire, voyons la commande produisant une image à partir
d'un fichier de configuration de type @code{operating-system} :

@example
guix system image my-os.scm
@end example

Cette commande demande une configuration de type @code{operating-system}
mais comment indiquer que l'on veut cibler une carte Pine64 ? Nous devons
fournir l'information supplémentaire, @code{image-type}, en passant le
drapeau @code{--image-type} ou @code{-t}, de cette manière :

@example
guix system image --image-type=pine64-raw my-os.scm
@end example

Ce paramètre @code{image-type} pointe vers le @code{pine64-image-type}
défini plus haut. Ainsi, la déclaration @code{operating-system} dans
@code{my-os.scm} se verra appliquée la procédure @code{[cut image-with-os
arm64-disk-image <>)} pour la transformer en une image.

L'image qui en résulte ressemble à ceci :

@lisp
(image
 (format 'disk-image)
 (target "aarch64-linux-gnu")
 (operating-system my-os)
 (partitions
  (list (partition
         (inherit root-partition)
         (offset root-offset)))))
@end lisp

qui ajoute l'objet @code{operating-system} défini dans @code{my-os.scm} à
l'enregistrement @code{arm64-disk-image}.

Mais assez de cette folie. Qu'est-ce que cette API pour les images apporte
aux utilisateurs et utilisatrices ?

On peut lancer :

@example
mathieu@@cervin:~$ guix system --list-image-types
Les types d'image disponibles sont :

   - pinebook-pro-raw
   - pine64-raw
   - novena-raw
   - hurd-raw
   - hurd-qcow2
   - qcow2
   - uncompressed-iso9660
   - efi-raw
   - arm64-raw
   - arm32-raw
   - iso9660
@end example

et en écrivant un fichier de type @code{operating-system} basé sur
@code{pine64-barebones-os}, vous pouvez personnaliser votre image selon vos
préférences dasn un fichier (@file{my-pine-os.scm}) de cette manière :

@lisp
(use-modules (gnu services linux)
             (gnu system images pine64))

(let ((base-os pine64-barebones-os))
  (operating-system
    (inherit base-os)
    (timezone "America/Indiana/Indianapolis")
    (services
     (cons
      (service earlyoom-service-type
               (earlyoom-configuration
                (prefer-regexp "icecat|chromium")))
      (operating-system-user-services base-os)))))
@end lisp

lancez :

@example
guix system image --image-type=pine64-raw my-pine-os.scm
@end example

ou bien,

@example
guix system image --image-type=hurd-raw my-hurd-os.scm
@end example

pour récupérer une image que vous pouvez écrire sur un disque dur pour
démarrer dessus.

Sans rien changer à @code{my-hurd-os.scm}, en appelant :

@example
guix system image --image-type=hurd-qcow2 my-hurd-os.scm
@end example

vous aurez une image QEMU pour le Hurd à la place.

@node Utiliser des clés de sécurité
@section Utiliser des clés de sécurité
@cindex 2FA, authentification à double facteur
@cindex U2F, second facteur universel
@cindex clé de sécurité, configuration

L'utilisation de clés de sécurité peut améliorer votre sécurité en
fournissant une seconde source d'authentification qui ne peut pas être
facilement volée ni copiée, au moins pour les adversaires à distance
(quelque chose que vous possédez) de votre secret principal (une phrase de
passe — quelque chose que vous connaissez), ce qui réduit les risques de vol
d'identité.

L'exemple de configuration détaillée plus bas montre la configuration
minimale dont vous avez besoin sur votre système Guix pour permettre
l'utilisation d'une clé de sécurité Yubico. Nous espérons que la
configuration puisse être utile pour d'autres clés de sécurité aussi, avec
quelques ajustements.

@subsection Configuration pour l'utiliser comme authentification à double facteur (2FA)

Pour être utilisable, les règles udev du systèmes doivent être étendues avec
des règles spécifiques à la clé. Ce qui suit montre comment étendre vos
règles udev avec le fichier de règles @file{lib/udev/rules.d/70-u2f.rules}
fournit par le paquet @code{libfido2} du module @code{(gnu packages
security-token)} et ajouter votre utilisateur au groupe @samp{"plugdev"}
qu'il utilise :

@lisp
(use-package-modules ... security-token ...)
...
(operating-system
 ...
 (users (cons* (user-account
               (name "your-user")
               (group "users")
               (supplementary-groups
		'("wheel" "netdev" "audio" "video"
                  "plugdev"))           ;<- added system group
               (home-directory "/home/your-user"))
              %base-user-accounts))
 ...
 (services
  (cons*
   ...
   (udev-rules-service 'fido2 libfido2 #:groups '("plugdev")))))
@end lisp

Après la reconfiguration de votre système et vous être authentifié dans
votre session graphique pour que le nouveau groupe prenne effet pour votre
utilisateur, vous pouvez vérifier que la clé est utilisable en exécutant :

@example
guix shell ungoogled-chromium -- chromium chrome://settings/securityKeys
@end example

et en validant que la clé de sécurité peut être remise à zéro via le menu «
réinitialiser votre clé de sécurité ». Si cela fonctionne, bravo, votre clé
de sécurité est prête à être utilisée avec les applications qui prennent en
charge l'authentification à double facteur (2FA).

@node Se connecter à un VPN Wireguard
@section Se connecter à un VPN Wireguard

Pour se connecter à un serveur VPN Wireguard, il faut que le module du noyau
soit chargé en mémoire et qu'un paquet fournissant des outils de réseau le
prenne en charge (par exemple, @code{wireguard-tools} ou
@code{network-manager}).

Voici un exemple de configuration pour Linux-Libre < 5.6, où le module est
hors de l'arborescence des sources et doit être chargé manuellement--les
révisions suivantes du noyau l'ont intégré et n'ont donc pas besoin d'une
telle configuration :

@lisp
(use-modules (gnu))
(use-service-modules desktop)
(use-package-modules vpn)

(operating-system
  ;; …
  (services (cons (simple-service 'wireguard-module
                                  kernel-module-loader-service-type
                                  '("wireguard"))
                  %desktop-services))
  (packages (cons wireguard-tools %base-packages))
  (kernel-loadable-modules (list wireguard-linux-compat)))
@end lisp

Après avoir reconfiguré et redémarré votre système, vous pouvez utiliser les
outils Wireguard ou NetworkManager pour vous connecter à un serveur VPN.

@subsection Utilisation des outils Wireguard

Pour tester votre configuration Wireguard, vous pouvez utiliser
@command{wg-quick}. Donnez-lui simplement un fichier de configuration :
@command{wg-quick up ./wg0.conf}, ou placez ce fichier dans
@file{/etc/wireguard} et lancez @command{wg-quick up wg0} à la place.

@quotation Remarque
Soyez averti que l'auteur a décrit cette commande comme un : « [...] script
bash écrit à la va-vite [...] ».
@end quotation

@subsection En utilisant NetworkManager

Grâce à la prise en charge de NetworkManager pour Wireguard, nous pouvons
nous connecter à notre VPN en utilisant la commande @command{nmcli}.
Jusqu'ici, ce guide suppose que vous utilisez le service Network Manager
fourni par @code{%desktop-services}.  Dans le cas contraire, vous devez
ajuster votre liste de services pour charger
@code{network-manager-service-type} et reconfigurer votre système Guix.

Pour importer votre configuration VPN, exécutez la commande d'import de
nmcli :

@example shell
# nmcli connection import type wireguard file wg0.conf
Connection 'wg0' (edbee261-aa5a-42db-b032-6c7757c60fde) successfully added
@end example

Cela va créer un fichier de configuration dans
@file{/etc/NetworkManager/wg0.nmconnection}. Ensuite connectez-vous au
serveur Wireguard :

@example shell
$ nmcli connection up wg0
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/6)
@end example

Par défaut, NetworkManager se connectera automatiquement au démarrage du
système. Pour changer ce comportement vous devez modifier votre
configuration :

@example shell
# nmcli connection modify wg0 connection.autoconnect no
@end example

Pour des informations plus spécifiques sur NetworkManager et wireguard
@uref{https://blogs.gnome.org/thaller/2019/03/15/wireguard-in-networkmanager/,voir
ce billet par thaller}.

@node Personnaliser un gestionnaire de fenêtres
@section Personnaliser un gestionnaire de fenêtres
@cindex wm

@node StumpWM
@subsection StumpWM
@cindex stumpwm

Vous pouvez installer StumpWM sur un système Guix en ajoutant @code{stumwm}
et éventuellement @code{`(,stumpwm "lib")} dans les paquets du fichier de
système d'exploitation, p.@: ex.@: @file{/etc/config.scm}.

Voici un exemple de configuration :

@lisp
(use-modules (gnu))
(use-package-modules wm)

(operating-system
  ;; …
  (packages (append (list sbcl stumpwm `(,stumpwm "lib"))
                    %base-packages)))
@end lisp

@cindex polices stumpwm
Par défaut StumpWM utilise les polices X11, qui peuvent être petites ou
pixelisées sur votre système. Vous pouvez corriger cela en installant le
module Lisp pour StumpWM @code{sbcl-ttf-fonts}, en l'ajoutant aux paquets de
votre système :

@lisp
(use-modules (gnu))
(use-package-modules fonts wm)

(operating-system
  ;; …
  (packages (append (list sbcl stumpwm `(,stumpwm "lib"))
                    sbcl-ttf-fonts font-dejavu %base-packages)))
@end lisp

Ensuite vous devrez ajouter le code suivant à au fichier de configuration de
StumpWM @file{~/.stumpwm.d/init.lisp} :

@lisp
(require :ttf-fonts)
(setf xft:*font-dirs* '("/run/current-system/profile/share/fonts/"))
(setf clx-truetype:+font-cache-filename+ (concat (getenv "HOME") "/.fonts/font-cache.sexp"))
(xft:cache-fonts)
(set-font (make-instance 'xft:font :family "DejaVu Sans Mono" :subfamily "Book" :size 11))
@end lisp

@node Verrouillage de session
@subsection Verrouillage de session
@cindex verrouillage de session

En fonction de votre environnement, le verrouillage de l'écran peut être
inclus, ou vous devrez le configurer vous-même. La fonctionnalité est
souvent intégrée aux environnements de bureau comme GNOME ou KDE. Si vous
utilisez un gestionnaire de fenêtre comme StumpWM ou EXWM, vous devrez sans
doute le configurer vous-même.

@node Xorg
@subsubsection Xorg

Si vous utilisez Xorg, vous pouvez utiliser l'utilitaire
@uref{https://www.mankier.com/1/xss-lock, xss-lock} pour verrouiller votre
session. xss-lock est lancé par DPMS qui est détecté et activé
automatiquement par Xorg 1.8 si ACPI est aussi activé à l'exécution dans le
noyau.

Pour utiliser xss-lock, vous pouvez simplement l'exécuter et le laisser
tourner en tache de fond avant de démarrer votre gestionnaire de fenêtre,
par exemple dans votre @file{~/.xsession} :

@example
xss-lock -- slock &
exec stumpwm
@end example

Dans cet exemple, xss-lock utilise @code{slock} pour effectivement
verrouiller l'écran quand il pense que c'est nécessaire, comme lorsque vous
mettez votre machine en veille.

Pour que slock puisse verrouiller l'écran de la session graphique, il doit
être en setuid-root pour qu'il puisse authentifier les utilisateurs, et il a
besoin d'un service PAM. On peut y arriver en ajoutant le service suivant
dans notre @file{config.scm} :

@lisp
(screen-locker-service slock)
@end lisp

Si vous verrouillez l'écran manuellement, p.@: ex.@: en appelant slock
directement si vous voulez verrouiller l'écran sans mettre l'ordinateur en
veille, il vaut mieux notifier xss-lock pour éviter la confusion. Vous
pouvez faire cela en exécutant @code{xset s activate} juste avant d'exécuter
slock.

@node Lancer Guix sur un serveur Linode
@section Lancer Guix sur un serveur Linode
@cindex linode, Linode

Pour lancer Guix sur un serveur hébergé par @uref{https://www.linode.com,
Linode}, commencez par un serveur Debian recommandé. Nous vous recommandons
d'utiliser la distribution par défaut pour amorcer Guix. Créez vos clés SSH.

@example
ssh-keygen
@end example

Assurez-vous d'ajouter votre clé SSH pour vous connecter facilement sur le
serveur distant. C'est facilité par l'interface graphique de Linode. Allez
sur votre profil et cliquez sur le bouton pour ajouter une clé SSH. Copiez
la sortie de :

@example
cat ~/.ssh/<username>_rsa.pub
@end example

Éteignez votre Linode.

Dans l'onglet de stockage du Linode, modifiez la taille du disque Debian
pour qu'il soit plus petit. Nous recommandons 30 Go d'espace libre. Ensuite,
cliquez sur « Ajouter un disque » et remplissez le formulaire de cette
manière :

@itemize @bullet
@item
Label: "Guix"

@item
Filesystem: ext4

@item
Donnez-lui la taille restante
@end itemize

Dans l'onglet de configuration, cliquez sur « modifier » sur le profil
Debian par défaut. Dans « Block Device Assignment » cliquez sur « Add a
Device ». Il devrait apparaître en tant que @file{/dev/sdc} et vous pouvez
sélectionner le disque « Guix ». Sauvegardez les changements.

Maintenant « Add a Configuration », avec ce qui suit :
@itemize @bullet
@item
Label: Guix

@item
Kernel: GRUB 2 (c'est à la toute fin ! Cette étape est @b{IMPORTANTE !})

@item
Périphériques blocs assignés :

@item
@file{/dev/sda} : Guix

@item
@file{/dev/sdb} : swap

@item
Périphérique racine : @file{/dev/sda}

@item
Désactivez tous les programmes d'aide pour les systèmes de fichiers et le
démarrage
@end itemize

Maintenant démarrez le serveur avec la configuration Debian. Une fois lancé,
connectez vous en ssh au serveur avec @code{ssh
root@@@var{<IP-de-votre-serveur-ici>}}. (Vous pouvez trouver l'adresse IP de
votre serveur dans la section résumé de Linode). Maintenant vous pouvez
lancer les étapes d'installation de @pxref{Installation binaire,,, guix.fr,
GNU Guix} :

@example
sudo apt-get install gpg
wget https://sv.gnu.org/people/viewgpg.php?user_id=15145 -qO - | gpg --import -
wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh
chmod +x guix-install.sh
./guix-install.sh
guix pull
@end example

Maintenant il est temps d'écrire une configuration pour le serveur. Voici ce
que vous devrez obligatoirement écrire, en plus de vos propres
configurations. Enregistrez le fichier avec le nom @file{guix-config.scm}.

@lisp
(use-modules (gnu)
             (guix modules))
(use-service-modules networking
                     ssh)
(use-package-modules admin
                     certs
                     package-management
                     ssh
                     tls)

(operating-system
  (host-name "my-server")
  (timezone "America/New_York")
  (locale "en_US.UTF-8")
  ;; Ce code va générer un grub.cfg
  ;; sans installer le chargeur d'amorçage grub sur le disque.
  (bootloader (bootloader-configuration
               (bootloader
                (bootloader
                 (inherit grub-bootloader)
                 (installer #~(const #true))))))
  (file-systems (cons (file-system
                        (device "/dev/sda")
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems))


  (swap-devices (list "/dev/sdb"))


  (initrd-modules (cons "virtio_scsi"    ; Requis pour trouver le disque
                        %base-initrd-modules))

  (users (cons (user-account
                (name "janedoe")
                (group "users")
                ;; Ajoute le compte au groupe « wheel »
                ;; pour en faire un sudoer.
                (supplementary-groups '("wheel"))
                (home-directory "/home/janedoe"))
               %base-user-accounts))

  (packages (cons* nss-certs            ; pour l'accès HTTPS
                   openssh-sans-x
                   %base-packages))

  (services (cons*
             (service dhcp-client-service-type)
             (service openssh-service-type
                      (openssh-configuration
                       (openssh openssh-sans-x)
                       (password-authentication? #false)
                       (authorized-keys
                        `(("janedoe" ,(local-file "janedoe_rsa.pub"))
                          ("root" ,(local-file "janedoe_rsa.pub"))))))
             %base-services)))
@end lisp

Remplacez les champs suivants dans la configuration ci-dessus :
@lisp
(host-name "my-server")       ; remplacez avec le nom de votre serveur
; si vous avez choisi un serveur Linode en dehors des U.S.,
; utilisez tzselect pour trouver le bon fuseau horaire
(timezone "America/New_York") ; remplacez le fuseau horaire si besoin
(name "janedoe")              ; remplacez avec votre nom d'utilisateur
("janedoe" ,(local-file "janedoe_rsa.pub")) ; remplacez par votre clé ssh
("root" ,(local-file "janedoe_rsa.pub")) ; remplacez par votre clé ssh
@end lisp

Cette dernière ligne vous permet de vous connecter au serveur en root et de
créer le mot de passe initial de root (voir la note à la fin de cette
recette sur la connexion en root). Après avoir fait cela, vous pouvez
supprimer cette ligne de votre configuration et reconfigurer pour empêcher
la connexion directe en root.

Copiez votre clé ssh publique (ex : @file{~/.ssh/id_rsa.pub}) dans
@file{@var{<votre-nom-d'utilisateur>}_rsa.pub} et ajoutez votre
@file{guix-config.scm} au même répertoire. Dans un nouveau terminal lancez
ces commandes.

@example
sftp root@@<adresse IP du serveur distant>
put /path/to/files/<username>_rsa.pub .
put /path/to/files/guix-config.scm .
@end example

Dans votre premier terminal, montez le disque guix :

@example
mkdir /mnt/guix
mount /dev/sdc /mnt/guix
@end example

À cause de la manière dont nous avons paramétré la section du chargeur
d'amorçage dans le fichier guix-config.scm, nous installons seulement notre
fichier de configuration grub. Donc on doit copier certains fichiers GRUB
déjà installés sur le système Debian :

@example
mkdir -p /mnt/guix/boot/grub
cp -r /boot/grub/* /mnt/guix/boot/grub/
@end example

Maintenant initialisez l'installation de Guix :

@example
guix system init guix-config.scm /mnt/guix
@end example

Ok, éteignez maintenant le serveur ! Depuis la console Linode, démarrez et
choisissez « Guix ».

Une fois démarré, vous devriez pouvoir vous connecter en SSH ! (La
configuration du serveur aura cependant changé). Vous pouvez rencontrer une
erreur de ce type :

@example
$ ssh root@@<server ip address>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:0B+wp33w57AnKQuHCvQP0+ZdKaqYrI/kyU7CfVbS7R4.
Please contact your system administrator.
Add correct host key in /home/joshua/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/joshua/.ssh/known_hosts:3
ECDSA host key for 198.58.98.76 has changed and you have requested strict checking.
Host key verification failed.
@end example

Vous pouvez soit supprimer @file{~/.ssh/known_hosts}, soit supprimer la
ligne qui pose problème, qui commence par l'adresse IP de votre serveur.

Assurez-vous de configurer votre mot de passe et celui de root.

@example
ssh root@@<remote ip address>
passwd  ; pour le mot de passe root
passwd <username> ; pour le mot de passe utilisateur
@end example

Il se peut que vous ne puissiez pas lancer les commandes précédentes si vous
n'arrivez pas à vous connecter à distance via SSH, auquel cas vous devrez
peut-être configurer vos mot de passes utilisateurs et root en cliquant sur
« Launch Console » dans votre espace Linode. Choisissez « Glish » au lieu de
« Weblish ». Maintenant vous devriez pouvoir vous connecter en ssh à la
machine.

Hourra ! Maintenant vous pouvez étendre le serveur, supprimer le disque
Debian et redimensionner celui de Guix. Bravo !

Au fait, si vous sauvegardez le résultat dans une image disque maintenant,
vous pourrez plus facilement démarrer de nouvelles images de guix ! Vous
devrez peut-être réduire la taille de l'image Guix à 6144 Mo, pour la
sauvegarder en tant qu'image. Ensuite vous pouvez redimensionner la
partition à la taille maximum.

@node Mettre en place un montage dupliqué
@section Mettre en place un montage dupliqué

Pour dupliquer le montage d'un système de fichier (@i{bind mount}), on doit
d'abord ajouter quelques définitions avant la section
@code{operating-system} de la définition de système d'exploitation. Dans cet
exemple nous allons dupliquer le montage d'un dossier d'un disque dur vers
@file{/tmp}, pour éviter d'épuiser le SSD principal, sans dédier une
partition entière à @file{/tmp}.

Déjà, le disque source qui héberge de dossier dont nous voulons dupliquer le
montage doit être défini, pour que le montage dupliqué puisse en dépendre.

@lisp
(define source-drive ;; vous pouvez nommer « source-drive » comme vous le souhaitez.
   (file-system
    (device (uuid "indiquez l'UUID ici"))
    (mount-point "/chemin-vers-le-disque-dur")
    (type "ext4"))) ;; Assurez-vous d'indiquer le bon type pour la partition
@end lisp

Le dossier source doit aussi être défini, pour que guix sache qu'il ne
s'agit pas d'un périphérique bloc, mais d'un dossier.
@lisp
(define (%source-directory) "/chemin-vers-le-disque-dur/tmp") ;; vous pouvez nommer « source-directory » comme vous le souhaitez.
@end lisp

Enfin, dans la définition @code{file-systems}, on doit ajouter le montage
lui-même.

@lisp
(file-systems (cons*

                ...<d'autres montages omis pour rester concis>...

                source-drive ;; Doit correspondre au nom que vous avez donné au disque source dans la définition précédente.

                (file-system
                 (device (%source-directory)) ;; Assurez-vous que « source-directory » corresponde à la définition précédente.
                 (mount-point "/tmp")
                 (type "none") ;; On monte un dossier, pas une partition, donc le montage est de type « none »
                 (flags '(bind-mount))
                 (dependencies (list source-drive)) ;; Assurez-vous que « source-drive » corresponde au nom de la variable pour le disque.
                 )

                 ...<d'autres montages omis pour rester concis>...

                ))
@end lisp

@node Récupérer des substituts via Tor
@section Récupérer des substituts via Tor

Le démon Guix peut utiliser un mandataire HTTP pour récupérer des
substituts. Nous le configurons ici pour les récupérer par Tor.

@quotation Attention
@emph{Tout} le trafic du démon de passera @emph{pas} par Tor ! Seuls
HTTP/HTTPS passer par le mandataire ; les connexions FTP, avec le protocol
Git, SSH, etc, passeront toujours par le réseau en clair. De nouveau, cette
configuration n'est pas parfaite et une partie de votre trafic ne sera pas
routé par Tor du tout. Utilisez-la à vos risques et périls.

Remarquez aussi que la procédure décrite ici ne s'applique qu'à la
substitution de paquets. Lorsque vous mettez à jour la distribution avec
@command{guix pull}, vous aurez encore besoin de @command{torsocks} si vous
voulez router la connexion vers les serveurs de dépôts git à travers Tor.
@end quotation

Le serveur de substitut de Guix est disponible sur un service Onion. Si vous
voulez l'utiliser pour récupérer des substituts par Tor, configurez votre
système de cette manière :

@lisp
(use-modules (gnu))
(use-service-module base networking)

(operating-system
  …
  (services
    (cons
      (service tor-service-type
              (tor-configuration
                (config-file (plain-file "tor-config"
                                         "HTTPTunnelPort 127.0.0.1:9250"))))
      (modify-services %base-services
        (guix-service-type
          config => (guix-configuration
                      (inherit config)
                      ;; service Onion de ci.guix.gnu.org
                      (substitute-urls
                       "@value{SUBSTITUTE-TOR-URL}")
                      (http-proxy "http://localhost:9250")))))))
@end lisp

Cela fera tourner le processus tor et fournira un tunnel HTTP CONNECT qui
sera utilisé par @command{guix-daemon}. Le démon peut utiliser d'autres
protocoles que HTTP(S) pour récupérer des ressources distantes. Les requêtes
utilisant ces protocoles ne passeront pas par Tor puisqu'il s'agit d'un
tunnel HTTP uniquement. Remarquez que @code{substitutes-urls} doit utiliser
HTTPS et non HTTP, sinon ça ne fonctionne pas. C'est une limite du tunnel de
Tor ; vous voudrez peut-être utiliser @command{privoxy} à la place pour
éviter ces limites.

Si vous ne voulez pas toute le temps récupérer des substituts à travers Tor
mais l'utiliser seulement de temps en temps, alors ne modifiez pas l'objet
@code{guix-configuration}. Lorsque vous voulez récupérer un substitut par le
tunnel Tor, lancez :

@example
sudo herd set-http-proxy guix-daemon http://localhost:9250
guix build \
  --substitute-urls=@value{SUBSTITUTE-TOR-URL} @dots{}
@end example

@node Configurer NGINX avec Lua
@section Configurer NGINX avec Lua
@cindex nginx, lua, openresty, resty

Les fonctionnalités de NGINX peuvent être étendues avec des scripts Lua.

Guix fournit un service NGINX qui est capable de charger des modules et des
paquets Lua spécifiques, et de répondre aux requêtes en évaluant des scripts
Lua.

L'exemple suivant montre une définition de système avec une configuration
qui évalue le script Lua @file{index.lua} lors d'une requête HTTP à
@uref{http://localhost/hello} :

@example
local shell = require "resty.shell"

local stdin = ""
local timeout = 1000  -- ms
local max_size = 4096  -- byte

local ok, stdout, stderr, reason, status =
   shell.run([[/run/current-system/profile/bin/ls /tmp]], stdin, timeout, max_size)

ngx.say(stdout)
@end example

@lisp
(use-modules (gnu))
(use-service-modules #;… web)
(use-package-modules #;… lua)
(operating-system
  ;; …
  (services
   ;; …
   (service nginx-service-type
            (nginx-configuration
             (modules
              (list
               (file-append nginx-lua-module "/etc/nginx/modules/ngx_http_lua_module.so")))
             (lua-package-path (list lua-resty-core
                                     lua-resty-lrucache
                                     lua-resty-signal
                                     lua-tablepool
                                     lua-resty-shell))
             (lua-package-cpath (list lua-resty-signal))
             (server-blocks
              (list (nginx-server-configuration
                     (server-name '("localhost"))
                     (listen '("80"))
                     (root "/etc")
                     (locations (list
                                 (nginx-location-configuration
                                  (uri "/hello")
                                  (body (list #~(format #f "content_by_lua_file ~s;"
                                                        #$(local-file "index.lua"))))))))))))))
@end lisp

@node Serveur de musique avec l'audio bluetooth
@section Serveur de musique avec l'audio bluetooth
@cindex mpd
@cindex serveur de musique, sans affichage
@cindex bluetooth, configuration ALSA

MPD, le démon lecteur de musique, est une application serveur flexible pour
jouer de la musique. Les programmes clients sur différentes machines du
réseau — un téléphone portable, un ordinateur portable, un ordinateur de
bureau — peuvent s'y connecter pour contrôler la lecture de fichiers audio
de votre collection musicale locale. MPD décode les fichiers audio et les
joue sur une ou plusieurs sorties.

Par défaut MPD jouera sur le périphérique audio par défaut. Dans l'exemple
ci-dessous nous rendons les choses un peu plus intéressantes en configurant
un serveur de musique sans affichage. Il n'y aura pas d'interface graphique,
pas de démon Pulseaudio, ni de sortie audio locale. Au lieu de cela, nous
configurons MPD avec deux sorties : un haut-parleur bluetooth et un serveur
web pour servir des flux audio à n'importe quel lecture de musique.

Le Bluetooth est souvent frustrant à configurer. Vous devrez appairer vos
périphériques Bluetooth et vous assurer que le périphérique se connecte
automatiquement dès qu'il est branché. Le service système Bluetooth renvoyé
par la procédure @code{bluetooth-service} fournit l'infrastructure requise
pour cette configuration.

Reconfigurez votre système avec au moins les services et les paquets
suivants :

@lisp
(operating-system
  ;; …
  (packages (cons* bluez bluez-alsa
                   %base-packages))
  (services
   ;; …
   (dbus-service #:services (list bluez-alsa))
   (bluetooth-service #:auto-enable? #t)))
@end lisp

Démarrez le service @code{bluetooth} puis utilisez @command{bluetoothctl}
pour scanner les périphériques Bluetooth. Essayez d'identifier votre
haut-parleur Bluetooth et choisissez son ID de périphérique dans la liste de
périphériques qui est indubitablement polluée par une armée de gadgets
connectés chez votre voisin. Vous ne devrez le faire qu'une seule fois :

@example
$ bluetoothctl 
[NEW] Controller 00:11:22:33:95:7F BlueZ 5.40 [default]

[bluetooth]# power on
[bluetooth]# Changing power on succeeded

[bluetooth]# agent on
[bluetooth]# Agent registered

[bluetooth]# default-agent
[bluetooth]# Default agent request successful

[bluetooth]# scan on
[bluetooth]# Discovery started
[CHG] Controller 00:11:22:33:95:7F Discovering: yes
[NEW] Device AA:BB:CC:A4:AA:CD My Bluetooth Speaker
[NEW] Device 44:44:FF:2A:20:DC My Neighbor's TV
@dots{}

[bluetooth]# pair AA:BB:CC:A4:AA:CD
Attempting to pair with AA:BB:CC:A4:AA:CD
[CHG] Device AA:BB:CC:A4:AA:CD Connected: yes

[My Bluetooth Speaker]# [CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110b-0000-1000-8000-00xxxxxxxxxx
[CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110c-0000-1000-8000-00xxxxxxxxxx
[CHG] Device AA:BB:CC:A4:AA:CD UUIDs: 0000110e-0000-1000-8000-00xxxxxxxxxx
[CHG] Device AA:BB:CC:A4:AA:CD Paired: yes
Pairing successful

[CHG] Device AA:BB:CC:A4:AA:CD Connected: no

[bluetooth]# 
[bluetooth]# trust AA:BB:CC:A4:AA:CD
[bluetooth]# [CHG] Device AA:BB:CC:A4:AA:CD Trusted: yes
Changing AA:BB:CC:A4:AA:CD trust succeeded

[bluetooth]# 
[bluetooth]# connect AA:BB:CC:A4:AA:CD
Attempting to connect to AA:BB:CC:A4:AA:CD
[bluetooth]# [CHG] Device AA:BB:CC:A4:AA:CD RSSI: -63
[CHG] Device AA:BB:CC:A4:AA:CD Connected: yes
Connection successful

[My Bluetooth Speaker]# scan off
[CHG] Device AA:BB:CC:A4:AA:CD RSSI is nil
Discovery stopped
[CHG] Controller 00:11:22:33:95:7F Discovering: no
@end example

Félicitations, vous pouvez maintenant vous connecter automatiquement à votre
haut-parleur Bluetooth !

Il est maintenant temps de configurer ALSA pour utiliser le module Bluetooth
@emph{bluealsa}, pour que vous puissiez définir un périphérique pcm ALSA
correspondant à votre haut-parleur Bluetooth. Un serveur sans affichage
utilisant @emph{bluealsa} avec un périphérique fixe est probablement plus
facile à configurer que Pulseaudio et son comportement de changement de
flux. Nous configurons ALSA en créant un @code{alsa-configuration}
personnalisé pour le service @code{alsa-service-type}. La configuration
déclarera un type @code{pcm} @code{bluealsa} du module @code{bluealsa}
fournit par le paquet @code{bluez-alsa}, puis définira un périphérique
@code{pcm} de ce type pour le haut-parleur Bluetooth.

Tout ce qui reste à faire est de faire en sorte que MPD envoie les données
audio à ce périphérique ALSA. Nous ajoutons aussi une sortie MPD secondaire
qui rend les fichiers audio en lecture disponibles en streaming sur un
serveur web sur le port 8080. Lorsque la sortie est activée, un appareil sur
le réseau peut écouter le flux audio en se connectant avec n'importe quel
lecteur multimédia au serveur HTTP sur le port 8080, indépendamment du
statut du haut-parleur Bluetooth.

Voici les grandes lignes d'une déclaration @code{operating-system} qui
devrait accomplir les tâches sus-mentionnées :

@lisp
(use-modules (gnu))
(use-service-modules audio dbus sound #;… etc)
(use-package-modules audio linux #;… etc)
(operating-system
  ;; …
  (packages (cons* bluez bluez-alsa
                   %base-packages))
  (services
   ;; …
   (service mpd-service-type
            (mpd-configuration
             (user "your-username")
             (music-dir "/path/to/your/music")
             (address "192.168.178.20")
             (outputs (list (mpd-output
                             (type "alsa")
                             (name "MPD")
                             (extra-options
                              ;; Utilisez le même nom que dans la configuration
                              ;; ALSA plus bas.
                              '((device . "pcm.btspeaker"))))
                            (mpd-output
                             (type "httpd")
                             (name "streaming")
                             (enabled? #false)
                             (always-on? #true)
                             (tags? #true)
                             (mixer-type 'null)
                             (extra-options
                              '((encoder . "vorbis")
                                (port    . "8080")
                                (bind-to-address . "192.168.178.20")
                                (max-clients . "0") ;no limit
                                (quality . "5.0")
                                (format  . "44100:16:1"))))))))
   (dbus-service #:services (list bluez-alsa))
   (bluetooth-service #:auto-enable? #t)
   (service alsa-service-type
            (alsa-configuration
             (pulseaudio? #false) ;we don't need it
             (extra-options
              #~(string-append "\
# Déclare un type de périphérique audio Bluetooth \"bluealsa\" du module bluealsa
pcm_type.bluealsa @{
    lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_pcm_bluealsa.so") "\"
@}

# Déclare un type de périphérique de contrôle \"bluealsa\" du même module
ctl_type.bluealsa @{
    lib \"" #$(file-append bluez-alsa "/lib/alsa-lib/libasound_module_ctl_bluealsa.so") "\"
@}

# Définie le périphérique Bluetooth audio.
pcm.btspeaker @{
    type bluealsa
    device \"AA:BB:CC:A4:AA:CD\" # unique device identifier
    profile \"a2dp\"
@}

# Définie un contrôleur associé.
ctl.btspeaker @{
    type bluealsa
@}
"))))))
@end lisp

Profitez de votre musique avec le client MPD de votre choix ou un lecteur
multimédia capable de streamer en HTTP !


@c *********************************************************************
@node Conteneurs
@chapter Conteneurs

Le noyau Linux fournit un certain nombre de dispositifs partagés qui sont
disponibles pour les processus du système. Ces dispositifs sont entre autres
un vue partagée du système de fichiers, des autres processus, des
périphériques réseau, des identités de groupe et d'utilisateur et quelques
autres. Depuis Linux 3.19 vous pouvez choisir de @emph{départager} certains
de ces dispositifs partagés pour des processus choisis, en leur fournissant
(ainsi qu'à leurs processus enfant) une vue différente du système.

Un processus avec un espace de nom de montage (@code{mount}) départagé par
exemple, a sa propre vue du système de fichier — il ne pourra voir que les
répertoires qui ont été explicitement liés à son espace de nom de
montage. Un processus avec son propre espace de nom de processus
(@code{proc}) considérera qu'il est le seul processus lancé sur le système,
avec le PID 1.

Guix utilise ces fonctionnalités du noyau pour fournir des environnement
complètement isolés e même des conteneurs complets pour le système Guix, des
machines virtuelles légères qui partagent le noyau de l'hôte. Cette
fonctionnalité est particulièrement pratique si vous utilise Guix sur une
distribution externe pour éviter les interférence avec les bibliothèques ou
les fichiers de configuration externes disponibles sur l'ensemble du
système.

@menu
* Conteneurs Guix::          Environnements parfaitement isolés
* Conteneurs pour le système Guix::  Un système dans votre système
@end menu

@node Conteneurs Guix
@section Conteneurs Guix

La manière la plus simple de démarrer est d'utiliser @command{guix shell}
avec l'option @option{--container}. @xref{Invoquer guix shell,,, guix.fr, le
manuel de référence de GNU Guix} pour la référence des options valides.

Le bout de code suivant démarre un shell minimal avec la plupart des espaces
de noms départagés du système. Le répertoire de travail actuel est visible
pour le processus, mais tout le reste du système de fichiers est
indisponible. Cette isolation extrême peut être très utile si vous voulez
écarter toute interférence des variables d'environnement, des bibliothèques
installées globalement ou des fichiers de configuration.

@example
guix shell --container
@end example

C'est un environnement vierge, aride et désolé. Vous trouverez que même GNU
coreutils n'y est pas disponible, donc pour explorer cet environnement
désert vous devrez utiliser les commandes internes au shell. Même le
répertoire @file{/gnu/store} habituellement énorme est réduit à peau de
chagrin.

@example sh
$ echo /gnu/store/*
/gnu/store/@dots{}-gcc-10.3.0-lib
/gnu/store/@dots{}-glibc-2.33
/gnu/store/@dots{}-bash-static-5.1.8
/gnu/store/@dots{}-ncurses-6.2.20210619
/gnu/store/@dots{}-bash-5.1.8
/gnu/store/@dots{}-profile
/gnu/store/@dots{}-readline-8.1.1
@end example

@cindex quitter un conteneur
Vous ne pouvez pas faire grand chose de plus dans un environnement comme
celui-ci à part en sortir. Vous pouvez utiliser @key{Ctrl-D} ou
@command{exit} pour quitter cet environnement shell limité.

@cindex exposer des répertoires, conteneur
@cindex partager des répertoires, conteneur
@cindex faire correspondre des emplacement, conteneur
Vous pouvez rendre d'autres répertoires disponibles à l'intérieur de
l'environnement du conteneur. Utilisez @option{--expose=RÉPERTOIRE} pour
créer un montage lié au répertoire donné en lecture-seule à l'intérieur du
conteneur, ou utilisez @option{--share=RÉPERTOIRE} pour rendre cet
emplacement inscriptible. Avec un argument de correspondance supplémentaire
après le nom du répertoire vous pouvez contrôler le nom du répertoire lié
dans le conteneur. Dans l'exemple suivant nous faisons correspondre
@file{/etc} du système hôte à @file{/l/hôte/etc} dans un conteneur dans
lequel GNU coreutils est installé.

@example sh
$ guix shell --container --share=/etc=/l/hôte/etc coreutils
$ ls /l/hôte/etc
@end example

De même, vous pouvez empêcher le répertoire actuel d'être ajouté au
conteneur avec l'option @option{--no-cwd}. Une autre bonne idée est de créer
un répertoire dédié qui servira de répertoire personnel dans le conteneur et
de démarrer le shell du conteneur dans ce répertoire.

@cindex cacher les bibliothèques système, conteneur
@cindex éviter les incompatibilités d'ABI, conteneur
Sur un système externe un environnement de conteneur peut être utilisé pour
compiler un logiciel qui ne peut pas être lié aux bibliothèques du système
ou avec la chaine d'outils du système. Un cas d'utilisation courant dans le
contexte de la recherche est l'installation de paquets à partir d'une
session R. En dehors de l'environnement du conteneur il est fort probable
que la chaine de compilation externe et les bibliothèques systèmes
incompatibles soient trouvés en premier, ce qui créer des binaires
incompatibles qui ne peuvent pas être utilisés dans R. Dans un conteneur ce
problème disparait car les bibliothèques du système et les executables ne
sont simplement pas disponibles à cause de l'espace de nom @code{mount}
départagé.

Prenons un manifeste complet pour fournir un environnement de développement
confortable pour R :

@lisp
(specifications->manifest
  (list "r-minimal"

        ;; paquets de base
        "bash-minimal"
        "glibc-locales"
        "nss-certs"

        ;; Outils en ligne de commande usuels, sans lesquels le conteneur est trop vide.
        "coreutils"
        "grep"
        "which"
        "wget"
        "sed"

        ;; outils markdown pour R
        "pandoc"

        ;; Chaine d'outils et bibliothèques courantes pour « install.packages »
        "gcc-toolchain@@10"
        "gfortran-toolchain"
        "gawk"
        "tar"
        "gzip"
        "unzip"
        "make"
        "cmake"
        "pkg-config"
        "cairo"
        "libxt"
        "openssl"
        "curl"
        "zlib"))
@end lisp

Utilisons cela pour lancer R dans un environnement de conteneur. Pour se
simplifier la vie, nous partageons l'espace de nom @code{net} pour utiliser
les interfaces réseau du système hôte. Maintenant nous pouvons construire
des paquets R à partir des sources de la manière traditionnelle sans avoir à
se soucier des incompatibilités d'ABI.

@example sh
$ guix shell --container --network --manifest=manifest.scm -- R

R version 4.2.1 (2022-06-23) -- "Funny-Looking Kid"
Copyright (C) 2022 The R Foundation for Statistical Computing
@dots{}
> e <- Sys.getenv("GUIX_ENVIRONMENT")
> Sys.setenv(GIT_SSL_CAINFO=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
> Sys.setenv(SSL_CERT_FILE=paste0(e, "/etc/ssl/certs/ca-certificates.crt"))
> Sys.setenv(SSL_CERT_DIR=paste0(e, "/etc/ssl/certs"))
> install.packages("Cairo", lib=paste0(getwd()))
@dots{}
* installing *source* package 'Cairo' ...
@dots{}
* DONE (Cairo)

The downloaded source packages are in
	'/tmp/RtmpCuwdwM/downloaded_packages'
> library("Cairo", lib=getwd())
> # success!
@end example

Utiliser des shells conteneurs est amusant, mais ils peuvent devenir un peu
embêtant quand vous voulez plus qu'un seul processus interactif. Certaines
tâches deviennent plus faciles lorsqu'elles se reposent sur les fondations
solides d'un système Guix et de son riche ensemble de services systèmes. La
section suivante vous montre comment lancer un système Guix complet à
l'intérieur d'un conteneur.


@node Conteneurs pour le système Guix
@section Conteneurs pour le système Guix

Le système Guix fournit un large éventail de services systèmes
interconnectés configurés déclarativement pour former les fondations d'un
système GNU fiable et sans état pour n'importe quelle tâche que vous lui
donnez. Même lorsque vous utilisez Guix sur une distribution externe, vous
pouvez bénéficier de la conception du système Guix en lançant une instance
du système dans un conteneur. Avec les mêmes fonctionnalités d'espaces de
noms départagés mentionnés dans la section précédente, l'instance du système
Guix qui en résulte est isolée du système hôte et ne partage que les
emplacements de fichiers que vous avez explicitement déclarés.

Un conteneur du système Guix est différent du processus shell créé par
@command{guix shell --container} de plusieurs façons importantes. Dans un
shell conteneur le processus de conteneurisation est le processus de shell
Bash alors qu'une conteneur du système Guix fait tourner le Shepherd en PID
1. Dans un conteneur système tous les services systèmes (@pxref{Services,,,
guix.fr, le manuel de référence de GNU Guix}) sont paramétrés de la même
manière que sur un système Guix dans une machine virtuelle ou directement
sur le matériel. Cela comprend les démons gérés par le GNU@tie{}Shepherd
(@pxref{Services Shepherd,,, guix.fr, le manuel de référence de GNU Guix})
ainsi que d'autres types d'extensions du système d'exploitation
(@pxref{Composition de services,,, guix.fr, le manuel de référence de GNU
Guix}).

La complexité perçue comme croissante d'un conteneur du système Guix est
facilement justifiée lorsque vous devez traiter avec des applications plus
complexes qui ont des prérequis plus grands ou plus rigides sur leur
contexte d'exécution — des fichiers de configuration, des comptes
utilisateurs dédiés, des répertoires pour les le cache ou les fichiers
journaux, etc. Sur le système Guix, la demande de ce genre de logiciels est
satisfaite en déployant des services systèmes.


@node Un conteneur de base de données
@subsection Un conteneur de base de données

Un bon exemple pourrait être un serveur de base de données PostgreSQL. La
majeure partie de la complexité de configuration d'un tel serveur de base de
données est encapsulée dans cette déclaration trompeusement courtes :

@lisp
(service postgresql-service-type
         (postgresql-configuration
          (postgresql postgresql-14)))
@end lisp

Une déclaration de système d'exploitation complète utilisable avec un
conteneur du système Guix ressemblerait à ceci :

@lisp
(use-modules (gnu))
(use-package-modules databases)
(use-service-modules databases)

(operating-system
  (host-name "container")
  (timezone "Europe/Berlin")
  (file-systems (cons (file-system
                        (device (file-system-label "does-not-matter"))
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems))
  (bootloader (bootloader-configuration
               (bootloader grub-bootloader)
               (targets '("/dev/sdX"))))
  (services
   (cons* (service postgresql-service-type
                   (postgresql-configuration
                    (postgresql postgresql-14)
                    (config-file
                     (postgresql-config-file
                      (log-destination "stderr")
                      (hba-file
                       (plain-file "pg_hba.conf"
                                   "\
local	all	all			trust
host	all	all	10.0.0.1/32 	trust"))
                      (extra-config
                       '(("listen_addresses" "*")
                         ("log_directory"    "/var/log/postgresql")))))))
          (service postgresql-role-service-type
                   (postgresql-role-configuration
                    (roles
                     (list (postgresql-role
                            (name "test")
                            (create-database? #t))))))
          %base-services)))
@end lisp

Avec @code{postgresql-role-service-type} nous définissons un rôle « test »
et créons une base de données correspondante, pour que nous puissions le
tester immédiatement sans autre paramétrage manuel. Les paramètres de
@code{postgresql-config-file} permettent à un client de se connecter à
partir de l'adresse IP 10.0.0.1 sans authentification — une mauvaise idée en
production, mais pratique pour cet exemple.

Construisons un script qui exécutera une instance de ce système Guix dans un
conteneur. Écrivez la déclaration @code{operating-system} ci-dessus dans un
fichier @file{os.scm} puis utilisez @command{guix system container} pour
construire le lanceur (@pxref{Invoquer guix system,,, guix.fr, le manuel de
référence de GNU Guix}).

@example
$ guix system container os.scm
Les dérivations suivantes seront construites :
  /gnu/store/@dots{}-run-container.drv
  @dots{}
construction de /gnu/store/@dots{}-run-container.drv...
/gnu/store/@dots{}-run-container
@end example

Maintenant que nous avons le script de lancement nous pouvons le lancer pour
démarrer le nouveau système avec un service PostgreSQL. Remarquez qu'à cause
de limites non encore résolues, nous devons lancer le lanceur en root, par
exemple avec @command{sudo}.

@example
$ sudo /gnu/store/@dots{}-run-container
le conteneur système tourne avec le PID 5983
@dots{}
@end example

Mettez le processus en fond avec @key{Ctrl-z} suivie de @command{bg}. Prenez
note de l'ID du processus dans la sortie ; nous en aurons besoin pour nous
connecter au conteneur plus tard. Vous savez quoi ? Essayons de nous
attacher au conteneur immédiatement. Nous utiliserons @command{nsenter}, un
outil fournit par le paquet @code{util-linux} :

@example
$ guix shell util-linux
$ sudo nsenter -a -t 5983
root@@container /# pgrep -a postgres
49 /gnu/store/@dots{}-postgresql-14.4/bin/postgres -D /var/lib/postgresql/data --config-file=/gnu/store/@dots{}-postgresql.conf -p 5432
51 postgres: checkpointer
52 postgres: background writer
53 postgres: walwriter
54 postgres: autovacuum launcher
55 postgres: stats collector
56 postgres: logical replication launcher
root@@container /# exit
@end example

Le service PostgreSQL tourne dans le conteneur !


@node Utilisation du réseau dans le conteneur
@subsection Utilisation du réseau dans le conteneur
@cindex configuration réseau d'un conteneur

Que vaut un système Guix dans lequel tourne un service de bases de données
PostgreSQL dans un conteneur si nous ne pouvons lui parler qu'avec des
processus originaire de ce conteneur ? Il serait bien mieux de pouvoir
parler à la base de données via le réseau.

La manière la plus simple de faire cela est de créer une paire de
périphérique Ethernet virtuels (connus sous le nom de @code{veth}). Nous
déplaçons l'un des périphériques (@code{ceth-test}) dans l'espace de nom
@code{net} du conteneur et laissons l'autre côté (@code{veth-test}) de la
connexion sur le système hôte.

@example
pid=5983
ns="guix-test"
host="veth-test"
client="ceth-test"

# Attache le nouvel espace de nom réseau « guix-test » au PID du conteneur.
sudo ip netns attach $ns $pid

# Crée une paire de périphériques
sudo ip link add $host type veth peer name $client

# Déplace le périphérique client dans l'espace de nom réseau du conteneur
sudo ip link set $client netns $ns
@end example

Puis nous configurons le côté de l'hôte :

@example
sudo ip link set $host up
sudo ip addr add 10.0.0.1/24 dev $host
@end example

@dots{}puis nous configurons le côté client :

@example
sudo ip netns exec $ns  ip link set lo up
sudo ip netns exec $ns  ip link set $client up
sudo ip netns exec $ns  ip addr add 10.0.0.2/24 dev $client
@end example

Maintenant l'hôte peut atteindre le conteneur à l'adresse IP 10.0.0.2 et le
conteneur peut atteindre l'hôte à l'adresse IP 10.0.0.1. C'est tout ce dont
nous avons besoin pour communiquer avec le serveur de bases de données dans
le conteneur à partir du système hôte, à l'extérieur.

@example
$ psql -h 10.0.0.2 -U test
psql (14.4)
Type "help" for help.

test=> CREATE TABLE hello (who TEXT NOT NULL);
CREATE TABLE
test=> INSERT INTO hello (who) VALUES ('world');
INSERT 0 1
test=> SELECT * FROM hello;
  who
-------
 world
(1 row)
@end example

Maintenant que nous avons fini cette petite démonstration, nettoyons tout ça
:

@example
sudo kill $pid
sudo ip netns del $ns
sudo ip link del $host
@end example


@c *********************************************************************
@node Gestion avancée des paquets
@chapter Gestion avancée des paquets

Guix est un gestionnaire de paquets fonctionnel qui propose de nombreuses
fonctionnalités en plus de ce que les gestionnaires de paquets traditionnels
peuvent faire. Pour quelqu'un qui n'est pas initié, ces fonctionnalités
peuvent ne pas paraître utiles au premier coup d'œil. Le but de ce chapitre
est de vous montrer certains concepts avancés en gestion de paquets.

@pxref{Gestion des paquets,,, guix.fr, le manuel de référence de GNU Guix}
pour une référence complète.

@menu
* Les profils Guix en pratique::  Stratégies pour gérer plusieurs profils 
                                    et manifestes.
@end menu

@node Les profils Guix en pratique
@section Les profils Guix en pratique

Guix fournit une fonctionnalité utile que peut être plutôt étrange pour les
débutants et débutantes : les @emph{profils}. C'est une manière de regrouper
l'installation de paquets ensemble et chaque utilisateur ou utilisatrice du
même système peuvent avoir autant de profils que souhaité.

Que vous programmiez ou non, vous trouverez sans doute plus de flexibilité
et de possibilité avec plusieurs profils. Bien qu'ils changent un peu du
paradigme des @emph{gestionnaires de paquets traditionnels}, ils sont
pratiques à utiliser une fois que vous avec saisi comment les configurer.

Si vous connaissez @samp{virtualenv} de Python, vous pouvez conceptualiser
un profil comme une sorte de @samp{virtualenv} universel qui peut contenir
n'importe quel sorte de logiciel, pas seulement du code Python. En plus, les
profils sont auto-suffisants : ils capturent toutes les dépendances à
l'exécution qui garantissent que tous les programmes d'un profil
fonctionneront toujours à tout instant.

Avoir plusieurs profils présente de nombreux intérêts :

@itemize
@item
Une séparation sémantique claire des divers paquets dont vous avez besoin
pour différents contextes.

@item
On peut rendre plusieurs profils disponibles dans l'environnement soit à la
connexion, soit dans un shell dédié.

@item
Les profils peuvent être chargés à la demande. Par exemple, vous pouvez
utiliser plusieurs shells, chacun dans un profil différent.

@item
L'isolation : les programmes d'un profil n'utiliseront pas ceux d'un autre,
et vous pouvez même installe plusieurs versions d'un même programme dans
deux profils différents, sans conflit.

@item
Déduplication : les profils partagent les dépendances qui sont exactement
les mêmes. Avoir plusieurs profils ne gâche donc pas d'espace.

@item
Reproductible : lorsque vous utilisez des manifestes déclaratifs, un profil
peut être entièrement spécifié par le commit Guix qui a été utilisé pour le
créer. Cela signifie que vous pouvez
@uref{https://guix.gnu.org/blog/2018/multi-dimensional-transactions-and-rollbacks-oh-my/,
recréer n'importe où et à n'importe quel moment} exactement le même profil,
avec juste l'information du numéro de commit. Voir la section sur les
@ref{Profils reproductibles}.

@item
Des mises à jours et une maintenance plus faciles : avoir plusieurs profils
facilite la gestion des listes de paquets à la main.
@end itemize

Concrètement voici des profils courants :

@itemize
@item
Les dépendances d'un projet sur lequel vous travaillez.

@item
Des bibliothèques de votre langage de programmation favori.

@item
Des programmes spécifiques pour les ordinateurs portables (comme
@samp{powertop}) dont vous n'avez pas besoin sur un ordinateur de bureau.

@item
@TeX{}live (il peut être bien pratique si vous avez besoin d'installer un
seul paquet pour un document que vous avez reçu par courriel).

@item
Jeux.
@end itemize

Voyons cela de plus près !

@node Utilisation de base avec des manifestes
@subsection Utilisation de base avec des manifestes

Un profil Guix peut être paramétré par un @dfn{manifeste}. Un manifeste est
un bout de code Scheme qui spécifie l'ensemble des paquets que vous voulez
avoir dans votre profil ; il ressemble à ceci :

@lisp
(specifications->manifest
  '("package-1"
    ;; Version 1.3 de package-2.
    "package-2@@1.3"
    ;; La sortie « lib » de package-3.
    "package-3:lib"
    ; ...
    "package-N"))
@end lisp

@xref{Écrire un manifeste,,, guix.fr, le manuel de référence de GNU Guix},
pour plus d'informations sur la syntaxe.

On peut créer une spécification de manifeste par profil et les installer de
cette manière :

@example
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
mkdir -p "$GUIX_EXTRA_PROFILES"/my-project # s'il n'existe pas encore
guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
@end example

On spécifie ici une variable arbitraire @samp{GUIX_EXTRA_PROFILES} pour
pointer vers le répertoire où seront stockés nos profils dans le reste de
cet article.

C'est un peu plus propre de placer tous vos profils dans un répertoire
unique, où chaque profil a son propre sous-répertoire. De cette manière,
chaque sous-répertoire contiendra tous les liens symboliques pour exactement
un profil. En plus, il devient facile d'énumérer les profils depuis
n'importe quel langage de programmation (p.@: ex.@: un script shell) en
énumérant simplement les sous-répertoires de @samp{$GUIX_EXTRA_PROFILES}.

Remarquez qu'il est aussi possible d'utiliser la sortie de

@example
guix package --list-profiles
@end example

même si vous devrez sans doute enlever @file{~/.config/guix/current}.

Pour activer tous les profils à la connexion, ajoutez cela à votre
@file{~/.bash_profile} (ou similaire) :

@example
for i in $GUIX_EXTRA_PROFILES/*; do
  profile=$i/$(basename "$i")
  if [ -f "$profile"/etc/profile ]; then
    GUIX_PROFILE="$profile"
    . "$GUIX_PROFILE"/etc/profile
  fi
  unset profile
done
@end example

Remarque pour les utilisateurs du système Guix : ce qui précède ressemble à
la manière dont votre profil par défaut @file{~/.guix-profile} est activé
dans @file{/etc/profile}, ce dernier étant chargé par défaut par
@file{~/.bashrc}.

Vous pouvez évidemment choisir de n'en activer qu'une partie :

@example
for i in "$GUIX_EXTRA_PROFILES"/my-project-1 "$GUIX_EXTRA_PROFILES"/my-project-2; do
  profile=$i/$(basename "$i")
  if [ -f "$profile"/etc/profile ]; then
    GUIX_PROFILE="$profile"
    . "$GUIX_PROFILE"/etc/profile
  fi
  unset profile
done
@end example

Lorsqu'un profil est désactivé, il est facile de l'activer pour un shell
individuel sans « polluer » le reste de la session :

@example
GUIX_PROFILE="path/to/my-project" ; . "$GUIX_PROFILE"/etc/profile
@end example

Le secret pour activer un profil est de @emph{sourcer} son fichier
@samp{etc/profile}. Ce fichier contient du code shell qui exporte les bonnes
variables d'environnement nécessaires à activer les logiciels présents dans
le profil. Il est créé automatiquement par Guix et doit être sourcé. Il
contient les mêmes variables que ce que vous obtiendrez en lançant :

@example
guix package --search-paths=prefix --profile=$my_profile"
@end example

Encore une fois, @xref{Invoquer guix package,,, guix.fr, le manuel de
référence de GNU Guix} pour les options de la ligne de commande.

Pour mettre à jour un profil, installez de nouveau le manifeste :

@example
guix package -m /path/to/guix-my-project-manifest.scm -p "$GUIX_EXTRA_PROFILES"/my-project/my-project
@end example

Pour mettre à jour tous les profils, vous pouvez simplement les
énumérer. Par exemple, en supposant que vous spécifications sont dans
@file{~/.guix-manifests/guix-$profile-manifest.scm}, où @samp{$profile} est
le nom du profil (p.@: ex@: « projet1 »), vous pouvez utiliser ce qui suit
dans le shell :

@example
for profile in "$GUIX_EXTRA_PROFILES"/*; do
  guix package --profile="$profile" --manifest="$HOME/.guix-manifests/guix-$profile-manifest.scm"
done
@end example

Chaque profil a ses propres générations :

@example
guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --list-generations
@end example

Vous pouvez revenir à n'importe quelle génération d'un profil donné :

@example
guix package -p "$GUIX_EXTRA_PROFILES"/my-project/my-project --switch-generations=17
@end example

Enfin, si vous voulez passer à un profil sans hériter l'environnement
actuel, vous pouvez l'activer dans un shell vide :

@example
env -i $(which bash) --login --noprofile --norc
. my-project/etc/profile
@end example

@node Paquets requis
@subsection Paquets requis

Activer un profil consiste en substance à exporter un ensemble de variables
d'environnement. C'est le rôle de @samp{etc/profile} dans le profil.

@emph{Remarque : seules les variables d'environnement des paquets qui les
utilisent seront modifiées.}

Par exemple, @samp{MANPATH} ne sera pas modifié s'il n'y a pas d'application
qui utilise les pages de manuel dans le profil. Donc si vous voulez pouvoir
accéder aux pages de manuel facilement une fois le profil chargé, vous avez
deux possibilités :

@itemize
@item
Exporter la variable manuellement, p.@: ex@:
@example
export MANPATH=/path/to/profile$@{MANPATH:+:@}$MANPATH
@end example

@item
Inclure @samp{man-db} dans le manifeste du profil.
@end itemize

Il en va de même pour @samp{INFOPATH} (vous pouvez installer
@samp{info-reader}), @samp{PKG_CONFIG_PATH} (installer @samp{pkg-config}),
etc.

@node Profil par défaut
@subsection Profil par défaut

Que faire du profil par défaut que Guix garder dans @file{~/.guix-profile} ?

Vous pouvez lui assigner le rôle que vous souhaitez. Habituellement, vous y
installerez un manifeste des paquets que vous voulez pouvoir utiliser dans
toutes les situations.

Autrement, vous pouvez en faire un profil sans manifeste pour des paquets
sans importance que vous voulez juste garder quelques jours. C'est une
manière de pouvoir facilement lancer

@example
guix install package-foo
guix upgrade package-bar
@end example

sans avoir à spécifier un profil.

@node Les avantages des manifestes
@subsection Les avantages des manifestes

Les manifestes sont pratiques pour garder la liste des paquets et, par
exemple, les synchroniser entre plusieurs machines avec un système de
gestion de versions.

Les gens se plaignent souvent que les manifestes sont lents à installer
quand ils contiennent beaucoup de paquets. C'est particulièrement embêtant
quand vous voulez juste mettre à jour un paquet dans un gros manifeste.

C'est une raison de plus d'utiliser plusieurs profils, qui sont bien
pratiques pour diviser les manifestes en plusieurs ensembles de paquets de
même type. Plusieurs petits profils sont plus flexibles et plus maniables.

Les manifestes ont de nombreux avantages. En particulier, ils facilitent la
maintenance :

@itemize
@item
Lorsqu'un profil est créé à partir d'un manifeste, le manifeste lui-même est
suffisant pour garder la liste des paquets sous le coude et réinstaller le
profil plus tard sur un autre système. Pour les profils ad-hoc, il faudrait
générer une spécification de manifeste à la main et noter les versions de
paquets pour les paquets qui n'utilisent pas la version par défaut.

@item
@code{guix package --upgrade} essaye toujours de mettre à jour les paquets
qui ont des entrées propagées, même s'il n'y à rien à faire. Les manifestes
de Guix résolvent ce problème.

@item
Lorsque vous mettez partiellement à jour un profil, des conflits peuvent
survenir (à cause des dépendances différentes entre les paquets à jour et
ceux qui ne le sont pas) et ça peut être embêtant à corriger à la main. Les
manifestes suppriment ce problème puisque tous les paquets sont toujours mis
à jour en même temps.

@item
Comme on l'a mentionné plus haut, les manifestes permettent d'avoir des
profils reproductibles, alors que les commandes impératives @code{guix
install}, @code{guix upgrade}, etc, ne le peuvent pas, puisqu'elles
produisent un profil différent à chaque fois qu'elles sont lancées, même
avec les même paquets. Voir @uref{https://issues.guix.gnu.org/issue/33285,
la discussion sur ce problème}.

@item
Les spécifications de manifestes sont utilisables par les autres commandes
@samp{guix}. Par exemple, vous pouvez lancer @code{guix weather -m manifest}
pour voir combien de substituts sont disponibles, ce qui peut vous aider à
décider si vous voulez faire la mise à jour maintenant ou un peu plus
tard. Un autre exemple : vous pouvez lancer @code{guix package -m
manifest.scm} pour créer un lot contenant tous les paquets du manifeste (et
leurs références transitives).

@item
Enfin, les manifestes ont une représentation Scheme, le type
d'enregistrement @samp{<manifest>}. Vous pouvez les manipuler en Scheme et
les passer aux diverses @uref{https://fr.wikipedia.org/wiki/Api, API} de
Guix.
@end itemize

Vous devez bien comprendre que même si vous pouvez utiliser les manifestes
pour déclarer des profils, les deux ne sont pas strictement équivalents :
les profils pour l'effet de bord « d'épingler » les paquets dans le dépôt,
ce qui évite qu'ils ne soient nettoyés (@pxref{Invoquer guix gc,,, guix.fr,
le manuel de référence de GNU Guix}) et s'assure qu'ils seront toujours
disponibles à n'importe quel moment dans le futur.

Voyons un exemple :

@enumerate
@item
Vous avez un environnement pour bidouiller un projet pour lequel il n'y a
pas encore de paquet Guix. Vous construisez l'environnement avec un
manifeste puis lancez @code{guix environment -m manifest.scm}. Jusqu'ici
tout va bien.

@item
Plusieurs semaines plus tard vous avez lancé quelques @code{guix pull} entre
temps. Plusieurs dépendances du manifeste ont été mises à jour ; ou bien
vous avez lancé @code{guix gc} et certains paquets requis par le manifeste
ont été nettoyés.

@item
Finalement, vous vous remettez au travail sur ce projet, donc vous lancez
@code{guix shell -m manifest.scm}. Mais maintenant vous devez attendre que
Guix construise et installe des paquets !
@end enumerate

Idéalement, vous voudriez éviter de perdre du temps à reconstruire. C'est en
fait possible, tout ce dont on a besoin, c'est d'installer le manifeste dans
un profil et d'utiliser @code{GUIX_PROFILE=/le/profil;
. "$GUIX_PROFILE"/etc/profile} comme on l'a expliqué plus haut : cela
garantie que l'environnement de bidouillage sera toujours disponible.

@emph{Avertissement de sécurité :} bien que garder d'anciens profils soit
pratique, gardez à l'esprit que les anciens paquets n'ont pas forcément reçu
les dernières corrections de sécurité.

@node Profils reproductibles
@subsection Profils reproductibles

Pour reproduire un profil bit-à-bit, on a besoin de deux informations :

@itemize
@item
un manifeste,
@item
et une spécification de canaux Guix.
@end itemize

En effet, les manifestes seuls ne sont pas forcément suffisants :
différentes versions de Guix (ou différents canaux) peuvent produire des
sorties différentes avec le même manifeste.

Vous pouvez afficher la spécification de canaux Guix avec @samp{guix
describe --format=channels}. Enregistrez-la dans un fichier, par exemple
@samp{channel-specs.scm}.

Sur un autre ordinateur, vous pouvez utiliser le fichier de spécification de
canaux et le manifeste pour reproduire exactement le même profil :

@example
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
GUIX_EXTRA=$HOME/.guix-extra

mkdir -p "$GUIX_EXTRA"/my-project
guix pull --channels=channel-specs.scm --profile="$GUIX_EXTRA/my-project/guix"

mkdir -p "$GUIX_EXTRA_PROFILES/my-project"
"$GUIX_EXTRA"/my-project/guix/bin/guix package --manifest=/path/to/guix-my-project-manifest.scm --profile="$GUIX_EXTRA_PROFILES"/my-project/my-project
@end example

Vous pouvez supprimer le profil des canaux Guix que vous venez d'installer
avec la spécification de canaux, le profil du projet n'en dépend pas.

@c *********************************************************************
@node Gestion de l'environnement
@chapter Gestion de l'environnement

Guix fournit plusieurs outils pour gérer l'environnement. Ce chapitre vous
montre ces outils.

@menu
* Environnement Guix avec direnv::  Créer un environnement Guix avec direnv
@end menu

@node Environnement Guix avec direnv
@section Environnement Guix avec direnv

Guix fournit un paquet @samp{direnv}, qui peut étendre le shell après avoir
changé de répertoire de travail. Vous pouvez utiliser cet outil pour
préparer un environnement Guix pur.

L'exemple suivant fournit une fonction shell dans @file{~/.direnvrc}, qui
peut être utilisée dans le dépôt Git de Guix dans @file{~/src/guix/.envrc}
pour créer un environnement de construction similaire à celui décrit dans
@ref{Construire depuis Git,,, guix.fr, le manuel de référence de GNU Guix}.

Créez un fichier @file{~/.direnv} avec le code Bash suivant :

@example
# Grâce à <https://github.com/direnv/direnv/issues/73#issuecomment-152284914>
export_function()
@{
  local name=$1
  local alias_dir=$PWD/.direnv/aliases
  mkdir -p "$alias_dir"
  PATH_add "$alias_dir"
  local target="$alias_dir/$name"
  if declare -f "$name" >/dev/null; then
    echo "#!$SHELL" > "$target"
    declare -f "$name" >> "$target" 2>/dev/null
    # Remarquez qu'on ajoute des variables shells au déclencheur de la fonction.
    echo "$name \$*" >> "$target"
    chmod +x "$target"
  fi
@}

use_guix()
@{
    # indique un jeton Github.
    export GUIX_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

    # Nettoie « GUIX_PACKAGE_PATH ».
    export GUIX_PACKAGE_PATH=""

    # Recrée une racine du ramasse miettes.
    gcroots="$HOME/.config/guix/gcroots"
    mkdir -p "$gcroots"
    gcroot="$gcroots/guix"
    if [ -L "$gcroot" ]
    then
        rm -v "$gcroot"
    fi

    # Divers paquets.
    PACKAGES_MAINTENANCE=(
        direnv
        git
        git:send-email
        git-cal
        gnupg
        guile-colorized
        guile-readline
        less
        ncurses
        openssh
        xdot
    )

    # Paquets de l'environnement.
    PACKAGES=(help2man guile-sqlite3 guile-gcrypt)

    # Grâce à <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html>
    eval "$(guix environment --search-paths --root="$gcroot" --pure guix --ad-hoc $@{PACKAGES[@@]@} $@{PACKAGES_MAINTENANCE[@@]@} "$@@")"

    # Défini les drapeaux configure à l'avance.
    configure()
    @{
        ./configure --localstatedir=/var --prefix=
    @}
    export_function configure

    # Lance make et construit éventuellement quelque chose.
    build()
    @{
        make -j 2
        if [ $# -gt 0 ]
        then
            ./pre-inst-env guix build "$@@"
        fi
    @}
    export_function build

    # Défini une commande Git pour pousser.
    push()
    @{
        git push --set-upstream origin
    @}
    export_function push

    clear                        # Nettoie l'écran.
    git-cal --author='Votre Nom' # Montre le calendrier des contributions.

    # Montre l'aide des commandes.
    echo "
build          construit un paquet ou juste un projet si aucun argument n'est fournit
configure      lance ./configure avec les paramètres pré-définis
push           pousse un dépôt Git
"
@}
@end example

Tous les projets contenant un @file{.envrc} avec une chaine @code{use guix}
aura des variables d'environnement et des procédures prédéfinies.

Lancez @command{direnv allow} pour mettre en place l'environnement pour la
première fois.

@c *********************************************************************
@node Remerciements
@chapter Remerciements

Guix se base sur le @uref{https://nixos.org/nix/ gestionnaire de paquets
Nix} conçu et implémenté par Eelco Dolstra, avec des contributions d'autres
personnes (voir le fichier @file{nix/AUTHORS} dans Guix).  Nix a inventé la
gestion de paquet fonctionnelle et promu des fonctionnalités sans précédents
comme les mises à jour de paquets transactionnelles et les retours en
arrière, les profils par utilisateurs et les processus de constructions
transparents pour les références.  Sans ce travail, Guix n'existerait pas.

Les distributions logicielles basées sur Nix, Nixpkgs et NixOS, ont aussi
été une inspiration pour Guix.

GNU@tie{}Guix lui-même est un travail collectif avec des contributions d'un
grand nombre de personnes.  Voyez le fichier @file{AUTHORS} dans Guix pour
plus d'information sur ces personnes de qualité.  Le fichier @file{THANKS}
liste les personnes qui ont aidé en rapportant des bogues, en prenant soin
de l'infrastructure, en fournissant des images et des thèmes, en faisant des
suggestions et bien plus. Merci !

Ce document contient des sections adaptées d'articles précédemment publiés
sur le blog de Guix sur @uref{https://guix.gnu.org/blog}.


@c *********************************************************************
@node La licence GNU Free Documentation
@appendix La licence GNU Free Documentation
@cindex licence, GNU Free Documentation License
@include fdl-1.3.texi

@c *********************************************************************
@node Index des concepts
@unnumbered Index des concepts
@printindex cp

@bye

@c Local Variables:
@c ispell-local-dictionary: "american";
@c End:
