#!/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 "-.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 [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 "/", also # liegt das Skript unter /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[@]}"}