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


11.19.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).

The main utility is the define-configuration macro, a helper used to define a Scheme record type (voir Record Overview dans GNU Guile Reference Manual). The fields from this Scheme record can be serialized using serializers, which are procedures that take some kind of Scheme value and translates them into another Scheme value or G-Expressions.

Macro :define-configuration nom clause1 clause2 …

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

A clause has the following form:

(field-name
 type-decl
 documentation
 option*
 …)

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

type-decl is either type for fields that require a value to be set or (type default-value) otherwise.

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.

option* is one of the following subclauses:

empty-serializer

Exclude this field from serialization.

(serializer serializer)

serializer is the name of a procedure which takes two arguments, the first is the name of the field, and the second is the value corresponding to the field. The procedure should return a string or G-Expressions that represents the content that will be serialized to the configuration file. If none is specified, a procedure of the name serialize-type will be used.

An example of a simple serializer procedure:

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

sanitizer is a procedure which takes one argument, a user-supplied value, and returns a “sanitized” value for the field. If no sanitizer is specified, a default sanitizer is used, which raises an error if the value is not of type type.

An example of a sanitizer for a field that accepts both strings and symbols looks like this:

(define (sanitize-foo value)
  (cond ((string? value) value)
        ((symbol? value) (symbol->string value))
        (else (error "bad 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 foo-configuration
  (label
   string
   "The name of label.")
  (prefix foo-))

(define-configuration bar-configuration
  (ip-address
   string
   "The IPv4 address for this device.")
  (prefix bar-))

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."))
Macro :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 :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 :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.

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 :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.

sub-documentation is a (field-name configuration-name) tuple. field-name is the name of the field which takes another configuration record as its value, and configuration-name is the name of that configuration record. The same value may be used for multiple field-names, in case a field accepts different types of configurations.

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 :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
   "The name of the contact."
   serialize-contact-name)
  (phone-number
   maybe-integer
   "The person's phone number.")
  (email
   maybe-string
   "The person's email address.")
  (married?
   boolean
   "Whether the person is married."))

(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-configuration} 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]