Précédent: , Monter: Définir des services   [Table des matières][Index]


12.18.5 Configurations complexes

Certains programmes peuvent avoir des fichiers ou des formats de configuration complexes, et pour rendre plus simple la création de liaisons Scheme pour ces fichiers de configuration, vous pouvez utiliser les fonction auxiliaires définies dans le modules (gnu services configuration).

L’utilitaire principal est la macro define-configuration, que vous utiliserez pour définir un type d’enregistrement Scheme (voir Record Overview dans GNU Guile Reference Manual). L’enregistrement Scheme sera sérialisé en un fichier de configuration par des sérialiseurs, qui sont des procédures qui prennent une valeur Scheme et renvoient une G-expression (voir G-Expressions), ce qui devrait, une fois sérialisé sur le disque, renvoyer une chaine. Plus de détails se trouvent plus bas.

Syntaxe Scheme :define-configuration nom clause1 clause2 ...

Crée un type d’enregistrement nommé nom qui contient les champs qui se trouvent dans les clauses.

Une clause peut avoir l’une des formes suivantes :

(nom-du-champ
 (type valeur-par-défaut)
 documentation)
 
(nom-du-champ
 (type valeur-par-défaut)
 documentation
 sérialiseur)

(nom-du-champ
 (type)
 documentation)

(nom-du-champ
 (type)
 documentation
 sérialiseur)

nom-du-champ est un identifiant qui dénote le nom du champ dans l’enregistrement généré.

type est le type de valeur correspondant à nom-du-champ ; comme Guile n’est pas typé, une procédure de prédicat — type? — sera appelée avec la valeur correspondant au champ pour s’assurer que la valeur est du type correct. Cela signifie que si type est package, alors une procédure nommée package? sera appliquée sur la valeur pour s’assurer que c’est bien un objet <package>.

valeur-par-défaut est la valeur par défaut correspondant au champ ; si aucune n’est spécifiée, l’utilisateur ou l’utilisatrice doit fournir une valeur à la création d’un objet de ce type d’enregistrement.

documentation est une chaine formatée avec la syntaxe de Texinfo qui fournit une description de ce que ce champ de configuration signifie.

sérialiseur est le nom d’une procédure qui prend deux arguments, le premier est le nom du champ, et le second est la valeur correspondant au champ. La procédure devrait renvoyer une chaine ou une G-expression (voir G-Expressions) qui représente le contenu qui sera sérialisé dans le fichier de configuration. Si aucun n’est spécifié, une procédure nommée serialize-type sera utilisée.

Une simple procédure de sérialisation pourrait ressembler à ceci :

