182 lines
7.5 KiB
Bash
182 lines
7.5 KiB
Bash
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# Installation -- der kurze Weg.
|
|
#
|
|
# Diese Datei liegt oben im Paket und ruft den Installer unter deploy/ auf:
|
|
#
|
|
# tar xzf tesm-vX.Y.Z.tar.gz && cd tesm
|
|
# sudo bash install.sh --app tesm --https
|
|
#
|
|
# Sie genuegt aber auch **allein**: liegt kein Paket um sie herum, holt sie
|
|
# sich das aktuelle Release selbst.
|
|
#
|
|
# curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm/raw/branch/main/install.sh
|
|
# sudo bash install.sh --app tesm --https
|
|
#
|
|
# Die Master-Ausgabe des Lizenzservers liegt im privaten Repositorium
|
|
# tesm-license-master. Allein-Betrieb dafuer:
|
|
#
|
|
# export TESM_RELEASE_REPO=tesm-license-master
|
|
# export TESM_RELEASE_TOKEN=<Gitea-Token>
|
|
# sudo -E bash install.sh --app tesm-license --https
|
|
#
|
|
# Aus einem entpackten Paket braucht es das nicht: dort entscheidet, welches
|
|
# Paket es ist. Die Master-Ausgabe legt beim Installieren Signaturschluessel
|
|
# und eigene Master-Lizenz selbst an.
|
|
#
|
|
# Alle Argumente gehen unveraendert an deploy/install.sh weiter; dessen Hilfe:
|
|
#
|
|
# bash install.sh --help
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# --app wird nur gelesen, nicht verbraucht: der Bootstrap braucht es fuer den
|
|
# Namen des Repositoriums, der Installer bekommt die Argumente unveraendert.
|
|
APP=""
|
|
TAG="latest"
|
|
ARGUMENTE=("$@")
|
|
for ((i = 0; i < $#; i++)); do
|
|
case "${ARGUMENTE[i]}" in
|
|
--app) APP="${ARGUMENTE[i + 1]:-}" ;;
|
|
--tag) TAG="${ARGUMENTE[i + 1]:-latest}" ;;
|
|
esac
|
|
done
|
|
|
|
# Ohne Paket drumherum brauchen wir den Namen, um das richtige Release zu
|
|
# finden -- die beiden Anwendungen liegen in getrennten Repositorien.
|
|
if [[ ! -f "$SCRIPT_DIR/deploy/install.sh" ]]; then
|
|
[[ "$APP" == "tesm" || "$APP" == "tesm-license" ]] || {
|
|
echo "Diese Datei liegt allein hier und muss sich das Release holen --" >&2
|
|
echo "dafuer braucht sie --app <tesm|tesm-license>." >&2
|
|
echo "Verwendung: install.sh --app <tesm|tesm-license> [weitere Optionen]" >&2
|
|
exit 2
|
|
}
|
|
fi
|
|
|
|
# --8<-- Bootstrap: Release holen --------------------------------------------
|
|
# Wortgleich in update.sh und upgrade.sh; ein Hygienetest vergleicht die beiden
|
|
# Bloecke. Zwei eigenstaendige Skripte koennen sich keine Datei teilen, und
|
|
# beide sollen als **einzelne Datei** genuegen: auf das Zielsystem legen,
|
|
# ausfuehren, fertig -- auf einer 1.2.8 liegt nichts von diesem Projekt.
|
|
#
|
|
# Erwartet: $APP und $TAG, wahlweise $REPO (Vorgabe: $APP). Setzt: $TAG
|
|
# (aufgeloest) und $SRC (entpacktes Release). Raeumt sein Arbeitsverzeichnis
|
|
# beim Beenden auf.
|
|
#
|
|
# $REPO gibt es, weil Installationsname und Repositorium auseinanderfallen
|
|
# koennen: die Master-Ausgabe des Lizenzservers liegt in
|
|
# "tesm-license-master", die Installation heisst weiter "tesm-license".
|
|
#
|
|
# Zwei Fallen des Vorgaengers sind hier 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-Anhangs.
|
|
# * Nach dem Entpacken wird geprueft, dass ein install.sh existiert.
|
|
BASE="${TESM_RELEASE_BASE:-https://gitea.int.eertmoed.net}"
|
|
OWNER="${TESM_RELEASE_OWNER:-alientim}"
|
|
|
|
# Ein privates Repositorium -- tesm-license-master -- gibt sein Release nur mit
|
|
# Zugriffstoken heraus. Reihenfolge: Umgebungsvariable, dann eine Datei, die
|
|
# der Betreiber selbst anlegt. Der Installer legt sie nie an: ob ein Token auf
|
|
# dem Server liegt, ist keine Entscheidung eines Skripts.
|
|
TOKEN="${TESM_RELEASE_TOKEN:-}"
|
|
if [[ -z "$TOKEN" && -r /etc/tesm-release.token ]]; then
|
|
TOKEN="$(tr -d '[:space:]' < /etc/tesm-release.token)"
|
|
fi
|
|
|
|
# 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"
|
|
}
|
|
|
|
BOOTSTRAP_WORK=""
|
|
bootstrap_aufraeumen() {
|
|
# Den Ausstiegscode zuerst festhalten: alles danach ueberschreibt ihn.
|
|
local code=$?
|
|
[[ -n "$BOOTSTRAP_WORK" ]] && rm -rf "$BOOTSTRAP_WORK"
|
|
# Wer einen eigenen Abschluss braucht -- etwa einen Rueckweg nach einem
|
|
# Fehlschlag --, definiert "beim_beenden". Ein zweiter "trap ... EXIT" waere
|
|
# der falsche Weg: er wuerde diesen hier ersetzen, und das entpackte Release
|
|
# bliebe unter /tmp liegen.
|
|
declare -F beim_beenden >/dev/null 2>&1 && beim_beenden "$code"
|
|
return "$code"
|
|
}
|
|
trap bootstrap_aufraeumen EXIT
|
|
|
|
release_holen() {
|
|
local repo="${TESM_RELEASE_REPO:-${REPO:-$APP}}" asset
|
|
# Leeres Array und "set -u" vertragen sich nur mit dieser Schreibweise.
|
|
local -a kopf=()
|
|
[[ -n "$TOKEN" ]] && kopf=(-H "Authorization: token $TOKEN")
|
|
for werkzeug in curl tar python3 find; do
|
|
command -v "$werkzeug" >/dev/null 2>&1 || {
|
|
echo "Auf diesem System fehlt $werkzeug -- ohne das geht es nicht." >&2
|
|
return 1
|
|
}
|
|
done
|
|
BOOTSTRAP_WORK="$(mktemp -d /tmp/tesm-release-XXXXXX)"
|
|
|
|
if [[ "$TAG" == "latest" ]]; then
|
|
echo "==> Ermittle aktuellen Release-Tag ..."
|
|
TAG="$(curl -fsS ${kopf[0]+"${kopf[@]}"} "$BASE/api/v1/repos/$OWNER/$repo/releases/latest" \
|
|
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')" || {
|
|
echo "Kein Release gefunden unter $BASE/$OWNER/$repo." >&2
|
|
[[ -z "$TOKEN" ]] &&
|
|
echo "Ist das Repositorium privat? Dann TESM_RELEASE_TOKEN setzen." >&2
|
|
echo "Andere Quelle: TESM_RELEASE_BASE, TESM_RELEASE_OWNER, TESM_RELEASE_REPO." >&2
|
|
return 1
|
|
}
|
|
echo " $TAG"
|
|
fi
|
|
|
|
asset="$repo-$TAG.tar.gz"
|
|
echo "==> Lade $asset ..."
|
|
curl -fsSL ${kopf[0]+"${kopf[@]}"} -o "$BOOTSTRAP_WORK/$asset" \
|
|
"$BASE/$OWNER/$repo/releases/download/$TAG/$asset" || {
|
|
echo "Download fehlgeschlagen: $BASE/$OWNER/$repo/releases/download/$TAG/$asset" >&2
|
|
return 1
|
|
}
|
|
|
|
echo "==> Entpacke ..."
|
|
tar -xzf "$BOOTSTRAP_WORK/$asset" -C "$BOOTSTRAP_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 "$BOOTSTRAP_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
|
|
return 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
|
|
return 1
|
|
fi
|
|
}
|
|
# --8<-- Ende Bootstrap ------------------------------------------------------
|
|
|
|
if [[ -f "$SCRIPT_DIR/deploy/install.sh" ]]; then
|
|
# Im Paket: der Installer liegt daneben.
|
|
exec bash "$SCRIPT_DIR/deploy/install.sh" ${ARGUMENTE[0]+"${ARGUMENTE[@]}"}
|
|
fi
|
|
|
|
# Allein: Release holen und dessen Installer benutzen. Kein exec -- sonst
|
|
# laeuft die Aufraeumfalle nie und das entpackte Release bliebe unter /tmp.
|
|
release_holen || { echo "Das Release liess sich nicht holen." >&2; exit 1; }
|
|
bash "$SRC/deploy/install.sh" ${ARGUMENTE[0]+"${ARGUMENTE[@]}"}
|