Suivant: Chemins de recherche, Précédent: Phases de construction, Monter: Interface de programmation [Table des matières][Index]
Dès que vous commencerez à écrire des définitions de paquets non triviales
(voir Définition des paquets) ou d’autres actions de compilation
(voir G-Expressions), vous commencerez probablement à chercher des
fonctions auxiliaires pour les actions « de type shell » — créer des
répertoires, copier et supprimer des fichiers de manière récursive,
manipuler les phases de compilation, etc. Le module (guix build
utils)
fournit de telles procédures utilitaires.
La plupart des systèmes de construction chargent (guix build utils)
(voir Systèmes de construction). Ainsi, lorsque vous écrivez des phases de
construction personnalisées pour vos définitions de paquets, vous pouvez
généralement supposer que ces procédures sont disponibles.
Lorsque vous écrivez des G-expressions, vous pouvez importer (guix
build utils)
« côté construction » en utilisant
with-imported-modules
et ensuite le rendre disponible avec la forme
use-modules
(voir Using Guile Modules dans GNU Guile Reference
Manual) :
(with-imported-modules '((guix build utils)) ;on l'importe
(computed-file "empty-tree"
#~(begin
;; On le rend disponible.
(use-modules (guix build utils))
;; On utilise sa procédure « mkdir-p » sans souci.
(mkdir-p (string-append #$output "/a/b/c")))))
Le reste de cette section est la référence pour la plupart des procédures
auxiliaires fournies par (guix build utils)
.
Cette section documente les procédures de traitement des noms de fichier du dépôt.
Renvoie le nom de répertoire du dépôt.
Renvoie vrai si fichier est dans le dépôt.
Enlevez le /gnu/store et le hash de fichier, un nom de fichier
du dépôt. Le résultat est généralement une chaîne
"paquet-version"
.
Si l’on passe nom, un nom de paquet comme "toto-0.9.1b"
, on
obtient deux valeurs : "toto"
et "0.9.1b"
. Lorsque la partie
version est indisponible, nom et #f
sont renvoyés. Le premier
trait d’union suivi d’un chiffre est considéré comme introduisant la partie
version.
Les procédures ci-dessous portent sur les fichiers et les types de fichiers.
Renvoie #t
si dir existe et est un répertoire.
Renvoie #t
si fichier existe et est exécutable.
Renvoie #t
si fichier est un lien symbolique (un « symlink »).
Renvoie #t
si fichier est, respectivement, un fichier ELF, une
archive ar
(telle qu’une bibliothèque statique .a), ou un
fichier gzip.
Si fichier est un fichier gzip, réinitialise son horodatage intégré
(comme avec gzip --no-name
) et renvoie vrai. Sinon, renvoie
#f
. Lorsque keep-mtime? est vrai, conserve la date de
modification de fichier.
Les procédures et macros suivantes permettent de créer, modifier et
supprimer des fichiers. Elles offrent des fonctionnalités comparables à
celles des utilitaires shell courants tels que mkdir -p
,
cp -r
, rm -r
et sed
. Elles complètent
l’interface de système de fichiers étendue, mais de bas niveau, de Guile
(voir POSIX dans GNU Guile Reference Manual).
Exécute corps avec répertoire comme répertoire actuel du processus.
En gros, cette macro change le répertoire actuel en répertoire avant
d’évaluer corps, en utilisant chdir
. (voir Processus dans Manuel de référence de GNU Guile). Elle revient au répertoire
initial à la sortie de la portée dynamique de corps, qu’il s’agisse
d’un retour de procédure normal ou d’une sortie non locale telle qu’une
exception.
Crée le répertoire dir et tous ses ancètres.
Crée répertoire s’il n’existe pas et y copie fichier sous le même nom.
Rend fichier inscriptible pour son propriétaire.
copy-file] [#:keep-mtime? #f] [#:keep-permissions? #t] [#:select? (const
#t)] Copy source directory to destination. Follow symlinks if
follow-symlinks? is true; otherwise, just preserve them. Call
copy-file to copy regular files. Call select?, taking two
arguments, file and stat, for each entry in source, where
file is the entry’s absolute file name and stat is the result of
lstat
(or stat
if follow-symlinks? is true); exclude
entries for which select? does not return true. When
keep-mtime? is true, keep the modification time of the files in
source on those of destination. When keep-permissions? is
true, preserve file permissions. Write verbose output to the log
port.
Efface récursivement dir, comme rm -rf
, sans suivre les
liens symboliques. Ne suit pas non plus les points de montage, à moins que
follow-mounts? ne soit vrai. Rapporte mais ignore les erreurs.
fichier par la chaîne renvoyée par body. body est évalué avec chaque match-var lié à la sous-expression de regexp positionnelle correspondante. Par exemple :
(substitute* file
(("hello")
"good morning\n")
(("toto([a-z]+)titi(.*)$" all letters end)
(string-append "tata" letters end)))
Ici, chaque fois qu’une ligne de fichier contient hello
, elle
est remplacée par good morning
. Chaque fois qu’une ligne de
fichier correspond à la deuxième regexp, all
est lié à la
correspondance complète, letters
est lié à la première
sous-expression, et end
est lié à la dernière.
Lorsque l’une des match-var est _
, aucune variable n’est liée à
la sous-chaîne de correspondance associée.
Autrement, fichier peut être une liste de noms de fichier, auquel cas ils sont tous sujets aux substitutions.
Be careful about using $
to match the end of a line; by itself it
won’t match the terminating newline of a line. For example, to match a
whole line ending with a backslash, one needs a regex like
"(.*)\\\\\n$"
.
Cette section documente les procédures pour chercher et filtrer des fichiers.
Renvoie un prédicat qui devient vrai lorsqu’on lui passe un nom de fichier dont le nom de base correspond à regexp.
Renvoie la liste des fichiers triés lexicographiquement sous dir pour
lesquels pred renvoie « vrai ». Deux arguments sont passés à
pred : le nom absolu du fichier et son tampon stat ; le prédicat par
défaut renvoie toujours « vrai ». pred peut également être une
expression régulière, auquel cas elle est équivalente à
(file-name-predicate pred)
. stat est utilisé pour
obtenir des informations sur les fichiers ; l’utilisation de lstat
signifie que les liens symboliques ne sont pas suivis. Si
directories? est vrai, alors les répertoires seront également inclus.
Si fail-on-error? est vrai, il lance une exception en cas d’erreur.
Voici quelques exemples où nous supposons que le répertoire actuel est la racine de l’arborescence des sources de Guix :
;; Liste tous les fichiers normaux dans le répertoire actuel. (find-files ".") ⇒ ("./.dir-locals.el" "./.gitignore" …) ;; Liste tous les fichiers .scm sous gnu/services. (find-files "gnu/services" "\\.scm$") ⇒ ("gnu/services/admin.scm" "gnu/services/audio.scm" …) ;; Liste les fichiers ar dans le répertoire actuel. (find-files "." (lambda (file stat) (ar-file? file))) ⇒ ("./libformat.a" "./libstore.a" …)
Renvoie le nom complet du fichier pour programme tel qu’il se trouve
dans $PATH
, ou #f
si programme n’a pas pu être trouvé.
Renvoie le nom de fichier complet de nom trouvé dans entrées ;
search-input-file
recherche les fichiers normaux et
search-input-directory
recherche les dossiers. Si nom n’est pas
trouvé, une exception est levée.
Ici, entrées doit être une liste d’association comme les variables
inputs
et native-inputs
disponibles dans les phases de
construction (voir Phases de construction).
Voici un exemple (simplifié) d’utilisation de search-input-file
dans
une phase de construction du paquet wireguard-tools
:
(add-after 'install 'wrap-wg-quick
(lambda* (#:key inputs outputs #:allow-other-keys)
(let ((coreutils (string-append (assoc-ref inputs "coreutils")
"/bin")))
(wrap-program (search-input-file outputs "bin/wg-quick")
#:sh (search-input-file inputs "bin/bash")
`("PATH" ":" prefix ,(list coreutils))))))
Vous trouverez des procédures pratiques pour invoquer des processus dans ce
module, en particulier des enveloppes pratiques autour de system*
de
Guile (voir system*
dans le manuel de référence de
Guile).
Invoque le programme avec les args donnés. Lève une exception
&invoke-error
si le code de retour n’est pas zéro ; sinon renvoie
#t
.
L’avantage par rapport à system*
c’est que vous n’avez pas besoin de
vérifier la valeur de sortie. Cela réduit le code dans les petits scripts
comme par exemple dans les phases de construction des paquets.
Renvoie vrai si c est une condition &invoke-error
.
Accède aux champs de c, une condition &invoke-error
.
Rapporte c, une condition &invoke-error
, sur port (par
défaut le port d’erreur actuel), dans un format humainement lisible.
L’utilisation habituelle ressemblerait à ceci :
(use-modules (srfi srfi-34) ;pour « guard » (guix build utils)) (guard (c ((invoke-error? c) (report-invoke-error c))) (invoke "date" "--option-imaginaire")) -| command "date" "--option-imaginaire" failed with status 1
Invoque programme avec args et capture la sortie standard et
l’erreur standard de programme. Si programme termine sans
erreur, n’affiche rien et renvoie la valeur non spécifiée ; sinon, lève une
condition d’erreur &message
qui inclut le code de statut et la sortie
de programme.
Voici un exemple :
(use-modules (srfi srfi-34) ;pour « guard » (srfi srfi-35) ;pour « message-condition? » (guix build utils)) (guard (c ((message-condition? c) (display (condition-message c)))) (invoke/quiet "date") ; tout va bien (invoke/quiet "date" "--imaginary-option")) -| 'date --imaginary-option' exited with status 1; output follows: date : option non reconnue '--imaginary-option' Saisissez « date --help » pour plus d'informations.
Le (guix build utils)
contient également des outils permettant de
manipuler les phases de construction telles qu’elles sont utilisées par les
systèmes de construction (voir Systèmes de construction). Les phases de
construction sont représentées sous forme de listes d’associations ou «
alists » (voir Association Lists dans Manuel de référence de GNU
Guile) où chaque clé est un symbole désignant la phase et où la valeur
associée est une procédure (voir Phases de construction).
Le noyau Guile et le module (srfi srfi-1)
fournissent tous deux des
outils pour manipuler les alignements. Le module (guix build utils)
complète ces outils avec des outils écrits en tenant compte des phases de
construction.
Modifie phases séquentiellement selon chaque clause, qui peut avoir l’une des formes suivantes :
(delete old-phase-name) (replace old-phase-name new-phase) (add-before old-phase-name new-phase-name new-phase) (add-after old-phase-name new-phase-name new-phase)
Où chaque phase-name ci-dessus est une expression s’évaluant en un symbole, et new-phase une expression évaluant à une procédure.
L’exemple ci-dessous est tiré de la définition du paquet grep
. Il
ajoute une phase à exécuter après la phase install
, appelée
fix-egrep-and-fgrep
. Cette phase est une procédure (lambda*
pour les procédures anonymes) qui prend un paramètre nommé #:outputs
et ignore les paramètres nommés supplémentaires (voir Optional
Arguments dans GNU Guile Reference Manual, pour en savoir plus sur
lambda*
et les arguments optionnels et nommés). La phase utilise
substitute*
pour modifier les scripts egrep et fgrep
installés afin qu’ils se réfèrent à grep
par son nom de fichier
absolu :
(modify-phases %standard-phases
(add-after 'install 'fix-egrep-and-fgrep
;; Corrige « egrep » et « fgrep » pour exécuter « grep » via son
;; nom de fichier absolu au lieu de le chercher dans $PATH.
(lambda* (#:key outputs #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
(bin (string-append out "/bin")))
(substitute* (list (string-append bin "/egrep")
(string-append bin "/fgrep"))
(("^exec grep")
(string-append "exec " bin "/grep")))))))
Dans l’exemple ci-dessous, les phases sont modifiées de deux façons : la
phase standard configure
est supprimée, vraisemblablement parce que
le paquet n’a pas de script configure ou quelque chose de similaire,
et la phase par défaut install
est remplacée par une phase qui copie
manuellement les fichiers exécutables à installer :
(modify-phases %standard-phases
(delete 'configure) ;pas de script « configure »
(replace 'install
(lambda* (#:key outputs #:allow-other-keys)
;; Le Makefile du paquet ne fournit pas de règle « install »
;; alors on le fait nous-mêmes.
(let ((bin (string-append (assoc-ref outputs "out")
"/bin")))
(install-file "footswitch" bin)
(install-file "scythe" bin)))))
Il est courant qu’une commande ait besoin que certaines variables d’environnement soient initialisées pour fonctionner correctement, souvent des chemins de recherche (voir Chemins de recherche). Sans cela, la commande peut échouer à trouver les fichiers et les autres commandes dont elle a besoin, ou elle pourrait trouver la « mauvaise » dépendance — en dépendant de l’environnement sur lequel elle tourne. Voici quelques exemples :
PATH
;
GUILE_LOAD_PATH
et GUILE_LOAD_COMPILED_PATH
;
QT_PLUGIN_PATH
.
Pour l’auteur ou l’autrice d’un paquet, le but est de s’assurer que les
commandes fonctionnent toujours pareil plutôt que de dépendre de paramètres
externes. Une manière d’y arriver est d’envelopper les commandes dans
un petit script qui défini ces variables d’environnement, ce qui assure que
ces dépendances à l’exécution seront trouvées. L’enveloppe serait utilisée
pour initialiser PATH
, GUILE_LOAD_PATH
ou QT_PLUGIN_PATH
dans les exemple ci-dessus.
Pour faciliter cette tâche, le module (guix build utils)
fournit
quelques fonctions auxiliaires pour envelopper des commandes.
Crée une enveloppe pour programme. variables doit ressembler à ceci :
'(variable délimiteur position liste-de-répertoires)
où délimiteur est facultatif. :
sera utilisé si
délimiteur n’est pas fourni.
Par exemple, cet appel :
(wrap-program "toto"
'("PATH" ":" = ("/gnu/.../titi/bin"))
'("CERT_PATH" suffix ("/gnu/.../tata/certs"
"/qux/certs")))
copiera toto dans .toto-real et créera le fichier toto avec le contenu suivant :
#!emplacement/de/bin/bash export PATH="/gnu/.../titi/bin" export CERT_PATH="$CERT_PATH${CERT_PATH:+:}/gnu/.../tata/certs:/qux/certs" exec -a $0 emplacement/de/.foo-real "$@"
Si programme a déjà été enveloppé par wrap-program
, l’enveloppe
est agrandie avec les définitions de variables. Sinon, sh sera
utilisé comme interpréteur.
Enveloppe le script programme pour que variables soient définie
avant. Le format de variables est le même que pour la procédure
wrap-program
. Cette procédure est différente de wrap-program
car elle ne crée pas de script shell séparé. Au lieu de cela, program
est modifié directement en ajoutant un script Guile au début, qui est
interprété comme un commentaire par le langage de script.
Les commentaires à l’encodage spécifique pris en charge par Python sont recréés sur la seconde ligne.
Remarquez que cette procédure ne peut être utilisée qu’une seule fois par fichier car les scripts Guile ne sont pas pris en charge.
Suivant: Chemins de recherche, Précédent: Phases de construction, Monter: Interface de programmation [Table des matières][Index]