258 lines
11 KiB
PowerShell
258 lines
11 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
Deployt GPLX MediaWiki auf den IONOS-Server.
|
||
|
||
.PARAMETER Mode
|
||
skin – Cavendish-Skin synchronisieren (schnell)
|
||
pages – Alle Wiki-Seiten aus scripts/templates/ auf Server pushen
|
||
db – Lokalen DB-Dump erstellen und auf Server importieren
|
||
all – Skin + Pages
|
||
initial – Erstinstallation: gesamten MediaWiki-Core übertragen
|
||
|
||
.EXAMPLE
|
||
.\deploy.ps1 # Skin deployen
|
||
.\deploy.ps1 -Mode pages # Alle Wiki-Seiten pushen
|
||
.\deploy.ps1 -Mode db # DB synchronisieren
|
||
.\deploy.ps1 -Mode all # Skin + Pages
|
||
.\deploy.ps1 -Mode initial
|
||
#>
|
||
param(
|
||
[ValidateSet('skin', 'pages', 'db', 'all', 'initial')]
|
||
[string]$Mode = 'skin'
|
||
)
|
||
|
||
Set-StrictMode -Version Latest
|
||
$ErrorActionPreference = 'Stop'
|
||
|
||
# ── Mapping: Dateiname in scripts/templates/ → Wiki-Seitentitel ──────────────
|
||
# Reihenfolge ist relevant: MediaWiki-Systemseiten zuerst, dann Templates,
|
||
# dann Inhaltsseiten.
|
||
$PAGE_MAP = [ordered]@{
|
||
'Sidebar.wiki' = 'MediaWiki:Sidebar'
|
||
'Common_js.wiki' = 'MediaWiki:Common.js'
|
||
'Editnotice_Advertisement.wiki' = 'MediaWiki:Editnotice-MediaWiki:Advertisement'
|
||
'Template_DocumentBox.wiki' = 'Template:DocumentBox'
|
||
'Template_ReferenceBox.wiki' = 'Template:ReferenceBox'
|
||
'Cat_Clinical.wiki' = 'Category:Clinical'
|
||
'Cat_EU_Regulation.wiki' = 'Category:EU Regulation'
|
||
'Cat_IVD.wiki' = 'Category:In Vitro Diagnostics'
|
||
'Cat_Labelling.wiki' = 'Category:Labelling'
|
||
'Cat_MedicalDevices.wiki' = 'Category:Medical Devices'
|
||
'Cat_PerformanceEvaluation.wiki' = 'Category:Performance Evaluation'
|
||
'Cat_PostMarket.wiki' = 'Category:Post-Market Surveillance'
|
||
'Cat_Traceability.wiki' = 'Category:Traceability'
|
||
'About_GxPlex.wiki' = 'About GxPlex'
|
||
'Contribute_to_GxPlex.wiki' = 'Contribute to GxPlex'
|
||
'Create_new_page.wiki' = 'Create new page'
|
||
'GxPlex_Search.wiki' = 'GxPlex Search'
|
||
'Help_Adding_a_topic.wiki' = 'Help:Adding a topic'
|
||
'Roadmap.wiki' = 'Development Roadmap'
|
||
'The_Project.wiki' = 'The Project'
|
||
'Themes_and_topics.wiki' = 'Themes and topics'
|
||
}
|
||
|
||
# ── .deploy.env laden ─────────────────────────────────────────────────────────
|
||
$envFile = Join-Path $PSScriptRoot '..' '.deploy.env'
|
||
if (-not (Test-Path $envFile)) {
|
||
Write-Error @"
|
||
.deploy.env nicht gefunden.
|
||
Kopiere .deploy.example.env zu .deploy.env und trage deine Zugangsdaten ein.
|
||
"@
|
||
exit 1
|
||
}
|
||
|
||
Get-Content $envFile | ForEach-Object {
|
||
if ($_ -match '^\s*([^#][^=]+)=(.*)$') {
|
||
[System.Environment]::SetEnvironmentVariable($Matches[1].Trim(), $Matches[2].Trim(), 'Process')
|
||
}
|
||
}
|
||
|
||
# Pflichtfelder prüfen
|
||
foreach ($var in @('DEPLOY_HOST', 'DEPLOY_USER', 'DEPLOY_MW_PATH', 'DEPLOY_PROJECT_PATH')) {
|
||
if (-not [System.Environment]::GetEnvironmentVariable($var, 'Process')) {
|
||
Write-Error "$var fehlt in .deploy.env."
|
||
exit 1
|
||
}
|
||
}
|
||
|
||
$deployHost = $env:DEPLOY_HOST
|
||
$deployUser = $env:DEPLOY_USER
|
||
$mwPath = $env:DEPLOY_MW_PATH
|
||
$projectPath = $env:DEPLOY_PROJECT_PATH
|
||
$serverPhp = if ($env:DEPLOY_PHP) { $env:DEPLOY_PHP } else { 'php' }
|
||
$mwUser = if ($env:DEPLOY_MW_USER) { $env:DEPLOY_MW_USER } else { 'Gxplex admin' }
|
||
$target = "${deployUser}@${deployHost}"
|
||
$repoRoot = Split-Path $PSScriptRoot
|
||
|
||
# ── Hilfsfunktionen ───────────────────────────────────────────────────────────
|
||
$hasWsl = $null -ne (Get-Command 'wsl' -ErrorAction SilentlyContinue)
|
||
|
||
function ConvertTo-WslPath([string]$winPath) {
|
||
$abs = [System.IO.Path]::GetFullPath($winPath)
|
||
$drive = $abs.Substring(0, 1).ToLower()
|
||
$rest = $abs.Substring(2).Replace('\', '/')
|
||
return "/mnt/$drive$rest"
|
||
}
|
||
|
||
function Sync-Dir([string]$localDir, [string]$remoteDir, [bool]$delete = $false) {
|
||
Write-Host " $localDir → ${target}:${remoteDir}" -ForegroundColor DarkGray
|
||
if ($hasWsl) {
|
||
$wslSrc = (ConvertTo-WslPath $localDir) + '/'
|
||
$rsyncArgs = @('-az', '--progress')
|
||
if ($delete) { $rsyncArgs += '--delete' }
|
||
$rsyncArgs += @($wslSrc, "${target}:${remoteDir}/")
|
||
wsl rsync @rsyncArgs
|
||
} else {
|
||
Write-Warning "WSL nicht gefunden – nutze scp."
|
||
ssh $target "mkdir -p '$remoteDir'"
|
||
scp -r "${localDir}\*" "${target}:${remoteDir}/"
|
||
}
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "Übertragung fehlgeschlagen (Exit $LASTEXITCODE)."; exit $LASTEXITCODE }
|
||
}
|
||
|
||
function Push-WikiPage([string]$remoteFile, [string]$title) {
|
||
# Titel für einfache Shell-Quoting escapen: einfache Anführungszeichen verdoppeln
|
||
$safeTitle = $title -replace "'", "'\"'\"'"
|
||
$cmd = "cat '$remoteFile' | $serverPhp $mwPath/maintenance/run.php edit --user '$mwUser' --summary 'Deploy' '$safeTitle' 2>&1"
|
||
$out = ssh $target $cmd
|
||
return $LASTEXITCODE -eq 0
|
||
}
|
||
|
||
# ── Deploy-Modi ───────────────────────────────────────────────────────────────
|
||
switch ($Mode) {
|
||
|
||
'skin' {
|
||
Write-Host "Deploye Cavendish-Skin..." -ForegroundColor Cyan
|
||
Sync-Dir "$repoRoot\mediawiki\skins\Cavendish" "$mwPath/skins/Cavendish" -delete $true
|
||
Write-Host "Fertig." -ForegroundColor Green
|
||
}
|
||
|
||
'pages' {
|
||
Write-Host "Deploye Wiki-Seiten ($($PAGE_MAP.Count) Seiten)..." -ForegroundColor Cyan
|
||
|
||
# 1. Template-Dateien auf Server synchronisieren
|
||
Write-Host "`n[1/2] Dateien übertragen..." -ForegroundColor DarkGray
|
||
Sync-Dir "$repoRoot\scripts\templates" "$projectPath/scripts/templates"
|
||
|
||
# 2. Jede Seite per Maintenance-Script einspielen
|
||
Write-Host "`n[2/2] Seiten pushen..." -ForegroundColor DarkGray
|
||
$ok = 0; $fail = 0; $skip = 0
|
||
|
||
foreach ($entry in $PAGE_MAP.GetEnumerator()) {
|
||
$localFile = Join-Path "$repoRoot\scripts\templates" $entry.Key
|
||
$remoteFile = "$projectPath/scripts/templates/$($entry.Key)"
|
||
$title = $entry.Value
|
||
|
||
if (-not (Test-Path $localFile)) {
|
||
Write-Host " SKIP $($entry.Key) (Datei nicht gefunden)" -ForegroundColor DarkYellow
|
||
$skip++
|
||
continue
|
||
}
|
||
|
||
Write-Host -NoNewline " → $title ... "
|
||
if (Push-WikiPage $remoteFile $title) {
|
||
Write-Host "OK" -ForegroundColor Green
|
||
$ok++
|
||
} else {
|
||
Write-Host "FEHLER" -ForegroundColor Red
|
||
$fail++
|
||
}
|
||
}
|
||
|
||
Write-Host ""
|
||
$color = if ($fail -eq 0) { 'Green' } else { 'Yellow' }
|
||
Write-Host "Ergebnis: $ok OK | $fail Fehler | $skip übersprungen" -ForegroundColor $color
|
||
}
|
||
|
||
'db' {
|
||
Write-Host "Synchronisiere Datenbank lokal → Server..." -ForegroundColor Cyan
|
||
|
||
# Konfiguration aus .deploy.env
|
||
$localDbName = if ($env:LOCAL_DB_NAME) { $env:LOCAL_DB_NAME } else { 'gflex_test' }
|
||
$localDump = if ($env:LOCAL_MYSQLDUMP) { $env:LOCAL_MYSQLDUMP } else { 'D:\xampp\mysql\bin\mysqldump.exe' }
|
||
$serverDbName = if ($env:DEPLOY_DB_NAME) { $env:DEPLOY_DB_NAME } else { 'gplx' }
|
||
$serverDbUser = if ($env:DEPLOY_DB_USER) { $env:DEPLOY_DB_USER } else { 'gplx' }
|
||
$serverDbPass = $env:DEPLOY_DB_PASS
|
||
|
||
if (-not $serverDbPass) {
|
||
Write-Error "DEPLOY_DB_PASS fehlt in .deploy.env."
|
||
exit 1
|
||
}
|
||
|
||
$dumpFile = Join-Path $env:TEMP "gplx_deploy_$(Get-Date -Format 'yyyyMMdd_HHmmss').sql"
|
||
|
||
# 1. Lokalen Dump erstellen
|
||
Write-Host "`n[1/3] Erstelle lokalen DB-Dump ($localDbName)..." -ForegroundColor DarkGray
|
||
& $localDump -u root $localDbName | Set-Content $dumpFile -Encoding UTF8
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "Dump fehlgeschlagen."; exit 1 }
|
||
$sizeMb = [math]::Round((Get-Item $dumpFile).Length / 1MB, 1)
|
||
Write-Host " Dump erstellt: $dumpFile ($sizeMb MB)"
|
||
|
||
# 2. Dump auf Server übertragen
|
||
Write-Host "`n[2/3] Übertrage Dump auf Server..." -ForegroundColor DarkGray
|
||
scp $dumpFile "${target}:/tmp/gplx_deploy.sql"
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "SCP fehlgeschlagen."; exit 1 }
|
||
|
||
# 3. Auf Server importieren (DB droppen + neu anlegen)
|
||
Write-Host "`n[3/3] Importiere auf Server (DB wird überschrieben)..." -ForegroundColor DarkGray
|
||
$importCmd = @"
|
||
mysql -u root <<'SQL'
|
||
DROP DATABASE IF EXISTS $serverDbName;
|
||
CREATE DATABASE $serverDbName CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
GRANT ALL PRIVILEGES ON $serverDbName.* TO '${serverDbUser}'@'localhost';
|
||
FLUSH PRIVILEGES;
|
||
SQL
|
||
mysql -u$serverDbUser -p$serverDbPass $serverDbName < /tmp/gplx_deploy.sql
|
||
cd $mwPath && $serverPhp maintenance/run.php update --quick
|
||
rm /tmp/gplx_deploy.sql
|
||
"@
|
||
ssh $target $importCmd
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "Import fehlgeschlagen."; exit 1 }
|
||
|
||
# Lokale Dump-Datei aufräumen
|
||
Remove-Item $dumpFile -Force
|
||
Write-Host "`nFertig. Datenbank wurde auf dem Server überschrieben." -ForegroundColor Green
|
||
Write-Host "Hinweis: LocalSettings.php auf dem Server muss ggf. angepasst werden." -ForegroundColor DarkYellow
|
||
}
|
||
|
||
'all' {
|
||
Write-Host "Deploye Skin + Wiki-Seiten..." -ForegroundColor Cyan
|
||
& $PSCommandPath -Mode skin
|
||
& $PSCommandPath -Mode pages
|
||
}
|
||
|
||
'initial' {
|
||
Write-Host "Erstinstallation – übertrage MediaWiki-Core..." -ForegroundColor Yellow
|
||
Write-Host "Das kann einige Minuten dauern." -ForegroundColor DarkGray
|
||
|
||
$excludes = @(
|
||
'--exclude=.git',
|
||
'--exclude=vendor/',
|
||
'--exclude=images/',
|
||
'--exclude=cache/',
|
||
'--exclude=LocalSettings.php'
|
||
)
|
||
|
||
if ($hasWsl) {
|
||
$wslSrc = (ConvertTo-WslPath "$repoRoot\mediawiki") + '/'
|
||
$rsyncArgs = @('-az', '--progress') + $excludes + @($wslSrc, "${target}:${mwPath}/")
|
||
wsl rsync @rsyncArgs
|
||
} else {
|
||
Write-Error "WSL ist für die Erstinstallation erforderlich (große Datenmenge). Bitte WSL installieren."
|
||
exit 1
|
||
}
|
||
|
||
if ($LASTEXITCODE -ne 0) { Write-Error "Übertragung fehlgeschlagen."; exit 1 }
|
||
|
||
Write-Host ""
|
||
Write-Host "Erstinstallation abgeschlossen." -ForegroundColor Green
|
||
Write-Host ""
|
||
Write-Host "Nächste Schritte auf dem Server:" -ForegroundColor Yellow
|
||
Write-Host " 1. LocalSettings.php hochladen: scp mediawiki/LocalSettings.php ${target}:${mwPath}/"
|
||
Write-Host " 2. Composer: ssh $target 'cd $mwPath && composer install --no-dev'"
|
||
Write-Host " 3. DB-Setup: php maintenance/run.php install ... (siehe Runbook)"
|
||
Write-Host " 4. SMW-Setup: php extensions/SemanticMediaWiki/maintenance/setupStore.php --nochecks"
|
||
Write-Host " 5. Seiten pushen: .\deploy.ps1 -Mode pages"
|
||
}
|
||
}
|