Files
flatpak-repo-test/docker/sync/sync.sh
T

228 lines
7.7 KiB
Bash

#!/bin/bash
set -euo pipefail
REPO_PATH="/srv/flatpak-mirror/repo"
CONFIG_SRC="/config/apps.yaml"
GIT_CACHE="/tmp/config-repo"
ARCH="x86_64"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
# --- 1. apps.yaml besorgen -------------------------------------------------
# Setzt HTTP-Basic-Auth fuer git ueber GIT_CONFIG_*-Umgebungsvariablen
# (git >= 2.31). Vorteil gegenueber "https://user:token@host/...": das Token
# steht weder in der URL (die in Logs auftauchen koennte) noch als
# Kommandozeilenargument (das per "ps aux" auf dem Host sichtbar waere).
configure_git_auth() {
unset GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0
if [ -n "${GIT_USERNAME:-}" ] && [ -n "${GIT_TOKEN:-}" ]; then
log "Git: verwende Token-Authentifizierung (Benutzer: ${GIT_USERNAME})"
export GIT_CONFIG_COUNT=1
export GIT_CONFIG_KEY_0="http.extraHeader"
export GIT_CONFIG_VALUE_0="Authorization: Basic $(printf '%s' "${GIT_USERNAME}:${GIT_TOKEN}" | base64 | tr -d '\n')"
fi
}
get_config() {
if [ -n "${GIT_REPO_URL:-}" ]; then
configure_git_auth
if [ -d "$GIT_CACHE/.git" ]; then
log "Git: hole Updates aus ${GIT_REPO_URL}"
git -C "$GIT_CACHE" fetch --quiet origin "$GIT_BRANCH"
git -C "$GIT_CACHE" reset --hard --quiet "origin/${GIT_BRANCH}"
else
log "Git: klone ${GIT_REPO_URL}"
git clone --quiet --branch "$GIT_BRANCH" "$GIT_REPO_URL" "$GIT_CACHE"
fi
CONFIG_FILE="$GIT_CACHE/apps.yaml"
else
log "Kein GIT_REPO_URL gesetzt, nutze lokal gemountete ${CONFIG_SRC}"
CONFIG_FILE="$CONFIG_SRC"
fi
if [ ! -f "$CONFIG_FILE" ]; then
log "FEHLER: apps.yaml nicht gefunden unter ${CONFIG_FILE}"
exit 1
fi
}
# --- 2. Repo initialisieren, falls noch nicht vorhanden --------------------
init_repo() {
mkdir -p "$REPO_PATH"
if [ ! -f "$REPO_PATH/config" ]; then
log "Initialisiere neues OSTree-Repo unter ${REPO_PATH}"
ostree --repo="$REPO_PATH" init --mode=archive-z2
fi
if ! ostree --repo="$REPO_PATH" remote list | grep -q '^flathub$'; then
log "Richte Flathub als Remote ein"
curl -sSL -o /tmp/flathub.gpg "$FLATHUB_GPG_URL"
ostree --repo="$REPO_PATH" remote add flathub "$FLATHUB_REMOTE_URL" \
--gpg-import=/tmp/flathub.gpg
fi
}
# --- 3. Explizit gewuenschte App-Refs aus apps.yaml ------------------------
explicit_app_refs() {
yq -r '.apps[] | "app/" + .id + "/'"$ARCH"'/" + .branch' "$CONFIG_FILE"
}
# --- Hilfsfunktion: Runtime-Abhaengigkeit eines bereits gepullten Refs -----
# --- aus der eingebetteten "metadata"-Datei auslesen (Zeile runtime=...) ---
get_runtime_dependency() {
local ref="$1"
local meta dep
meta="$(ostree --repo="$REPO_PATH" cat "$ref" /metadata 2>/dev/null || true)"
[ -z "$meta" ] && return 0
dep="$(echo "$meta" | grep -E '^runtime=' | head -n1 | cut -d= -f2-)"
[ -z "$dep" ] && return 0
echo "runtime/${dep}"
}
# --- Hilfsfunktion: Commit-Checksum eines Refs finden, egal ob unter -------
# --- refs/heads/ oder (Collection-ID-gebunden) refs/mirrors/<id>/ ----------
resolve_pulled_checksum() {
local ref="$1"
if [ -f "$REPO_PATH/refs/heads/$ref" ]; then
cat "$REPO_PATH/refs/heads/$ref"
return 0
fi
find "$REPO_PATH/refs/mirrors" -type f -path "*/$ref" 2>/dev/null | head -n1 | xargs -r cat
}
# --- 4. Aktuell lokal verwaltete Refs ermitteln (Apps + Runtimes) ----------
current_refs() {
ostree --repo="$REPO_PATH" refs | grep -E "^(app|runtime)/" || true
}
# --- 5. Pull + rekursive Abhaengigkeitsaufloesung --------------------------
# Pullt einen einzelnen Ref und legt den passenden heads/-Ref an
# (siehe Kommentar bei resolve_pulled_checksum weiter oben).
pull_one_ref() {
local ref="$1"
log "Pull: ${ref}"
ostree --repo="$REPO_PATH" pull --mirror flathub "$ref"
local checksum
checksum="$(resolve_pulled_checksum "$ref")"
if [ -z "$checksum" ]; then
log "FEHLER: Konnte Commit-Checksum fuer ${ref} nach dem Pull nicht ermitteln"
exit 1
fi
ostree --repo="$REPO_PATH" refs --create="$ref" "$checksum" --force
if [ -n "${GPG_KEY_ID:-}" ]; then
# ref hat die Form "app/ID/ARCH/BRANCH" oder "runtime/ID/ARCH/BRANCH"
local ref_id ref_arch ref_branch
ref_id="$(echo "$ref" | cut -d/ -f2)"
ref_arch="$(echo "$ref" | cut -d/ -f3)"
ref_branch="$(echo "$ref" | cut -d/ -f4)"
log "Signiere ${ref_id}/${ref_arch}/${ref_branch} mit eigenem Key"
flatpak build-sign "$REPO_PATH" "$ref_id" "$ref_branch" \
--arch="$ref_arch" \
--gpg-sign="$GPG_KEY_ID" \
--gpg-homedir="${GNUPGHOME:-/etc/flatpak-sign/gnupg}"
fi
}
# Nimmt die explizit freigegebenen App-Refs, pullt sie, liest jeweils die
# Runtime-Abhaengigkeit aus und haengt sie hinten an die Warteschlange an -
# so werden auch mehrstufige Abhaengigkeiten (App -> Runtime -> Basis-Runtime)
# vollstaendig aufgeloest. Gibt am Ende alle tatsaechlich benoetigten Refs aus
# (Apps + alle aufgeloesten Runtimes), damit sync_refs() weiss, was behalten
# werden soll.
resolve_and_pull_all() {
local -A seen=()
local queue=()
local ref dep
while IFS= read -r ref; do
[ -z "$ref" ] && continue
queue+=("$ref")
done < <(explicit_app_refs)
while [ "${#queue[@]}" -gt 0 ]; do
ref="${queue[0]}"
queue=("${queue[@]:1}")
[ -n "${seen[$ref]:-}" ] && continue
seen["$ref"]=1
pull_one_ref "$ref"
dep="$(get_runtime_dependency "$ref")"
if [ -n "$dep" ] && [ -z "${seen[$dep]:-}" ]; then
log " -> benoetigt zusaetzlich: ${dep}"
queue+=("$dep")
fi
done
printf '%s\n' "${!seen[@]}"
}
# --- 6. Abgleich: pullen was fehlt (inkl. Abhaengigkeiten), loeschen was ---
# --- nicht mehr gewuenscht ist ----------------------------------------------
sync_refs() {
local wanted current
log "Loese App-Refs und Abhaengigkeiten auf..."
wanted="$(resolve_and_pull_all)"
current="$(current_refs)"
log "Verwaltete Refs (Apps + Runtimes):"
echo "$wanted" | sed 's/^/ + /'
# Refs entfernen, die weder explizit freigegeben noch als Abhaengigkeit
# noch benoetigt werden
while IFS= read -r ref; do
[ -z "$ref" ] && continue
if ! grep -qxF "$ref" <<< "$wanted"; then
log "Entferne nicht mehr benoetigten Ref: ${ref}"
ostree --repo="$REPO_PATH" refs --delete "$ref"
fi
done <<< "$current"
}
# --- 7. Summary aktualisieren -----------------------------------------------
update_summary() {
log "Aktualisiere Repo-Summary und Static Deltas"
if [ -n "${GPG_KEY_ID:-}" ]; then
if ! flatpak build-update-repo \
--generate-static-deltas \
--gpg-sign="$GPG_KEY_ID" \
--gpg-homedir="${GNUPGHOME:-/etc/flatpak-sign/gnupg}" \
"$REPO_PATH"; then
log "FEHLER: Signierte Summary konnte nicht erstellt werden"
return 1
fi
else
if ! flatpak build-update-repo --generate-static-deltas "$REPO_PATH"; then
log "FEHLER: Summary konnte nicht erstellt werden"
return 1
fi
fi
}
run_once() {
get_config
init_repo
sync_refs
if ! update_summary; then
return 1
fi
log "Sync abgeschlossen."
}
# --- Hauptschleife ----------------------------------------------------------
log "Starte Sync-Loop (Intervall: ${SYNC_INTERVAL_SECONDS}s)"
while true; do
if run_once; then
log "Naechster Lauf in ${SYNC_INTERVAL_SECONDS}s"
else
log "Sync-Lauf fehlgeschlagen, versuche es beim naechsten Intervall erneut"
fi
sleep "$SYNC_INTERVAL_SECONDS"
done