From 9db5217eeca5c93dc484c5736614880f7fa86c49 Mon Sep 17 00:00:00 2001 From: Rhino <1+rhino@noreply.gitea.rhino.nrw> Date: Sat, 20 Jun 2026 21:38:30 +0200 Subject: [PATCH] fix: Rollback auf ZIP-Snapshot (offline-faehig, kanonische Referenz) --- scripts/rollback.ps1 | 136 +++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/scripts/rollback.ps1 b/scripts/rollback.ps1 index 2884c69..debcf1f 100644 --- a/scripts/rollback.ps1 +++ b/scripts/rollback.ps1 @@ -1,97 +1,97 @@ # StatusQuo_Updates/scripts/rollback.ps1 -# Stellt den Stand vor dem letzten Update wieder her. -# Erwartet im aufrufenden Scope (wie update.ps1): -# $root - Installationspfad -# $stopBat - (optional) Stop-Skript-Dateiname oder '' -# $startBat - (optional) Start-Skript-Dateiname -$ErrorActionPreference = 'Stop' +# Kanonisches Rollback-Skript (Referenz). Die ausgelieferte rollback.bat enthaelt +# diese Logik EINGEBETTET und laeuft damit vollstaendig OFFLINE (kein Netz noetig). +# Erwartet im aufrufenden Scope: $root, $stopBat, $startBat +$ErrorActionPreference = 'Stop' +# Erwartet im Scope: $root, $stopBat, $startBat $_stopName = if ($null -ne $stopBat) { $stopBat } else { 'stop.bat' } $_startName = if ($null -ne $startBat) { $startBat } else { 'dgl.bat' } -# Verfügbare Backups suchen -$_backupBase = Join-Path $root '.backup' -if (-not (Test-Path -LiteralPath $_backupBase)) { - Write-Host "FEHLER: Kein Backup-Verzeichnis gefunden!" -ForegroundColor Red - Write-Host " Gesucht: $_backupBase" - Write-Host " Backups werden automatisch beim nächsten Update angelegt." +$bk = Join-Path $root '.backup' +if (-not (Test-Path -LiteralPath $bk)) { + Write-Host "Kein Backup-Verzeichnis gefunden. Sicherungen entstehen automatisch beim ersten Update." -ForegroundColor Red return } - -$_backups = Get-ChildItem -LiteralPath $_backupBase -Directory | - Where-Object { $_.Name -match '^\d{8}-\d{6}$' } | Sort-Object Name -Descending - -if ($_backups.Count -eq 0) { - Write-Host "FEHLER: Keine Backups vorhanden." -ForegroundColor Red - Write-Host " Backups werden automatisch beim nächsten Update angelegt." +$snaps = Get-ChildItem -LiteralPath $bk -Filter 'snapshot-*.zip' -ErrorAction SilentlyContinue | Sort-Object Name -Descending +if (-not $snaps) { + Write-Host "Keine Sicherungen vorhanden. Sicherungen entstehen automatisch beim ersten Update." -ForegroundColor Red return } Write-Host "" -Write-Host "Verfügbare Backups:" -ForegroundColor Cyan -$_i = 0 -foreach ($bk in $_backups) { - $suffix = if ($_i -eq 0) { " ← neuestes" } else { "" } - Write-Host (" [{0}] {1}{2}" -f $_i, $bk.Name, $suffix) - $_i++ +Write-Host "Verfügbare Sicherungen (neueste zuerst):" -ForegroundColor Cyan +$i = 0 +foreach ($s in $snaps) { + $size = '{0:N1} MB' -f ($s.Length / 1MB) + $tag = if ($i -eq 0) { " <- neueste" } else { "" } + Write-Host (" [{0}] {1} ({2}){3}" -f $i, $s.Name, $size, $tag) + $i++ } - Write-Host "" -$_choice = Read-Host "Backup-Nummer wählen (Enter = neuestes [0])" -if ($_choice -eq '') { $_choice = '0' } -if ($_choice -notmatch '^\d+$' -or [int]$_choice -ge $_backups.Count) { +$c = Read-Host "Nummer der Sicherung wählen (Enter = neueste [0])" +if ($c -eq '') { $c = '0' } +if ($c -notmatch '^\d+$' -or [int]$c -ge $snaps.Count) { Write-Host "Ungültige Auswahl. Abgebrochen." -ForegroundColor Yellow return } +$chosen = $snaps[[int]$c] +$zip = $chosen.FullName + +# Integrität der Sicherung prüfen, BEVOR irgendetwas ersetzt wird +Add-Type -AssemblyName System.IO.Compression.FileSystem +try { + $z = [System.IO.Compression.ZipFile]::OpenRead($zip) + $null = $z.Entries.Count + $z.Dispose() +} catch { + Write-Host "FEHLER: Sicherung ist beschädigt — Rollback abgebrochen: $zip" -ForegroundColor Red + return +} -$_selected = $_backups[[int]$_choice] Write-Host "" -Write-Host "Stelle wieder her: $($_selected.Name)" -ForegroundColor Yellow - -$yn = Read-Host "Rollback durchführen? Aktuelle Dateien werden überschrieben! [j/N]" +$yn = Read-Host "Stand '$($chosen.Name)' wiederherstellen? Der aktuelle Stand wird ersetzt! [j/N]" if ($yn -notin 'j','J','y','Y') { Write-Host "Abgebrochen."; return } # Server stoppen Write-Host "Stoppe Server ..." if ($_stopName -ne '') { - $_stopPath = Join-Path $root $_stopName - if (Test-Path -LiteralPath $_stopPath) { - & cmd /c "`"$_stopPath`"" - Start-Sleep -Seconds 2 - } else { - Write-Host " (Stop-Skript '$_stopName' nicht gefunden — übersprungen)" -ForegroundColor DarkYellow + $sp = Join-Path $root $_stopName + if (Test-Path -LiteralPath $sp) { & cmd /c "`"$sp`""; Start-Sleep -Seconds 2 } + else { Write-Host " (Stop-Skript '$_stopName' nicht gefunden — übersprungen)" -ForegroundColor DarkYellow } +} else { Write-Host " (Kein Stop-Skript konfiguriert — übersprungen)" -ForegroundColor DarkYellow } + +# Aktuellen Stand beiseite verschieben (Sicherheitsnetz, kein Datenverlust) +$aside = Join-Path $bk ("_vor-rollback-" + (Get-Date -Format 'yyyyMMdd-HHmmss')) +New-Item -ItemType Directory -Path $aside -Force | Out-Null +Get-ChildItem -LiteralPath $root -Force | Where-Object { $_.Name -ne '.backup' } | ForEach-Object { + Move-Item -LiteralPath $_.FullName -Destination (Join-Path $aside $_.Name) -Force +} + +# Sicherung wiederherstellen +try { + Expand-Archive -LiteralPath $zip -DestinationPath $root -Force + Write-Host "Stand wiederhergestellt: $($chosen.Name)" -ForegroundColor Green +} catch { + Write-Host "FEHLER beim Wiederherstellen — mache Änderung rückgängig ..." -ForegroundColor Red + Get-ChildItem -LiteralPath $root -Force | Where-Object { $_.Name -ne '.backup' } | + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + Get-ChildItem -LiteralPath $aside -Force | ForEach-Object { + Move-Item -LiteralPath $_.FullName -Destination (Join-Path $root $_.Name) -Force } -} else { - Write-Host " (Kein Stop-Skript konfiguriert — übersprungen)" -ForegroundColor DarkYellow + Write-Host "Vorheriger Zustand wiederhergestellt — kein Datenverlust." -ForegroundColor Yellow + return } -# Nutzerdaten wiederherstellen -$_dataBackup = Join-Path $_selected.FullName 'data' -if (Test-Path -LiteralPath $_dataBackup) { - $dataTarget = Join-Path $root 'data' - if (Test-Path -LiteralPath $dataTarget) { - # Aktuellen data/-Ordner vor Überschreiben sichern - $safeName = "data_vor_rollback_$(Get-Date -Format 'yyyyMMdd-HHmmss')" - Rename-Item -LiteralPath $dataTarget -NewName $safeName -ErrorAction SilentlyContinue - } - Copy-Item -Path $_dataBackup -Destination $dataTarget -Recurse -Force - $dataCount = (Get-ChildItem -LiteralPath $dataTarget -Recurse -File -ErrorAction SilentlyContinue).Count - Write-Host "Nutzerdaten wiederhergestellt ($dataCount Dateien)." -ForegroundColor Green -} else { - Write-Host " (Kein Nutzerdaten-Backup in diesem Stand)" -ForegroundColor DarkYellow -} +# Beiseite-Ordner aufräumen: nur die letzten 2 behalten +Get-ChildItem -LiteralPath $bk -Directory -Filter '_vor-rollback-*' -ErrorAction SilentlyContinue | + Sort-Object Name -Descending | Select-Object -Skip 2 | + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -# Code-Dateien wiederherstellen -$_codeFiles = Get-ChildItem -LiteralPath $_selected.FullName -File -ErrorAction SilentlyContinue -foreach ($f in $_codeFiles) { - Copy-Item -Path $f.FullName -Destination (Join-Path $root $f.Name) -Force -} -Write-Host "Code-Dateien wiederhergestellt ($($_codeFiles.Count) Dateien)." -ForegroundColor Green - -# Server neu starten -$_startPath = Join-Path $root $_startName -if (Test-Path -LiteralPath $_startPath) { - Start-Process -FilePath 'cmd.exe' -ArgumentList "/c `"$_startPath`"" -WindowStyle Hidden +# Server starten +$stp = Join-Path $root $_startName +if (Test-Path -LiteralPath $stp) { + Start-Process -FilePath 'cmd.exe' -ArgumentList "/c `"$stp`"" -WindowStyle Hidden Write-Host "Server gestartet." -ForegroundColor Green } else { Write-Host "Start-Skript '$_startName' nicht gefunden — bitte Server manuell starten." -ForegroundColor Yellow @@ -99,4 +99,4 @@ if (Test-Path -LiteralPath $_startPath) { Write-Host "" Write-Host "=== Rollback abgeschlossen ===" -ForegroundColor Green -Write-Host " Wiederhergestellt: $($_selected.Name)" -ForegroundColor Cyan +Write-Host " Wiederhergestellt: $($chosen.Name)" -ForegroundColor Cyan