161 lines
6.6 KiB
PowerShell
161 lines
6.6 KiB
PowerShell
# import-data.ps1
|
|
# Restores a database dump and .env config files from data_backup\<timestamp>\
|
|
#
|
|
# Prerequisites on the new PC before running this script:
|
|
# 1. Copy the project folder (or clone from git)
|
|
# 2. Copy the data_backup\<timestamp>\ folder into the project root
|
|
# 3. Start Postgres: cd infrastructure && docker compose up -d postgres redis
|
|
# 4. Run this script: .\import-data.ps1
|
|
# 5. After import: cd backend && npm install && npm run start:dev
|
|
# cd frontend && npm install && npm run dev
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$ProjectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$BackupRoot = Join-Path $ProjectRoot "data_backup"
|
|
|
|
Write-Host ""
|
|
Write-Host "=== StudioFlow Data Import ===" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# --- Pick a backup ------------------------------------------------------------
|
|
if (-not (Test-Path $BackupRoot)) {
|
|
Write-Error "No data_backup folder found. Copy it from the source PC first."
|
|
}
|
|
|
|
$Backups = Get-ChildItem $BackupRoot -Directory | Sort-Object Name -Descending
|
|
if ($Backups.Count -eq 0) {
|
|
Write-Error "data_backup folder is empty. Nothing to import."
|
|
}
|
|
|
|
Write-Host "Available backups:"
|
|
for ($i = 0; $i -lt $Backups.Count; $i++) {
|
|
$ManifestPath = Join-Path $Backups[$i].FullName "manifest.json"
|
|
$Extra = ""
|
|
if (Test-Path $ManifestPath) {
|
|
$M = Get-Content $ManifestPath -Raw | ConvertFrom-Json
|
|
$Extra = " (from $($M.machine), db: $($M.database.name))"
|
|
}
|
|
Write-Host " [$i] $($Backups[$i].Name)$Extra"
|
|
}
|
|
|
|
Write-Host ""
|
|
$Choice = Read-Host "Enter number to restore (press Enter for 0 = most recent)"
|
|
if ($Choice -eq "" -or $null -eq $Choice) { $Choice = 0 }
|
|
$BackupDir = $Backups[[int]$Choice].FullName
|
|
Write-Host "Restoring from: $BackupDir"
|
|
Write-Host ""
|
|
|
|
# --- Read manifest + credentials ----------------------------------------------
|
|
$ManifestFile = Join-Path $BackupDir "manifest.json"
|
|
if (-not (Test-Path $ManifestFile)) { Write-Error "manifest.json missing from backup." }
|
|
|
|
$Manifest = Get-Content $ManifestFile -Raw | ConvertFrom-Json
|
|
$DbName = $Manifest.database.name
|
|
$DbUser = $Manifest.database.user
|
|
$DbHost = $Manifest.database.host
|
|
$DbPort = $Manifest.database.port
|
|
|
|
$BackupEnvFile = Join-Path $BackupDir "backend.env"
|
|
if (-not (Test-Path $BackupEnvFile)) { Write-Error "backend.env missing from backup." }
|
|
|
|
$DbUrl = (Get-Content $BackupEnvFile | Where-Object { $_ -match "^DATABASE_URL=" }) -replace "^DATABASE_URL=",""
|
|
if ($DbUrl -match "postgresql://([^:]+):([^@]+)@") {
|
|
$DbPassword = $Matches[2]
|
|
} else {
|
|
Write-Error "Could not parse DATABASE_URL from backup backend.env"
|
|
}
|
|
|
|
Write-Host "Database : $DbName on ${DbHost}:${DbPort} as $DbUser"
|
|
|
|
$DumpFile = Join-Path $BackupDir "database.dump"
|
|
if (-not (Test-Path $DumpFile)) { Write-Error "database.dump missing from backup." }
|
|
|
|
# --- Detect running Postgres (Docker first, then local) -----------------------
|
|
$PgContainer = $null
|
|
if (Get-Command docker -ErrorAction SilentlyContinue) {
|
|
$Running = docker ps --format "{{.Names}}" 2>$null
|
|
if ($Running) {
|
|
$PgContainer = $Running | Where-Object { $_ -match "postgres" } | Select-Object -First 1
|
|
}
|
|
if (-not $PgContainer) {
|
|
$ByImage = docker ps --format "{{.Names}}|||{{.Image}}" 2>$null |
|
|
Where-Object { $_ -match "postgres" } |
|
|
ForEach-Object { ($_ -split "\|\|\|")[0] } |
|
|
Select-Object -First 1
|
|
$PgContainer = $ByImage
|
|
}
|
|
}
|
|
|
|
# --- Restore database ---------------------------------------------------------
|
|
if ($PgContainer) {
|
|
Write-Host "Using Docker container : $PgContainer"
|
|
|
|
Write-Host "Copying dump into container..."
|
|
docker cp $DumpFile "${PgContainer}:/tmp/studioflow_restore.dump"
|
|
|
|
Write-Host "Terminating existing connections..."
|
|
docker exec $PgContainer psql -U $DbUser -d postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DbName';" | Out-Null
|
|
|
|
Write-Host "Dropping and recreating database..."
|
|
docker exec $PgContainer psql -U $DbUser -d postgres -c "DROP DATABASE IF EXISTS $DbName;" | Out-Null
|
|
docker exec $PgContainer psql -U $DbUser -d postgres -c "CREATE DATABASE $DbName OWNER $DbUser;" | Out-Null
|
|
|
|
Write-Host "Restoring data (this may take a moment)..."
|
|
docker exec $PgContainer pg_restore -U $DbUser -d $DbName --no-owner --no-privileges /tmp/studioflow_restore.dump
|
|
if ($LASTEXITCODE -ne 0) { Write-Error "pg_restore inside Docker failed." }
|
|
|
|
docker exec $PgContainer rm /tmp/studioflow_restore.dump
|
|
Write-Host "Database restored via Docker." -ForegroundColor Green
|
|
|
|
} else {
|
|
Write-Host "No running Docker postgres found -- using local pg_restore"
|
|
$env:PGPASSWORD = $DbPassword
|
|
|
|
Write-Host "Terminating existing connections..."
|
|
psql -h $DbHost -p $DbPort -U $DbUser -d postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DbName';" | Out-Null
|
|
|
|
Write-Host "Dropping and recreating database..."
|
|
psql -h $DbHost -p $DbPort -U $DbUser -d postgres -c "DROP DATABASE IF EXISTS $DbName;" | Out-Null
|
|
psql -h $DbHost -p $DbPort -U $DbUser -d postgres -c "CREATE DATABASE $DbName OWNER $DbUser;" | Out-Null
|
|
|
|
Write-Host "Restoring data (this may take a moment)..."
|
|
pg_restore -h $DbHost -p $DbPort -U $DbUser -d $DbName --no-owner --no-privileges $DumpFile
|
|
if ($LASTEXITCODE -ne 0) { Write-Error "pg_restore failed." }
|
|
|
|
Remove-Item Env:\PGPASSWORD -ErrorAction SilentlyContinue
|
|
Write-Host "Database restored via local pg_restore." -ForegroundColor Green
|
|
}
|
|
|
|
# --- Restore .env files -------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host "Restoring config files..."
|
|
|
|
$EnvFiles = @(
|
|
@{ Src = "backend.env"; Dst = "backend\.env" }
|
|
@{ Src = "frontend.env.local"; Dst = "frontend\.env.local" }
|
|
@{ Src = "infrastructure.env"; Dst = "infrastructure\.env" }
|
|
)
|
|
|
|
foreach ($f in $EnvFiles) {
|
|
$Src = Join-Path $BackupDir $f.Src
|
|
$Dst = Join-Path $ProjectRoot $f.Dst
|
|
if (Test-Path $Src) {
|
|
$DstDir = Split-Path $Dst -Parent
|
|
if (-not (Test-Path $DstDir)) { New-Item -ItemType Directory -Path $DstDir -Force | Out-Null }
|
|
Copy-Item $Src $Dst -Force
|
|
Write-Host " Restored $($f.Dst)" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " Skipped $($f.Dst) (not in backup)" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
|
|
# --- Done ---------------------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host "Import complete!" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host "Next steps:"
|
|
Write-Host " cd backend && npm install && npm run start:dev"
|
|
Write-Host " (second terminal) cd backend && npx ts-node src/worker.ts"
|
|
Write-Host " cd frontend && npm install && npm run dev"
|
|
Write-Host ""
|