#!/usr/bin/env bash # Projekte-Sync (20.08.2026): haelt ~/projekte mit Gitea deckungsgleich. # # Warum: Der Hermes-Desktop laeuft gegen das Box-Backend, sein Ordner-Waehler zeigt # also das Dateisystem der BOX. Damit dort alle Projekte auftauchen, muessen sie hier # liegen — und aktuell sein. # # Regeln (bewusst konservativ — dieses Skript laeuft unbeaufsichtigt): # • NUR fast-forward (`--ff-only`). Kein merge, kein rebase, kein reset, kein force. # • Repos mit lokalen Aenderungen werden UEBERSPRUNGEN, nicht ueberfahren. # • Live-Deployments werden NIE gezogen (mission-control-v2 wird aus dem Deploy # bedient und pusht selbst) — sie bekommen nur eine Verknuepfung, damit sie im # Waehler auftauchen. # • Bestehende Checkouts in ~ bleiben, wo sie sind; ~/projekte bekommt eine # Verknuepfung darauf statt eines zweiten Klons. # • Interne Gitea-IP, NICHT die DDNS-Domain: die ist nachts durch die # Zwangstrennung zeitweise tot (Lehre vom 24.07.). # # Aufruf: projekte-sync.sh [--dry-run] # Exit: 0 = alles gut · 1 = mindestens ein Repo hatte ein Problem set -uo pipefail GITEA="${GITEA_URL:-http://192.168.178.153:3000}" ZIEL="${PROJEKTE_DIR:-$HOME/projekte}" LOG="${PROJEKTE_SYNC_LOG:-$HOME/.hermes/logs/projekte-sync.log}" DRY=0 [ "${1:-}" = "--dry-run" ] && DRY=1 # Repos, die NICHT nach ~/projekte geklont werden (Live-Deployment oder Altlast). # mission-control-v2: laeuft aus ~/mission-control-v2, Dienste arbeiten daraus. # mission-control: archivierte v1. NIE_ZIEHEN="mission-control-v2" UEBERSPRINGEN="mission-control" mkdir -p "$ZIEL" "$(dirname "$LOG")" FEHLER=0 log() { printf '%s %s\n' "$(date '+%F %T')" "$*" | tee -a "$LOG"; } TOKEN="" for f in "$HOME/.config/gitea/create-token"; do [ -r "$f" ] && TOKEN="$(tr -d '[:space:]' < "$f")" && break done if [ -z "$TOKEN" ]; then log "ABBRUCH: kein Gitea-Token unter ~/.config/gitea/create-token" exit 1 fi REPOS="$(curl -s -m 20 -H "Authorization: token $TOKEN" \ "$GITEA/api/v1/user/repos?limit=100" \ | python3 -c 'import sys,json; [print(r["name"]) for r in json.load(sys.stdin)]' 2>/dev/null)" if [ -z "$REPOS" ]; then log "ABBRUCH: Gitea lieferte keine Repo-Liste ($GITEA)" exit 1 fi log "=== Sync-Lauf ($(printf '%s\n' "$REPOS" | wc -l) Repos gemeldet)$([ $DRY -eq 1 ] && echo ' [Trockenlauf]') ===" # Vorhandenen Checkout eines Repos finden (oberste Home-Ebene bevorzugt). finde_checkout() { local name="$1" d for d in "$HOME/$name" "$ZIEL/$name"; do [ -d "$d/.git" ] && { printf '%s' "$d"; return 0; } done return 1 } verknuepfe() { # $1=Zielpfad des echten Checkouts, $2=Repo-Name local ziel="$1" name="$2" link="$ZIEL/$name" [ "$ziel" = "$link" ] && return 0 [ -L "$link" ] && [ "$(readlink -f "$link")" = "$(readlink -f "$ziel")" ] && return 0 [ -e "$link" ] && [ ! -L "$link" ] && { log " ! $name: $link existiert und ist keine Verknuepfung — nichts getan"; return 1; } [ $DRY -eq 1 ] && { log " ~ $name: wuerde verknuepfen -> $ziel"; return 0; } ln -sfn "$ziel" "$link" && log " ~ $name: verknuepft -> ${ziel/$HOME/\~}" } for name in $REPOS; do case " $UEBERSPRINGEN " in *" $name "*) log " - $name: uebersprungen (Altlast)"; continue;; esac if checkout="$(finde_checkout "$name")"; then case " $NIE_ZIEHEN " in *" $name "*) log " = $name: Live-Deployment, kein Pull" verknuepfe "$checkout" "$name" continue;; esac if [ -n "$(git -C "$checkout" status --porcelain 2>/dev/null)" ]; then log " ! $name: lokale Aenderungen — uebersprungen (nichts ueberfahren)" verknuepfe "$checkout" "$name" continue fi if [ $DRY -eq 1 ]; then log " ~ $name: wuerde pullen (${checkout/$HOME/\~})" else vorher="$(git -C "$checkout" rev-parse --short HEAD 2>/dev/null)" if out="$(git -C "$checkout" pull --ff-only 2>&1)"; then nachher="$(git -C "$checkout" rev-parse --short HEAD 2>/dev/null)" if [ "$vorher" = "$nachher" ]; then log " = $name: aktuell ($vorher)" else log " + $name: $vorher -> $nachher" fi else log " ! $name: Pull fehlgeschlagen — $(printf '%s' "$out" | tail -1)" FEHLER=1 fi fi verknuepfe "$checkout" "$name" else if [ $DRY -eq 1 ]; then log " ~ $name: wuerde klonen nach ${ZIEL/$HOME/\~}/$name" elif out="$(git clone -q "$GITEA/Hitonabi/$name.git" "$ZIEL/$name" 2>&1)"; then log " + $name: neu geklont" else log " ! $name: Klonen fehlgeschlagen — $(printf '%s' "$out" | tail -1)" FEHLER=1 fi fi done log "=== Ende (Fehler: $FEHLER) ===" exit $FEHLER