Ein grosser Commit, weil die Punkte einander bedingen: ohne lesbare Fehlermeldung war die Serienerkennung nicht zu diagnostizieren, und ohne Build-Kennung nicht einmal festzustellen, ob überhaupt der gebaute Stand läuft. Zwei der neun Meldungen betrafen Funktionen, die seit Stunden im Quelltext stehen. Version und Build. Die Version steht fest; daneben eine Kennung aus sechs Zeichen, die sich bei jedem Docker-Bau ändert. Sie steht in der Verwaltung, unter /health und im Protokoll bei jedem Start. Damit ist "reden wir vom selben Build?" in zwei Sekunden beantwortet statt in einem halben Tag. Serien. Lag eine Datei direkt im Serienordner und trug vor der Folgennummer nichts, wurde der ganze Dateiname zum Serientitel: aus 95 Serien wurden 737, jede mit einer Folge, bei jedem Lauf neu. Dazu lief der Scan in Verweise hinein — derselbe Ordner unter zwei Namen ergab zwei Serien. Und weder neue noch umgezogene Dateien standen in der Pfadliste des Laufs, weshalb ein doppelt gesehener Pfad eine zweite Zeile mit gleichem (LibraryId, Path) anlegte und der Eindeutigkeitsindex den ganzen Speichervorgang scheitern liess. Jede Serienanlage wird jetzt im Tagesprotokoll begründet. Fehlermeldungen. "An error occurred while saving the entity changes" stand englisch in einer deutschen Oberfläche und nannte weder Ursache noch nächsten Schritt. Jetzt geht der vollständige Text ins Protokoll und ein deutscher Satz ohne Fehlercode in die Anzeige — auch für "Failed to fetch", das aus dem Browser kam und nie übersetzt wurde. Protokolle. Die Ansicht holte die ganze Datei und zeigte 800 Zeilen davon; bei zwei Megabyte brach die Verbindung ab. Gelesen wird jetzt serverseitig rückwärts, mit einem Knopf für mehr. Auswahlfelder. Die drei <select> zeichnete das Betriebssystem: ein helles Systemmenü mitten in der dunklen Oberfläche. Ersetzt durch ein eigenes Listenfeld mit Tastaturbedienung. Bildwahl. Drei Raster untereinander in einem scrollenden Dialog hiess zwei Scrollebenen übereinander. Jetzt ein Reiter je Bildtyp. Sprache. Die Serversprache stand in der Serverliste zwischen Name, Metadaten und Fassung — gesucht und nicht gefunden. Sie hat jetzt einen eigenen Abschnitt ganz oben. Dazu: ein Knopf, der den erfassten Inhalt einer Mediathek verwirft, ohne Name und Pfad mitzunehmen; ein Abschnitt Speicher mit den drei Pfaden, ihrer Belegung und dem Leeren des Bildspeichers; und die Korrektur einer Zuordnung frischt nur noch die Kachel auf statt die ganze Seite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
144 lines
5.1 KiB
Bash
Executable File
144 lines
5.1 KiB
Bash
Executable File
#!/bin/bash
|
|
# Baut das Flaro-Image für beide Architekturen und legt es in die Registry.
|
|
#
|
|
# **Der Weg von Hand** — für den Fall, dass kein Gitea-Runner läuft. Sonst
|
|
# macht das `.gitea/workflows/image.yml` bei jedem Push von selbst.
|
|
#
|
|
# Tools/image-veroeffentlichen.sh → :latest
|
|
# Tools/image-veroeffentlichen.sh 0.2.0 → :latest und :0.2.0
|
|
#
|
|
# Nur eine Architektur — deutlich schneller, weil die fremde sonst unter
|
|
# Emulation läuft:
|
|
#
|
|
# FLARO_PLATTFORMEN=linux/amd64 Tools/image-veroeffentlichen.sh
|
|
#
|
|
# Vorher einmalig anmelden — das Passwort tippst du selbst ein:
|
|
#
|
|
# docker login git.scarriffle.com
|
|
|
|
set -euo pipefail
|
|
|
|
REGISTRY="${FLARO_REGISTRY:-git.scarriffle.com}"
|
|
PFAD="${FLARO_IMAGE_PATH:-scarriffle/flaro}"
|
|
BILD="$REGISTRY/$PFAD"
|
|
FASSUNG="${1:-}"
|
|
PLATTFORMEN="${FLARO_PLATTFORMEN:-linux/amd64,linux/arm64}"
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
command -v docker >/dev/null || { echo "docker fehlt."; exit 1; }
|
|
|
|
# **Ohne Anmeldung bricht der Push erst nach dem ganzen Bau ab.** Zwei
|
|
# Minuten Arbeit für eine Fehlermeldung, die am Anfang gestanden hätte.
|
|
# Kein `docker info | grep -q`: `grep -q` beendet die Pipe beim ersten
|
|
# Treffer, Docker bekommt SIGPIPE, und mit `set -o pipefail` gilt das als
|
|
# Fehlschlag. Die Prüfung meldete dann „Docker läuft nicht", während es lief.
|
|
if ! docker info >/dev/null 2>&1; then
|
|
echo "Docker läuft nicht."; exit 1
|
|
fi
|
|
if ! grep -q "$REGISTRY" ~/.docker/config.json 2>/dev/null; then
|
|
echo "Nicht an $REGISTRY angemeldet. Erst:"
|
|
echo
|
|
echo " docker login $REGISTRY"
|
|
exit 1
|
|
fi
|
|
|
|
# **Vor dem Bauen, nicht danach.** Laufen App und Browser farblich
|
|
# auseinander, soll das auffallen, bevor ein Image daraus wird.
|
|
if command -v python3 >/dev/null && [ -f Tools/tokens-pruefen.py ]; then
|
|
python3 Tools/tokens-pruefen.py || {
|
|
echo
|
|
echo "Abgebrochen. Mit FLARO_DRIFT_EGAL=1 trotzdem bauen."
|
|
[ "${FLARO_DRIFT_EGAL:-}" = "1" ] || exit 1
|
|
}
|
|
fi
|
|
|
|
# Fragt die Registry, welcher Stand dort unter `latest` liegt.
|
|
#
|
|
# Anonym — das Paket ist öffentlich lesbar. Schlägt es fehl, ist die Antwort
|
|
# leer, und der Aufrufer entscheidet, was das bedeutet.
|
|
registry_digest() {
|
|
local token
|
|
token=$(curl -fsS --max-time 20 \
|
|
"https://$REGISTRY/v2/token?scope=repository:$PFAD:pull&service=container_registry" \
|
|
| python3 -c 'import json,sys;print(json.load(sys.stdin).get("token",""))' 2>/dev/null) || return 1
|
|
[ -n "$token" ] || return 1
|
|
|
|
curl -fsS --max-time 20 -D- -o /dev/null \
|
|
-H "Authorization: Bearer $token" \
|
|
-H "Accept: application/vnd.oci.image.index.v1+json" \
|
|
"https://$REGISTRY/v2/$PFAD/manifests/latest" 2>/dev/null \
|
|
| awk 'BEGIN{IGNORECASE=1} /^docker-content-digest:/ {print $2}' | tr -d '\r'
|
|
}
|
|
|
|
MARKEN=(-t "$BILD:latest")
|
|
[ -n "$FASSUNG" ] && MARKEN+=(-t "$BILD:$FASSUNG")
|
|
|
|
# **Eine Kennung je Bau.**
|
|
#
|
|
# Sechs Zeichen, jedes Mal neu — auch bei unverändertem Quelltext. Sie landet
|
|
# im Abbild und steht danach in der Oberfläche unter „Einstellungen" sowie
|
|
# unter `/health`. Damit ist die Frage „läuft auf dem NAS wirklich der Bau von
|
|
# eben?" in zwei Sekunden beantwortet statt in einem halben Tag.
|
|
#
|
|
# Ohne I, O, 0 und 1: diese Kennung wird vorgelesen und abgetippt.
|
|
BUILD=$(LC_ALL=C tr -dc 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' < /dev/urandom | head -c 6)
|
|
echo "Build-Kennung dieses Laufs: $BUILD"
|
|
|
|
# **Ein eigener Builder.** Der Vorgabe-Builder von Docker Desktop kann kein
|
|
# Manifest mit zwei Architekturen bauen; `docker buildx create` schon.
|
|
docker buildx inspect flaro-bauer >/dev/null 2>&1 \
|
|
|| docker buildx create --name flaro-bauer --use >/dev/null
|
|
|
|
# **Den Digest festhalten, bevor gebaut wird.** Nur so lässt sich hinterher
|
|
# sagen, ob wirklich etwas Neues angekommen ist.
|
|
vorher=$(registry_digest || true)
|
|
|
|
echo "Baue $BILD für $PLATTFORMEN."
|
|
if ! docker buildx build \
|
|
--builder flaro-bauer \
|
|
--platform "$PLATTFORMEN" \
|
|
-f server/Dockerfile \
|
|
--build-arg "FLARO_BUILD=$BUILD" \
|
|
"${MARKEN[@]}" \
|
|
--push . ; then
|
|
echo
|
|
echo "Der Bau oder das Hochladen ist gescheitert. In der Registry liegt weiter:"
|
|
echo " ${vorher:-nichts}"
|
|
exit 1
|
|
fi
|
|
|
|
# **Nachsehen, statt zu glauben.**
|
|
#
|
|
# `docker buildx build --push` hat bei einem abgebrochenen Upload schon mit
|
|
# Rückgabewert 0 beendet, nachdem es „ERROR: failed to build" gedruckt hatte —
|
|
# ein TLS-Zeitlimit mitten im Hochladen. Das Skript meldete Erfolg, in der
|
|
# Registry lag das alte Image, und auf dem NAS kam eine Fassung an, die
|
|
# niemand gebaut hatte. Seitdem wird gefragt, nicht vertraut.
|
|
nachher=$(registry_digest || true)
|
|
|
|
if [ -z "$nachher" ]; then
|
|
echo
|
|
echo "Die Registry antwortet nicht auf $BILD:latest — hochgeladen wurde offenbar nichts."
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$vorher" ] && [ "$vorher" = "$nachher" ]; then
|
|
echo
|
|
echo "In der Registry liegt noch derselbe Stand wie vorher:"
|
|
echo " $nachher"
|
|
echo "Das Hochladen ist also nicht durchgekommen. Noch einmal versuchen."
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "Fertig. In der Registry liegt jetzt:"
|
|
echo " $nachher"
|
|
echo
|
|
echo "Build-Kennung: $BUILD"
|
|
echo " Dieselbe muss nach dem Ziehen unter Einstellungen stehen."
|
|
echo " Steht dort eine andere, läuft auf dem NAS ein älteres Abbild."
|
|
echo
|
|
echo "Auf dem NAS:"
|
|
echo " image: $BILD:${FASSUNG:-latest}"
|