Vorige: Shepherd-Dienste, Nach oben: Dienste definieren [Inhalt][Index]
Einige Programme haben vielleicht ziemlich komplizierte
Konfigurationsdateien oder -formate. Sie können die Hilfsmittel, die in dem
Modul (gnu services configuration)
definiert sind, benutzen, um das
Erstellen von Scheme-Anbindungen für diese Konfigurationsdateien leichter zu
machen.
The main utility is the define-configuration
macro, a helper used to
define a Scheme record type (siehe Record Overview in 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-Ausdrücke.
Einen Verbundstyp mit dem Namen Name
erstellen, der die in den
Klauseln gefundenen Felder enthalten wird.
A clause has the following form:
(field-name type-decl documentation option* …)
Feldname ist ein Bezeichner, der als Name des Feldes im erzeugten Verbund verwendet werden wird.
type-decl is either type
for fields that require a value
to be set or (type default)
otherwise.
Mit Typ wird benannt, was als Typ des Werts für Feldname gelten
soll. Weil Guile typenlos ist, muss es eine entsprechend benannte
Prädikatprozedur Typ?
geben, die auf dem Wert für das Feld
aufgerufen werden wird und prüft, dass der Wert des Feldes den geltenden Typ
hat. Wenn zum Beispiel package
als Typ angegeben wird, wird
eine Prozedur namens package?
auf den für das Feld angegebenen Wert
angewandt werden. Sie muss zurückliefern, ob es sich wirklich um ein
<package>
-Objekt handelt.
Vorgabewert ist der Standardwert für das Feld; wenn keiner festgelegt wird, muss der Benutzer einen Wert angeben, wenn er ein Objekt mit dem Verbundstyp erzeugt.
Dokumentation ist eine Zeichenkette, die mit Texinfo-Syntax formatiert ist. Sie sollte eine Beschreibung des Feldes enthalten.
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-Ausdrücke 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)
Sanitisierer ist eine Prozedur, die ein Argument nimmt, welches vom Dienstbenutzer bestimmt wird, und dafür einen „sanitisierten“ Wert zurückliefert. Wenn kein Sanitisierer angegeben wird, wird ein vorgegebener Sanitisierer verwendet, der einen Fehler meldet, wenn der Wert nicht den als Typ genannten Datentyp hat.
So sieht ein Beispiel aus für einen Sanitisierer eines Feldes, der sowohl Zeichenketten als auch Symbole zulässt:
(define (sanitize-foo value)
(cond ((string? value) value)
((symbol? value) (symbol->string value))
(else (error "bad value"))))
Es kommt vor, dass in derselben Datei mehrere Arten von
Konfigurationsverbund definiert werden, deren Serialisierer sich für
denselben Typ unterscheiden, weil ihre Konfigurationen verschieden
formatiert werden müssen. Zum Beispiel braucht es eine andere
serialize-boolean
-Prozedur für einen Getmail-Dienst als für einen
Transmission-Dienst. Um leichter mit so einer Situation fertig zu werden,
können Sie ein Serialisierer-Präfix nach dem Literal prefix
in der
define-configuration
-Form angeben. Dann müssen Sie den eigenen
Serialisierer nicht für jedes Feld angeben.
(define (foo-serialize-string field-name value) …) (define (bar-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-))
In manchen Fällen wollen Sie vielleicht überhaupt gar keinen Wert aus dem
Verbund serialisieren. Dazu geben Sie das Literal no-serialization
an. Auch können Sie das Makro define-configuration/no-serialization
benutzen, was eine Kurzschreibweise dafür ist.
Manchmal soll ein Feld dann nicht serialisiert werden, wenn der
Benutzer keinen Wert dafür angibt. Um das zu erreichen, können Sie das Makro
define-maybe
benutzen, um einen „maybe type“, zu Deutsch
„Vielleicht-Typ“, zu definieren. Wenn der Wert eines Vielleicht-Typs
nicht gesetzt oder auf den Wert %unset-value
gesetzt ist, wird
er nicht serialisiert.
Beim Definieren eines „Vielleicht-Typs“ ist die Voreinstellung, den dem
Grundtyp entsprechenden Serialisierer zu benutzen. Zum Beispiel wird ein
Feld vom Typ maybe-string
nach Voreinstellung mit der Prozedur
serialize-string
serialisiert. Natürlich können Sie stattdessen eine
eigene Serialisiererprozedur festlegen. Ebenso muss der Wert entweder den
Typ „string“ (also Zeichenkette) aufweisen oder unspezifiziert sein.
(define-maybe string) (define (serialize-string field-name value) …) (define-configuration baz-configuration (name ;; Wenn eine Zeichenkette angegeben wird, wird diese mit der ;; Prozedur „serialize-string“ serialisiert werden. Sonst ;; ist vorgegeben, für dieses Feld nichts zu serialisieren. maybe-string "The name of this module."))
Wie bei define-configuration
kann man ein Präfix für
Serialisierernamen als Literal mit prefix
angeben.
(define-maybe integer (prefix baz-)) (define (baz-serialize-integer field-name value) …)
Auch gibt es das Literal no-serialization
. Wenn es angegeben wird,
bedeutet das, es wird kein Serialisierer für den Vielleicht-Typ eingesetzt,
ganz gleich ob ein Wert gesetzt wurde oder
nicht. define-maybe/no-serialization
ist eine Kurzschreibweise, um
das Literal no-serialization
festzulegen.
(define-maybe/no-serialization symbol) (define-configuration/no-serialization test-configuration (mode maybe-symbol "Docstring."))
Mit diesem Prädikat können Sie ermitteln, ob ein Benutzer für das Vielleicht-Feld einen bestimmten Wert angegeben hat.
Liefert einen G-Ausdruck mit den Werten zu jedem der Felder im
Verbundsobjekt Konfiguration, das mit define-configuration
erzeugt wurde. Der G-Ausdruck kann mit z.B. mixed-text-file
auf die
Platte serialisiert werden.
Nachdem Sie einen Konfigurationsverbundstyp definiert haben, haben Sie bestimmt auch die Absicht, die Dokumentation dafür zu schreiben, um anderen Leuten zu erklären, wie man ihn benutzt. Dabei helfen Ihnen die folgenden zwei Prozeduren, die hier dokumentiert sind.
Ein Stück Texinfo aus den Docstrings in der Dokumentation
erzeugen. Als Dokumentation geben Sie eine Liste aus
(Bezeichnung Felder Unterdokumentation ...)
an. Bezeichnung ist ein Symbol und gibt den Namen des
Konfigurationsverbunds an. Felder ist eine Liste aller Felder des
Konfigurationsverbunds.
Unterdokumentation ist ein Tupel (Feldname
Konfigurationsname)
. Feldname ist der Name des Feldes, das
einen anderen Konfigurationsverbund als Wert hat. Konfigurationsname
ist der Name dessen Konfigurationsverbundstyps.
Eine Unterdokumentation müssen Sie nur angeben, wenn es verschachtelte
Verbundstypen gibt. Zum Beispiel braucht ein Verbundsobjekt
getmail-configuration
(siehe Mail-Dienste) ein Verbundsobjekt
getmail-configuration-file
in seinem rcfile
-Feld, daher ist
die Dokumentation für getmail-configuration-file
verschachtelt in der
von getmail-configuration
.
(generate-documentation
`((getmail-configuration ,getmail-configuration-fields
(rcfile getmail-configuration-file))
…)
'getmail-configuration)
Für Dokumentationsname geben Sie ein Symbol mit dem Namen des Konfigurationsverbundstyps an.
Für Konfigurationssymbol, ein Symbol mit dem Namen, der beim
Definieren des Konfigurationsverbundstyp mittels define-configuration
benutzt wurde, gibt diese Prozedur die Texinfo-Dokumentation seiner Felder
aus. Wenn es keine verschachtelten Konfigurationsfelder gibt, bietet sich
diese Prozedur an, mit der Sie ausschließlich die Dokumentation der
obersten Ebene von Feldern ausgegeben bekommen.
Gegenwärtig gibt es kein automatisiertes Verfahren, um die Dokumentation zu
Konfigurationsverbundstypen zu erzeugen und gleich ins Handbuch
einzutragen. Stattdessen würden Sie jedes Mal, wenn Sie etwas an den
Docstrings eines Konfigurationsverbundstyps ändern, aufs Neue
generate-documentation
oder configuration->documentation
von
Hand aufrufen und die Ausgabe in die Datei doc/guix.texi einfügen.
Nun folgt ein Beispiel, wo ein Verbundstyp mit define-configuration
usw. erzeugt wird.
(use-modules (gnu services) (guix gexp) (gnu services configuration) (srfi srfi-26) (srfi srfi-1)) ;; Feldnamen, in Form von Scheme-Symbolen, zu Zeichenketten machen (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 "The name of the owner of this contact list.") (email string "The owner's email address.") (contacts (list-of-contact-configurations '()) "A list of @code{contact-configuation} records which contain information about all your contacts."))
Eine Kontaktelistekonfiguration könnte dann wie folgt erzeugt werden:
(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))))))
Wenn Sie diese Konfiguration auf die Platte serialisierten, ergäbe sich so eine Datei:
[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
Vorige: Shepherd-Dienste, Nach oben: Dienste definieren [Inhalt][Index]