param( [string]$Version = "0.1.0", [string]$OutputDir = "$PSScriptRoot/dist/SimCAEServerDockerPackage", [switch]$SkipBuild, [switch]$SkipPull ) $ErrorActionPreference = "Stop" $serverDir = $PSScriptRoot $projectRoot = (Resolve-Path (Join-Path $serverDir "..")).Path $imageName = "simcae-update-server:$Version" $minioImage = "minio/minio:RELEASE.2025-04-22T22-12-26Z" $mcImage = "minio/mc:RELEASE.2025-04-16T18-13-26Z" $packageDir = $OutputDir $imagesDir = Join-Path $packageDir "images" $keysDir = Join-Path $packageDir "keys" $tarFile = Join-Path $imagesDir "simcae-server-all-images_$Version.tar" function Require-File($path, $message) { if (-not (Test-Path $path)) { throw $message } } Require-File (Join-Path $serverDir "Dockerfile") "server/Dockerfile is missing." Require-File (Join-Path $serverDir "docker-compose.image.yml") "server/docker-compose.image.yml is missing." Require-File (Join-Path $serverDir ".env.docker.example") "server/.env.docker.example is missing." Require-File (Join-Path $serverDir "keys/manifest_private_key.pem") "server/keys/manifest_private_key.pem is missing." Require-File (Join-Path $serverDir "keys/manifest_public_key.pem") "server/keys/manifest_public_key.pem is missing." if (-not $SkipBuild) { docker build -t $imageName -f (Join-Path $serverDir "Dockerfile") $projectRoot } if (-not $SkipPull) { docker pull $minioImage docker pull $mcImage } if (Test-Path $packageDir) { Remove-Item $packageDir -Recurse -Force } New-Item $imagesDir,$keysDir -ItemType Directory -Force | Out-Null Copy-Item (Join-Path $serverDir "docker-compose.image.yml") (Join-Path $packageDir "docker-compose.yml") -Force Copy-Item (Join-Path $serverDir ".env.docker.example") (Join-Path $packageDir ".env.example") -Force $readmeSource = Get-ChildItem $serverDir -File -Filter "*.md" | Where-Object { $_.Name -like "*Docker*.md" } | Select-Object -First 1 if ($readmeSource) { Copy-Item $readmeSource.FullName (Join-Path $packageDir "README.md") -Force } Copy-Item (Join-Path $serverDir "keys/manifest_private_key.pem") (Join-Path $keysDir "manifest_private_key.pem") -Force Copy-Item (Join-Path $serverDir "keys/manifest_public_key.pem") (Join-Path $keysDir "manifest_public_key.pem") -Force $quickReadme = @" # SimCAE Server Offline Docker Package 1. Copy this package to the target server and extract it. 2. Run: ./load-images.ps1 3. Edit .env and replace tokens, passwords, and SERVER_IP. 4. Run: docker compose up -d 5. Visit: http://SERVER_IP:8000/ Important: keys/manifest_private_key.pem is the server signing private key. Keep it secret. "@ $readmePath = Join-Path $packageDir "README.md" if (Test-Path $readmePath) { $oldReadme = Get-Content $readmePath -Raw -Encoding UTF8 Set-Content $readmePath ($quickReadme + "`n---`n`n" + $oldReadme) -Encoding UTF8 } else { Set-Content $readmePath $quickReadme -Encoding UTF8 } @" `$ErrorActionPreference = "Stop" docker load -i .\images\simcae-server-all-images_$Version.tar if (-not (Test-Path .\.env)) { Copy-Item .\.env.example .\.env Write-Host "Created .env from .env.example. Edit .env before starting services." } else { Write-Host ".env already exists. Keeping existing file." } Write-Host "Next: edit .env, then run: docker compose up -d" "@ | Set-Content (Join-Path $packageDir "load-images.ps1") -Encoding UTF8 $envExamplePath = Join-Path $packageDir ".env.example" $envText = Get-Content $envExamplePath -Raw -Encoding UTF8 $envText = $envText.Replace("SIMCAE_UPDATE_SERVER_IMAGE=simcae-update-server:0.1.0", "SIMCAE_UPDATE_SERVER_IMAGE=$imageName") Set-Content $envExamplePath $envText -Encoding UTF8 docker save -o $tarFile $imageName $minioImage $mcImage Compress-Archive -Path (Join-Path $packageDir "*") -DestinationPath "$packageDir.zip" -CompressionLevel Optimal -Force Write-Host "Offline package directory: $packageDir" Write-Host "Offline package zip: $packageDir.zip" Write-Host "Images tar: $tarFile"