Der Lauf gegen die echte Installation hat zwei Fehler gezeigt, die den
Aktualisierungsweg fuer jede Version unbrauchbar machten:
* Die Suche nach install.sh im entpackten Paket lief mit "-maxdepth 2".
release.sh packt mit dem Praefix "<name>/", das Skript liegt also drei
Ebenen tief -- gefunden wurde nie etwas, und die Meldung schob es auf den
Download ("Im Paket fehlt deploy/install.sh").
* Die CRLF-Pruefung rief "file" auf. Das Paket gehoert nicht zur
Grundinstallation eines Servers; fehlt es, endete die Pipeline in "command
not found", grep bekam nichts zu sehen, der if-Zweig wurde nicht betreten --
und genau der Fehler, den die Pruefung abfangen soll, ging unbemerkt durch.
Der Wagenruecklauf wird jetzt ohne Zusatzpaket gesucht, mit "-U": unter Linux
ohne Wirkung, auf einer Windows-Buildmaschine entscheidend, weil grep dort
den Wagenruecklauf beim Lesen entfernt.
Beide Pruefungen fuehren die echten Zeilen aus dem Skript aus -- die eine
gegen den Verzeichnisaufbau, den release.sh erzeugt, die andere gegen zwei
Dateien mit und ohne Wagenruecklauf.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
90 lines
3.8 KiB
Bash
90 lines
3.8 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Bootstrapper: laedt ein Release herunter und ruft dessen install.sh auf.
|
|
# Enthaelt selbst keinerlei Installationslogik.
|
|
#
|
|
# Zwei Fallen des Vorgaengers sind hier bewusst vermieden:
|
|
# * Der Tag "latest" wird ueber die API aufgeloest, nie direkt in die
|
|
# Download-URL geschrieben. Gitea liefert sonst mit HTTP 200 ein
|
|
# automatisch erzeugtes Quell-Snapshot statt des echten Release-Assets.
|
|
# * Nach dem Entpacken wird geprueft, dass ein install.sh existiert -- faengt
|
|
# denselben Fehler ein zweites Mal ab.
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
# Ein Wagenruecklauf im Paket macht jedes Shell-Skript auf dem Ziel
|
|
# unbrauchbar ("bad interpreter"). Die Pruefung darf dabei nicht selbst
|
|
# von einem Zusatzpaket abhaengen: mit "file" -- das auf einem schlanken
|
|
# Server fehlt -- endete sie in "command not found", grep bekam nichts zu
|
|
# sehen, und das Skript machte weiter, als waere alles in Ordnung.
|
|
hat_crlf() {
|
|
local cr
|
|
cr="$(printf '\r')"
|
|
# -U (binaer lesen) ist unter Linux ohne Wirkung, auf einer Windows-Buildmaschine
|
|
# aber entscheidend: dort entfernt grep den Wagenruecklauf beim Lesen und
|
|
# findet deshalb nie einen.
|
|
LC_ALL=C grep -qU "$cr" "$1"
|
|
}
|
|
|
|
APP="${1:-}"
|
|
TAG="${2:-latest}"
|
|
|
|
# Alles nach dem Tag geht unveraendert an install.sh weiter. Ohne das liesse
|
|
# sich eine benannte Instanz nicht aktualisieren: install.sh leitet den Namen
|
|
# aus "--instance" ab, und ohne den Schalter entstuende neben "tesm-opus" eine
|
|
# zweite Installation namens "tesm" -- mit eigener Datenbank, eigener
|
|
# nginx-Site und demselben Port.
|
|
shift $(( $# > 2 ? 2 : $# ))
|
|
EXTRA=("$@")
|
|
# Bezugsquelle. Die Vorgaben zeigen dorthin, wo die Releases tatsaechlich
|
|
# liegen -- ein Platzhalter wie "gitea.example.invalid" macht das Skript auf
|
|
# jedem Host unbrauchbar, und genau das war hier der Fall.
|
|
#
|
|
# Das Repository heisst wie die Anwendung; getrennte Repositorien, getrennte
|
|
# Releases. Der Anhang heisst "<repo>-<tag>.tar.gz", siehe unten.
|
|
BASE="${TESM_RELEASE_BASE:-https://gitea.int.eertmoed.net}"
|
|
OWNER="${TESM_RELEASE_OWNER:-alientim}"
|
|
|
|
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || {
|
|
echo "Verwendung: update.sh <tesm|tesm-license> [tag] [install.sh-Argumente ...]" >&2
|
|
echo "Beispiel : update.sh tesm latest --instance opus" >&2
|
|
exit 2
|
|
}
|
|
|
|
REPO="${TESM_RELEASE_REPO:-$APP}"
|
|
|
|
WORK="$(mktemp -d /tmp/tesm-update-XXXXXX)"
|
|
trap 'rm -rf "$WORK"' EXIT # anders als im Vorgaenger wird aufgeraeumt
|
|
|
|
if [[ "$TAG" == "latest" ]]; then
|
|
echo "==> Ermittle aktuellen Release-Tag ..."
|
|
TAG="$(curl -fsS "$BASE/api/v1/repos/$OWNER/$REPO/releases/latest" \
|
|
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')"
|
|
echo " $TAG"
|
|
fi
|
|
|
|
ASSET="$REPO-$TAG.tar.gz"
|
|
echo "==> Lade $ASSET ..."
|
|
curl -fsSL -o "$WORK/$ASSET" "$BASE/$OWNER/$REPO/releases/download/$TAG/$ASSET"
|
|
|
|
echo "==> Entpacke ..."
|
|
tar -xzf "$WORK/$ASSET" -C "$WORK"
|
|
# Drei Ebenen, nicht zwei: release.sh packt mit dem Praefix "<name>/", also
|
|
# liegt das Skript unter <name>/deploy/install.sh. Mit "-maxdepth 2" fand die
|
|
# Suche nie etwas -- und die Fehlermeldung schob es auf den Download.
|
|
SRC="$(find "$WORK" -maxdepth 3 -name install.sh -path '*/deploy/*' -printf '%h/..\n' | head -1)"
|
|
[[ -n "$SRC" ]] || { echo "Im Paket fehlt deploy/install.sh -- Download unbrauchbar." >&2; exit 1; }
|
|
SRC="$(cd "$SRC" && pwd)"
|
|
|
|
echo "==> Pruefe auf CRLF (Windows-Buildmaschinen) ..."
|
|
if hat_crlf "$SRC/deploy/install.sh"; then
|
|
echo "Das Paket enthaelt CRLF-Zeilenenden. Beim Paketieren fehlte" >&2
|
|
echo "'git -c core.autocrlf=false archive'." >&2
|
|
exit 1
|
|
fi
|
|
|
|
read -r -p "Version $TAG fuer $APP${EXTRA[0]+ (${EXTRA[*]})} installieren? [j/N] " answer
|
|
[[ "$answer" =~ ^[jJyY]$ ]] || exit 0
|
|
|
|
exec sudo bash "$SRC/deploy/install.sh" --app "$APP" --yes ${EXTRA[0]+"${EXTRA[@]}"}
|