(define (serialize-boolean field-name value)
  (let ((value (if value "true" "false")))
    #~(string-append #$field-name #$value)))

Dans certains cas plusieurs enregistrements de configuration différents peuvent être définis dans le même fichier, mais leurs sérialiseurs pour le même type peuvent devoir être différents, à cause de formats de configuration différents. Par exemple, la procédure serialize-boolean pour le service Getmail doit être différente de celle pour le service Transmission. Pour faciliter cette situation, on peut spécifier un préfixe pour sérialiseur en utilisant le littéral prefix dans la forme define-configuration. Cela signifie qu’on n’a pas à spécifier manuellement un sérialiseur personnalisé pour chaque champ.

(define (toto-serialize-string field-name value)
  )

(define (titi-serialize-string field-name value)
  )
  
(define-configuration toto-configuration
  (label
   (string)
   "Le nom de l'étiquette.")
  (prefix toto-))

(define-configuration titi-configuration
  (ip-address
   (string)
   "L'adresse IPv4 de cet appareil.")
  (prefix titi-))

Cependant, dans certains cas vous ne voudrez pas sérialiser les valeurs de l’enregistrement. Pour cela, vous pouvez utiliser le littéral no-serialization. Il y a aussi la macro define-configuration/no-serialization qui est un raccourci.

;; Rien ne sera sérialisé sur le disque.
(define-configuration toto-configuration
  (field
   (string "test")
   "De la documentation.")
  (no-serialization))

;; Comme au-dessus.
(define-configuration/no-serialization titi-configuration
  (field
   (string "test")
   "De la documentation."))
Syntaxe Scheme :define-maybe type

Parfois un champ ne devrait pas être sérialisé si l’utilisateur ou l’utilisatrice de spécifie par de valeur. Pour cela, vous pouvez utiliser la macro define-maybe pour définir un « type peut-être » ; si la valeur d’un type peut-être n’est pas spécifiée, ou est indiquée à %unset-value, elle n’est pas sérialisée.

Lorsque vous définissez un « type peut-être », le sérialiseur correspondant au type normal sera utilisé par défaut. Par exemple, un champ de type maybe-string sera sérialisé avec la procédure serialize-string par défaut, vous pouvez évidemment changer cela en spécifiant une procédure de sérialisation personnalisée. De la même manière, le type de la valeur doit être une chaine, ou la valeur doit rester non spécifiée.

(define-maybe string)

(define (serialize-string field-name value)
  )

(define-configuration tata-configuration
  (name
   ;; Si c'est une chaine, la procédure « serialize-string » sera utilisée
   ;; pour sérialiser la chaine.  Sinon ce champ n'est pas sérialisé
   maybe-string
   "Le nom de ce module."))

Comme avec define-configuration, on peut indiquer un préfixe pour le nom de sérialiseur en utilisant le littéral prefix.

(define-maybe integer
  (prefix tata-))

(define (tata-serialize-integer field-name value)
  )

Il y a aussi le littéral no-serialization, qui s’il est utilisé indique qu’aucun sérialiseur ne sera défini pour le « type peut-être », indépendamment de si la valeur est indiquée ou non. define-maybe/no-serialization est un raccourci pour spécifier le littéral no-serialization.

(define-maybe/no-serialization symbol)

(define-configuration/no-serialization test-configuration
  (mode
   maybe-symbol
   "Docstring."))
Procédure Scheme :maybe-value-set? valeur

Prédicat pour vérifier si l’utilisateur ou l’utilisatrice a spécifié la valeur d’un champ peut-être.

Procédure Scheme :serialize-configuration configuration champs

Renvoie une G-expression qui contient les valeurs correspondant aux champs de configuration, un enregistrement qui a été généré par define-configuration. La G-expression peut ensuite être sérialisée vers le disque en utilisant par exemple mixed-text-file.

Procédure Scheme :empty-serializer champ-de-nom valeur

Un sérialiseur qui renvoie juste une chaine vide. La procédure serialize-package est un alias pour cette procédure.

Une fois que vous avez défini un enregistrement de configuration, vous voudrez aussi sans doute le documenter pour que d’autres personnes sachent comment l’utiliser. Pour vous aider, il y a deux procédure qui sont documentées plus bas.

Procédure Scheme :generate-documentation documentation documentation-name

Génère un fragment Texinfo à partir de docstrings dans documentation, une liste de (étiquette champs sous-documentation …). étiquette devrait être un symbole et devrait être le nom de l’enregistrement de configuration. champs devrait être une liste de tous les champs disponibles pour l’enregistrement de configuration.

sous-documentation est un tuple (nom-de-champ nom-de-configuration). nom-de-champ est le nom du champ qui prend un autre enregistrement de configuration comme valeur, et nom-de-configuration est le nom de cet enregistrement de configuration.

sous-documentation n’est requis que s’il y a des enregistrements de configuration imbriqués. Par exemple, l’enregistrement getmail-configuration (voir Services de courriels) accepte un enregistrement getmail-configuration-file dans l’un de ses champs rcfile, donc la documentation de getmail-configuration-file est imbriquée dans getmail-configuration.

(generate-documentation
  `((getmail-configuration ,getmail-configuration-fields
     (rcfile getmail-configuration-file))
    )
  'getmail-configuration)

nom-de-documentation devrait être un symbole et devrait être le nom de l’enregistrement de configuration.

Procédure Scheme :configuration->documentation

configuration-symbol Prend configuration-symbol, le symbole correspondant au nom utilisé pour définir un enregistrement de configuration avec define-configuration, et affiche la documentation Texinfo pour ses champs. Cette procédure est utile s’il n’y a pas d’enregistrement de configuration imbriqué car elle n’affiche que la documentation des champs de plus haut niveau.

Actuellement, il n’y a pas de manière automatique de générer la documentation pour les enregistrements de configuration et les ajouter au manuel. Au lieu de cela, chaque fois que vous faites un changement dans les docstrings d’un enregistrement de configuration, vous devez appeler manuellement generate-documentation ou configuration->documentation et coller la sortie dans le fichier doc/guix.texi.

Ci-dessous se trouve un exemple d’un type d’enregistrement créé avec define-configuration et compagnie.

(use-modules (gnu services)
             (guix gexp)
             (gnu services configuration)
             (srfi srfi-26)
             (srfi srfi-1))

;; Transforme les noms de champs, qui sont des symboles Scheme, en chaines
(define (uglify-field-name field-name)
  (let ((str (symbol->string field-name)))
    ;; field? -> is-field
    (if (string-suffix? "?" str)
        (string-append "is-" (string-drop-right str 1))
        str)))

(define (serialize-string field-name value)
  #~(string-append #$(uglify-field-name field-name) " = " #$value "\n"))

(define (serialize-integer field-name value)
  (serialize-string field-name (number->string value)))

(define (serialize-boolean field-name value)
  (serialize-string field-name (if value "true" "false")))

(define (serialize-contact-name field-name value)
  #~(string-append "\n[" #$value "]\n"))

(define (list-of-contact-configurations? lst)
  (every contact-configuration? lst))

(define (serialize-list-of-contact-configurations field-name value)
  #~(string-append #$@(map (cut serialize-configuration <>
                                contact-configuration-fields)
                           value)))

(define (serialize-contacts-list-configuration configuration)
  (mixed-text-file
   "contactrc"
   #~(string-append "[Owner]\n"
                    #$(serialize-configuration
                       configuration contacts-list-configuration-fields))))

(define-maybe integer)
(define-maybe string)

(define-configuration contact-configuration
  (name
   (string)
   "Le nom du contact."
   serialize-contact-name)
  (phone-number
   maybe-integer
   "Le numéro de téléphone de la personne.")
  (email
   maybe-string
   "L'adresse de courriel de la personne.")
  (married?
   (boolean)
   "Indique si la personne est mariée."))

(define-configuration contacts-list-configuration
  (name
   (string)
   "Le nom du propriétaire de cette liste de contacts.")
  (email
   (string)
   "L'adresse de courriel du propriétaire.")
  (contacts
   (list-of-contact-configurations '())
   "Une liste d'enregistrements @code{contact-configuation} qui contiennent
des informations sur tous vos contacts."))

Une configuration de liste de contacts pourrait alors être créée de cette manière :

(define my-contacts
  (contacts-list-configuration
   (name "Alice")
   (email "alice@example.org")
   (contacts
    (list (contact-configuration
           (name "Bob")
           (phone-number 1234)
           (email "bob@gnu.org")
           (married? #f))
          (contact-configuration
           (name "Charlie")
           (phone-number 0000)
           (married? #t))))))

Après la sérialisation de la configuration sur le disque, le fichier qui en résulte ressemble à ceci :

[owner]
name = Alice
email = alice@example.org

[Bob]
phone-number = 1234
email = bob@gnu.org
is-married = false

[Charlie]
phone-number = 0
is-married = true

Précédent: Services Shepherd, Monter: Définir des services   [Table des matières][Index]