Implementierungen in goat gen
Registrieren, Überschreiben und Ausführen von Implementierungen mit den Befehlen implement und implement:overwrite.
goat gen: implement und implement:overwrite
Das Subterminal goat gen stellt zwei Befehle zur Registrierung von Generierungsimplementierungen bereit:
implementimplement:overwrite
Implementierungen können sowohl im Haupt-Generierungsskript als auch in jedem geladenen Modul deklariert werden.
Nach Abschluss der Registrierungsphase werden alle final aufgelösten Implementierungen parallel ausgeführt.
implement
Der Befehl implement registriert eine Implementierung unter einem eindeutigen Namen.
Syntax
implement --name <name> --body=<<EOF
...
EOFBeispiel
implement --name assets --body=<<IMPLEOF
gen:files:onchange \
--from="assets" \
--cache="cache/assets-mtimes.json" \
--foreach=<<EOF
gen:force \
--tmpl="asset.txt.tmpl" \
--out="generated/{{.Data.Name.SnakeCase}}.txt"
EOF \
--index=<<EOF
gen:force \
--tmpl="index.txt.tmpl" \
--out="generated/index.txt"
EOF
IMPLEOFDer über --name übergebene Wert identifiziert die Implementierung.
Für jeden Implementierungsnamen darf genau eine implement-Definition existieren.
Wenn beispielsweise bereits folgende Implementierung registriert wurde:
implement --name assets --body=<<EOF
...
EOFist eine erneute Registrierung mit demselben Namen ungültig:
implement --name assets --body=<<EOF
...
EOFund muss zu einem Fehler führen.
implement:overwrite
Der Befehl implement:overwrite ersetzt den Body einer Implementierung bei der finalen Auflösung der Implementierungs-Registry.
Syntax
implement:overwrite --name <name> --body=<<EOF
...
EOFBeispiel
implement:overwrite --name assets --body=<<IMPLEOF
gen:files:onchange \
--from="assets" \
--cache="cache/assets-mtimes.json" \
--foreach=<<EOF
gen:force \
--tmpl="other_asset.txt.tmpl" \
--out="generated/{{.Data.Name.SnakeCase}}.txt"
EOF \
--index=<<EOF
gen:force \
--tmpl="other_index.txt.tmpl" \
--out="generated/index.txt"
EOF
IMPLEOFFür jeden Implementierungsnamen darf höchstens eine implement:overwrite-Definition existieren.
Beispielsweise:
implement:overwrite --name assets --body=<<EOF
...
EOFgefolgt von:
implement:overwrite --name assets --body=<<EOF
...
EOFmuss zu einem Fehler führen.
Die Registrierungsreihenfolge spielt keine Rolle
Generierungsmodule können parallel geladen werden.
Daher ist die Reihenfolge, in der implement und implement:overwrite verarbeitet werden, nicht garantiert.
implement:overwrite setzt deshalb nicht voraus, dass die zugehörige Basisimplementierung bereits registriert wurde.
Folgendes ist gültig:
implement:overwrite --name assets --body=<<EOF
# überschriebene Implementierung
EOFauch wenn die Basisimplementierung erst später registriert wird:
implement --name assets --body=<<EOF
# Basisimplementierung
EOFDie finale Implementierung wird erst bestimmt, nachdem das Haupt-Generierungsskript und alle geladenen Module ihre Implementierungen registriert haben.
Für jeden Implementierungsnamen gelten folgende Regeln:
| Registrierung | Zulässig |
Ein implement | Ja |
Zwei oder mehr implement-Definitionen | Nein |
Ein implement + ein implement:overwrite | Ja |
Ein implement + mehrere implement:overwrite | Nein |
Mehrere implement-Definitionen + ein implement:overwrite | Nein |
Wenn ein implement:overwrite vorhanden ist, ersetzt dessen Body den durch implement registrierten Body.
Implementierungen dürfen nicht verschachtelt werden
implement und implement:overwrite sind Registrierungsbefehle.
Sie dürfen ausschließlich während der Registrierungsphase verwendet werden.
Keiner der beiden Befehle darf innerhalb des Bodys einer anderen Implementierung aufgerufen werden.
Ungültig: implement innerhalb von implement
implement --name assets --body=<<EOF
implement --name nested --body=<<INNER
...
INNER
EOFUngültig: implement:overwrite innerhalb von implement
implement --name assets --body=<<EOF
implement:overwrite --name nested --body=<<INNER
...
INNER
EOFUngültig: implement innerhalb von implement:overwrite
implement:overwrite --name assets --body=<<EOF
implement --name nested --body=<<INNER
...
INNER
EOFUngültig: implement:overwrite innerhalb von implement:overwrite
implement:overwrite --name assets --body=<<EOF
implement:overwrite --name nested --body=<<INNER
...
INNER
EOFAlle oben genannten Fälle müssen zu einem Fehler führen.
Ausführungszyklus
Die Verarbeitung von Implementierungen in goat gen erfolgt in zwei klar getrennten Phasen.
1. Registrierung
Das Haupt-Generierungsskript und alle geladenen Module registrieren ihre Implementierungen mit:
implement
implement:overwriteIn dieser Phase werden die Implementierungs-Bodys gespeichert, aber noch nicht ausgeführt.
Nach Abschluss der Registrierung wird die Implementierungs-Registry validiert und anschließend final aufgelöst.
Für jeden Implementierungsnamen gilt:
- Es muss genau eine
implement-Definition existieren. - Es darf null oder eine
implement:overwrite-Definition geben. - Doppelte
implement-Definitionen führen zu einem Fehler. - Doppelte
implement:overwrite-Definitionen führen zu einem Fehler. - Wenn ein
implement:overwriteexistiert, wird dessen Body zum finalen Implementierungs-Body.
2. Ausführung
Nach Abschluss der Registrierung werden alle final aufgelösten Implementierungen parallel ausgeführt.
goat gen wartet auf den Abschluss aller Implementierungen, bevor der Befehl beendet wird.
Während dieser Phase ist die Registrierung geschlossen.
Wenn der Body einer Implementierung versucht, einen der folgenden Befehle aufzurufen:
implementoder:
implement:overwritemuss der Aufruf mit einem Fehler fehlschlagen.
Fehler, die während der Ausführung von Implementierungen auftreten, müssen korrekt an goat gen weitergegeben werden.
Verwendung von Implementierungen über mehrere Module hinweg
Ein Modul kann eine Standardimplementierung bereitstellen:
# Modul: assets
implement --name assets --body=<<EOF
gen:files:onchange \
--from="assets" \
--cache="cache/assets-mtimes.json" \
--foreach=<<FILE
gen:force \
--tmpl="asset.txt.tmpl" \
--out="generated/{{.Data.Name.SnakeCase}}.txt"
FILE
EOFEin anderes Modul oder das Haupt-Generierungsskript kann diese Implementierung ersetzen:
implement:overwrite --name assets --body=<<EOF
gen:files:onchange \
--from="assets" \
--cache="cache/assets-mtimes.json" \
--foreach=<<FILE
gen:force \
--tmpl="custom-asset.txt.tmpl" \
--out="generated/{{.Data.Name.SnakeCase}}.txt"
FILE
EOFEs spielt keine Rolle, welche Deklaration zuerst verarbeitet wird.
Nach Abschluss der Registrierung ist der über implement:overwrite angegebene Body die finale Implementierung für assets.
Der ursprüngliche Body wird nicht ausgeführt.
Mehrere unabhängige Implementierungen
Unterschiedliche Implementierungen können von unterschiedlichen Modulen registriert werden.
Beispiel:
implement --name assets --body=<<EOF
# Assets generieren
EOFimplement --name routes --body=<<EOF
# Routen generieren
EOFimplement --name models --body=<<EOF
# Modelle generieren
EOFNach Abschluss der Registrierung werden alle drei Implementierungen parallel ausgeführt.
Schematisch:
Registrierung
|
+-- assets
+-- routes
+-- models
|
v
Registry auflösen
|
+--> assets ausführen ----+
+--> routes ausführen ----+--> auf alle warten --> beenden
+--> models ausführen ----+Es gibt keine garantierte Ausführungsreihenfolge zwischen unabhängigen Implementierungen.
Eine Implementierung darf daher nicht davon ausgehen, dass eine andere Implementierung vor oder nach ihr ausgeführt wird.
Beispiel für ein Überschreiben
Angenommen, es existieren zwei Module.
Das erste stellt eine Standardimplementierung bereit:
implement --name assets --body=<<EOF
echo "default assets implementation"
EOFDas zweite ersetzt diese Implementierung:
implement:overwrite --name assets --body=<<EOF
echo "custom assets implementation"
EOFDie final aufgelöste Implementierung lautet:
echo "custom assets implementation"Nur der Body aus implement:overwrite wird ausgeführt.
Die folgende Reihenfolge ist gleichwertig und ebenfalls gültig:
implement:overwrite --name assets --body=<<EOF
echo "custom assets implementation"
EOF
implement --name assets --body=<<EOF
echo "default assets implementation"
EOFDie Reihenfolge der Deklarationen hat keinen Einfluss auf das Ergebnis.
Ungültige doppelte Registrierungen
Doppeltes implement
implement --name assets --body=<<EOF
echo "first"
EOF
implement --name assets --body=<<EOF
echo "second"
EOFDieser Fall muss zu einem Fehler führen, da für assets mehr als eine Basisimplementierung existiert.
Doppeltes implement:overwrite
implement --name assets --body=<<EOF
echo "default"
EOF
implement:overwrite --name assets --body=<<EOF
echo "first overwrite"
EOF
implement:overwrite --name assets --body=<<EOF
echo "second overwrite"
EOFDieser Fall muss zu einem Fehler führen, da für assets mehr als ein Overwrite registriert wurde.
Wichtigste Regeln
Bei der Verwendung von Implementierungen gelten folgende Regeln:
implementdefiniert die Basisimplementierung.- Jeder Implementierungsname muss genau eine Basisdefinition besitzen.
implement:overwritekann die Basisdefinition ersetzen.- Für einen Implementierungsnamen darf höchstens ein
implement:overwriteexistieren. implement:overwritedarf vor dem zugehörigenimplementregistriert werden.- Auf die Registrierungsreihenfolge zwischen Modulen darf man sich nicht verlassen.
- Implementierungs-Bodys werden während der Registrierungsphase nicht ausgeführt.
implementundimplement:overwritedürfen nicht innerhalb von Implementierungs-Bodys aufgerufen werden.- Final aufgelöste Implementierungen werden parallel ausgeführt.
- Die Ausführungsreihenfolge der Implementierungen ist nicht garantiert.
goat genwartet auf den Abschluss aller Implementierungen.- Fehler aus der Implementierungsausführung werden an
goat genweitergegeben.