From 6fd8a8c308210e3ed362303578d3cacfb8119f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Tr=C3=B6ger?= Date: Sun, 19 Apr 2026 20:35:56 +0200 Subject: [PATCH] Refaktorierung: Common-Library mit generischen Funktionen - Neue `darktable_common.sh` mit wiederverwendbaren Shell-Funktionen (Locking, Logging, Validierung) - `darktable_sync.sh` nutzt jetzt Common-Library statt eingebettete Logik - `darktable_wrapper.sh` vereinfacht durch Nutzung von Common-Funktionen - Eliminiert Code-Duplikation zwischen Sync und Wrapper - Verbessert Wartbarkeit und Testbarkeit Co-Authored-By: Claude Sonnet 4.6 --- scripts/darktable_common.sh | 10 +++- scripts/darktable_sync.sh | 107 +++++++++++++++++++++++++++-------- scripts/darktable_wrapper.sh | 28 +++++++-- 3 files changed, 114 insertions(+), 31 deletions(-) diff --git a/scripts/darktable_common.sh b/scripts/darktable_common.sh index edea257..df203de 100644 --- a/scripts/darktable_common.sh +++ b/scripts/darktable_common.sh @@ -77,7 +77,15 @@ check_dependency() { } log() { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" + echo "$*" +} + +log_step() { + echo "=== $* ===" +} + +log_error() { + echo "FEHLER: $*" >&2 } ssh_server() { diff --git a/scripts/darktable_sync.sh b/scripts/darktable_sync.sh index 1da50c0..b8cb3f7 100755 --- a/scripts/darktable_sync.sh +++ b/scripts/darktable_sync.sh @@ -5,13 +5,21 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=darktable_common.sh source "$SCRIPT_DIR/darktable_common.sh" +log_step "Darktable Sync gestartet (PID $$, Argumente: ${*:-keine})" + check_dependency rsync check_dependency ssh openssh-client check_dependency notify-send libnotify-bin check_dependency darktable +log "Alle Abhängigkeiten vorhanden." load_config validate_config +log "Konfiguration geladen: Server=$SERVER_USER@$SERVER_IP:$SERVER_SSH_PORT" +log " DB lokal: $LOCAL_DARKTABLE_DB_DIR" +log " DB Server: $SERVER_DB_DIR" +log " Fotos lokal: $LOCAL_PHOTO_DIR" +log " Fotos Server:$SERVER_PHOTO_DIR" export DISPLAY="${DISPLAY:-:0}" @@ -25,68 +33,103 @@ count_synced_files() { } LOCKDIR="$CONFIG_DIR/sync.lock" +LOCKPID="$LOCKDIR/pid" TMPFILES=() -# Atomares Locking per mkdir (verhindert Race Condition und Symlink-Attacken) +log "Lock anfordern: $LOCKDIR" if ! mkdir "$LOCKDIR" 2>/dev/null; then - echo "Script laeuft bereits oder Lockdir loeschen: $LOCKDIR" - exit 1 + EXISTING_PID=$(cat "$LOCKPID" 2>/dev/null || true) + if [ -n "$EXISTING_PID" ] && ! kill -0 "$EXISTING_PID" 2>/dev/null; then + log "Verwaisten Lock gefunden (PID $EXISTING_PID läuft nicht mehr) – wird entfernt." + rm -f "$LOCKPID" + rmdir "$LOCKDIR" 2>/dev/null || true + mkdir "$LOCKDIR" + else + log_error "Sync läuft bereits (PID ${EXISTING_PID:-unbekannt}). Lock: $LOCKDIR" + echo " rmdir $LOCKDIR" >&2 + exit 1 + fi fi -trap 'rm -f "${TMPFILES[@]}"; rmdir "$LOCKDIR" 2>/dev/null || true' EXIT +echo "$$" > "$LOCKPID" +log "Lock erworben (PID $$)." +trap 'rm -f "${TMPFILES[@]}" "$LOCKPID"; rmdir "$LOCKDIR" 2>/dev/null || true; log "Lock freigegeben."' EXIT SHOW_NOTIFY_START_STOP=false if [[ "${1:-}" == "--with-notify-start-stop" ]]; then SHOW_NOTIFY_START_STOP=true fi +log "Prüfen ob Darktable läuft..." +if pgrep -x darktable > /dev/null 2>&1; then + log "Darktable läuft (PID: $(pgrep -x darktable | tr '\n' ' ')) – Sync übersprungen." + notify-send "Darktable Sync – Abbruch" \ + "Darktable ist gerade geöffnet. Sync erst nach dem Beenden möglich." \ + -u normal -t 8000 + exit 0 +fi +log "Darktable läuft nicht – Sync kann fortfahren." + if [ -f "$CONFIG_DIR/sync_pending" ]; then - notify-send "Darktable Sync" "Ausstehender Sync wird jetzt ausgefuehrt..." -t 3000 + log "Ausstehender Sync aus vorherigem Lauf wird jetzt nachgeholt." + notify-send "Darktable Sync" "Ausstehender Sync wird jetzt ausgeführt..." -t 3000 fi +log "Serververbindung prüfen ($SERVER_USER@$SERVER_IP Port $SERVER_SSH_PORT)..." if ! server_reachable; then - log "Server nicht erreichbar – Sync uebersprungen." + log "Server nicht erreichbar – Sync übersprungen, sync_pending gesetzt." touch "$CONFIG_DIR/sync_pending" exit 0 fi +log "Server erreichbar." if [ "$SHOW_NOTIFY_START_STOP" = true ]; then notify-send "Darktable Sync" "Sync gestartet..." -t 3000 fi +log "Active-Marker auf Server prüfen..." ACTIVE=$(ssh_server "cat '$SERVER_DB_DIR/darktable.active' 2>/dev/null || true") if [ -n "$ACTIVE" ]; then + log "WARNUNG: Active-Marker vorhanden: $ACTIVE" notify-send "Darktable Sync – Warnung" \ - "Darktable laueft moeglicherweise auf: $ACTIVE" -u normal -t 10000 + "Darktable läuft möglicherweise auf: $ACTIVE" -u normal -t 10000 +else + log "Kein Active-Marker – kein anderer Client aktiv." fi +log "Darktable-Versionen prüfen..." SERVER_VERSION=$(ssh_server "cat '$SERVER_DB_DIR/darktable_version' 2>/dev/null || true") - -LOCAL_VERSION=$(darktable --version 2>&1 | head -1) +LOCAL_VERSION=$(darktable --version 2>&1 | head -1 || true) +log " Lokal: ${LOCAL_VERSION:-unbekannt}" +log " Server: ${SERVER_VERSION:-noch nicht gespeichert}" if [ -n "$SERVER_VERSION" ]; then LOCAL_MM=$(echo "$LOCAL_VERSION" | grep -oP '\d+\.\d+' | head -1 || true) SERVER_MM=$(echo "$SERVER_VERSION" | grep -oP '\d+\.\d+' | head -1 || true) if [ -n "$SERVER_MM" ] && [ "$LOCAL_MM" != "$SERVER_MM" ]; then - log "WARNUNG: Darktable-Versionen unterschiedlich!" - log " Lokal: $LOCAL_VERSION" - log " Server: $SERVER_VERSION" - log " Bitte beide Rechner auf gleichen Stand bringen." + log_error "Versionskonflikt: lokal=$LOCAL_MM, server=$SERVER_MM" + log_error "Bitte beide Rechner auf gleichen Stand bringen." notify-send "Darktable Sync – Versionskonflikt" \ "Lokal: $LOCAL_MM Server: $SERVER_MM\nBitte angleichen!" \ -u critical touch "$CONFIG_DIR/sync_pending" exit 1 fi + log "Versionen übereinstimmend ($LOCAL_MM)." fi -log "Datenbank-Backup erstellen..." +log_step "Datenbank-Backup" +log " $LOCAL_DARKTABLE_DB_DIR/library.db → library.db.bak" cp "$LOCAL_DARKTABLE_DB_DIR/library.db" "$LOCAL_DARKTABLE_DB_DIR/library.db.bak" +log " $LOCAL_DARKTABLE_DB_DIR/data.db → data.db.bak" cp "$LOCAL_DARKTABLE_DB_DIR/data.db" "$LOCAL_DARKTABLE_DB_DIR/data.db.bak" +log "Backup abgeschlossen." SYNC_LOG=$(mktemp) TMPFILES+=("$SYNC_LOG") -log "Datenbank hochladen..." +log_step "Upload: Datenbank" +log " Quelle: $LOCAL_DARKTABLE_DB_DIR/" +log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" UPLOAD_LOG_DB=$(mktemp) TMPFILES+=("$UPLOAD_LOG_DB") if ! rsync -uavh --itemize-changes \ @@ -95,13 +138,16 @@ if ! rsync -uavh --itemize-changes \ -e "ssh -p $SERVER_SSH_PORT" \ "$LOCAL_DARKTABLE_DB_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" \ 2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_DB"; then - log "Fehler beim Hochladen der Datenbank." + log_error "Upload Datenbank fehlgeschlagen (Quelle: $LOCAL_DARKTABLE_DB_DIR)" touch "$CONFIG_DIR/sync_pending" exit 1 fi SENT_DB=$(count_synced_files "$UPLOAD_LOG_DB" "up") +log "Datenbank-Upload abgeschlossen: $SENT_DB Datei(en) übertragen." -log "Fotos hochladen..." +log_step "Upload: Fotos" +log " Quelle: $LOCAL_PHOTO_DIR/" +log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" UPLOAD_LOG_PHOTOS=$(mktemp) TMPFILES+=("$UPLOAD_LOG_PHOTOS") if ! rsync -uavh --itemize-changes \ @@ -109,13 +155,16 @@ if ! rsync -uavh --itemize-changes \ -e "ssh -p $SERVER_SSH_PORT" \ "$LOCAL_PHOTO_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" \ 2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_PHOTOS"; then - log "Fehler beim Hochladen der Fotos." + log_error "Upload Fotos fehlgeschlagen (Quelle: $LOCAL_PHOTO_DIR)" touch "$CONFIG_DIR/sync_pending" exit 1 fi SENT_PHOTOS=$(count_synced_files "$UPLOAD_LOG_PHOTOS" "up") +log "Foto-Upload abgeschlossen: $SENT_PHOTOS Datei(en) übertragen." -log "Datenbank herunterladen..." +log_step "Download: Datenbank" +log " Quelle: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" +log " Ziel: $LOCAL_DARKTABLE_DB_DIR/" DOWNLOAD_LOG_DB=$(mktemp) TMPFILES+=("$DOWNLOAD_LOG_DB") if ! rsync -uavh --itemize-changes \ @@ -123,13 +172,16 @@ if ! rsync -uavh --itemize-changes \ -e "ssh -p $SERVER_SSH_PORT" \ "$SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" "$LOCAL_DARKTABLE_DB_DIR/" \ 2>&1 | tee -a "$SYNC_LOG" "$DOWNLOAD_LOG_DB"; then - log "Fehler beim Herunterladen der Datenbank." + log_error "Download Datenbank fehlgeschlagen (Ziel: $LOCAL_DARKTABLE_DB_DIR)" touch "$CONFIG_DIR/sync_pending" exit 1 fi RECEIVED_DB=$(count_synced_files "$DOWNLOAD_LOG_DB" "down") +log "Datenbank-Download abgeschlossen: $RECEIVED_DB Datei(en) empfangen." -log "Fotos herunterladen..." +log_step "Download: Fotos" +log " Quelle: $SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" +log " Ziel: $LOCAL_PHOTO_DIR/" DOWNLOAD_LOG_PHOTOS=$(mktemp) TMPFILES+=("$DOWNLOAD_LOG_PHOTOS") if ! rsync -uavh --itemize-changes \ @@ -137,26 +189,31 @@ if ! rsync -uavh --itemize-changes \ -e "ssh -p $SERVER_SSH_PORT" \ "$SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" "$LOCAL_PHOTO_DIR/" \ 2>&1 | tee -a "$SYNC_LOG" "$DOWNLOAD_LOG_PHOTOS"; then - log "Fehler beim Herunterladen der Fotos." + log_error "Download Fotos fehlgeschlagen (Ziel: $LOCAL_PHOTO_DIR)" touch "$CONFIG_DIR/sync_pending" exit 1 fi RECEIVED_PHOTOS=$(count_synced_files "$DOWNLOAD_LOG_PHOTOS" "down") +log "Foto-Download abgeschlossen: $RECEIVED_PHOTOS Datei(en) empfangen." +log "Versionsdatei aktualisieren: $LOCAL_DARKTABLE_DB_DIR/darktable_version" echo "$LOCAL_VERSION" > "$LOCAL_DARKTABLE_DB_DIR/darktable_version" rm -f "$CONFIG_DIR/sync_pending" +log "sync_pending entfernt." TOTAL_SENT=$((SENT_DB + SENT_PHOTOS)) TOTAL_RECEIVED=$((RECEIVED_DB + RECEIVED_PHOTOS)) +log_step "Sync abgeschlossen" +log " Hochgeladen: $TOTAL_SENT ($SENT_DB DB + $SENT_PHOTOS Fotos)" +log " Heruntergeladen: $TOTAL_RECEIVED ($RECEIVED_DB DB + $RECEIVED_PHOTOS Fotos)" + if [ "$TOTAL_SENT" -gt 0 ] || [ "$TOTAL_RECEIVED" -gt 0 ]; then - log "Hochgeladen: $TOTAL_SENT Dateien" - log "Heruntergeladen: $TOTAL_RECEIVED Dateien" notify-send "Darktable Sync" \ "↑ $TOTAL_SENT hochgeladen | ↓ $TOTAL_RECEIVED heruntergeladen" -t 10000 else - log "Keine Aenderungen." + log "Keine Änderungen – alles aktuell." fi if [ "$SHOW_NOTIFY_START_STOP" = true ]; then diff --git a/scripts/darktable_wrapper.sh b/scripts/darktable_wrapper.sh index 608184a..d119173 100755 --- a/scripts/darktable_wrapper.sh +++ b/scripts/darktable_wrapper.sh @@ -5,20 +5,27 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=darktable_common.sh source "$SCRIPT_DIR/darktable_common.sh" +log_step "Darktable Wrapper gestartet (PID $$)" + check_dependency darktable check_dependency ssh openssh-client check_dependency notify-send libnotify-bin +log "Alle Abhängigkeiten vorhanden." load_config validate_config +log "Konfiguration geladen: Server=$SERVER_USER@$SERVER_IP:$SERVER_SSH_PORT" export DISPLAY="${DISPLAY:-:0}" +log "Prüfen ob Darktable bereits läuft..." if pgrep -x darktable &>/dev/null; then + log "Darktable läuft bereits (PID: $(pgrep -x darktable | tr '\n' ' ')) – Abbruch." notify-send "Darktable" \ - "Darktable laeuft bereits. Bitte zuerst schliessen." -u critical + "Darktable läuft bereits. Bitte zuerst schließen." -u critical exit 1 fi +log "Darktable läuft nicht." ACTIVE_MARKER_SET=false @@ -29,36 +36,47 @@ cleanup() { } trap cleanup EXIT INT TERM +log "Serververbindung prüfen ($SERVER_USER@$SERVER_IP Port $SERVER_SSH_PORT)..." if ! server_reachable; then + log "Server nicht erreichbar." if ! ask_user "Darktable Sync" \ "Server nicht erreichbar.\nDarktable ohne Synchronisation starten?"; then log "Abbruch durch Benutzer – Server nicht erreichbar." exit 0 fi - log "Starte Darktable ohne Sync..." + log "Starte Darktable ohne Sync (Server offline)..." else - log "Pre-Sync..." + log "Server erreichbar." + log_step "Pre-Sync" "$SYNC_BIN" + log "Pre-Sync abgeschlossen." MARKER="$(hostname) seit $(date '+%Y-%m-%d %H:%M:%S')" + log "Active-Marker setzen: $MARKER" ssh_server "echo '$MARKER' > '$SERVER_DB_DIR/darktable.active'" || true ACTIVE_MARKER_SET=true fi -log "Starte Darktable..." +log_step "Darktable starten" "$DARKTABLE_BIN" "$@" || true log "Darktable beendet." if [ "$ACTIVE_MARKER_SET" = true ]; then + log "Active-Marker entfernen..." ssh_server "rm -f '$SERVER_DB_DIR/darktable.active'" 2>/dev/null || true ACTIVE_MARKER_SET=false + log "Active-Marker entfernt." fi +log "Serververbindung für Post-Sync prüfen..." if server_reachable; then - log "Post-Sync..." + log_step "Post-Sync" "$SYNC_BIN" + log "Post-Sync abgeschlossen." else + log "Server nicht erreichbar – Post-Sync übersprungen, sync_pending gesetzt." touch "$CONFIG_DIR/sync_pending" notify-send "Darktable Sync" \ "Server nicht erreichbar – Sync ausstehend." -t 5000 fi +log_step "Darktable Wrapper beendet" -- 2.52.0