# ============================================================================== # lf_mri_platform -- Pull latest code and rebuild services # Usage: # .\update.ps1 -- git pull + rebuild all containers # .\update.ps1 -Services o,s -- rebuild only listed services (comma-separated) # .\update.ps1 -SkipGit -- skip git pull (only rebuild) # .\update.ps1 -RestartSpec -- also restart the native spectrometer # ============================================================================== param( [string]$Services = "", # e.g. "orchestrator,seq-interp" [switch]$SkipGit, [switch]$RestartSpec ) $ErrorActionPreference = "Stop" $Root = $PSScriptRoot $EnvFile = Join-Path $Root ".env" function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan } function Write-OK($msg) { Write-Host " [OK] $msg" -ForegroundColor Green } function Write-Warn($msg) { Write-Host " [!!] $msg" -ForegroundColor Yellow } function Write-Fail($msg) { Write-Host "`n[FAIL] $msg" -ForegroundColor Red Write-Host "`n Press Enter to close..." -ForegroundColor DarkGray $null = Read-Host exit 1 } trap { Write-Host "`n[ERROR] $_" -ForegroundColor Red Write-Host "`n Press Enter to close..." -ForegroundColor DarkGray $null = Read-Host exit 1 } # -- 1. Git pull --------------------------------------------------------------- if (-not $SkipGit) { Write-Step "Pulling latest code" Push-Location $Root try { $before = & git rev-parse HEAD 2>$null & git pull if ($LASTEXITCODE -ne 0) { Write-Fail "git pull failed" } $after = & git rev-parse HEAD 2>$null if ($before -eq $after) { Write-OK "Already up to date ($($after.Substring(0,8)))" } else { Write-OK "Updated $($before.Substring(0,8)) -> $($after.Substring(0,8))" Write-Host "" & git log --oneline "$before..$after" } } finally { Pop-Location } } # -- 2. Check Docker ----------------------------------------------------------- Write-Step "Checking Docker" try { & docker info *>$null } catch { Write-Fail "Docker is not running. Start Docker Desktop and try again." } Write-OK "Docker is running" # -- 3. Rebuild containers ----------------------------------------------------- Write-Step "Rebuilding containers" $envArgs = if (Test-Path $EnvFile) { @("--env-file", $EnvFile) } else { @() } if ($Services) { $svcList = $Services -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ } Write-Host " Services: $($svcList -join ', ')" -ForegroundColor DarkGray & docker compose @envArgs up --build -d @svcList } else { Write-Host " Services: all" -ForegroundColor DarkGray & docker compose @envArgs up --build -d } if ($LASTEXITCODE -ne 0) { Write-Fail "docker compose up --build failed" } Write-OK "Containers rebuilt and started" # -- 4. Optionally restart the native spectrometer ---------------------------- if ($RestartSpec) { Write-Step "Restarting native spectrometer" $specProc = Get-Process -Name python* -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -like "*manage.py*runserver*" } if ($specProc) { Write-Host " Stopping old spectrometer process (PID $($specProc.Id))..." -ForegroundColor DarkGray Stop-Process -Id $specProc.Id -Force Start-Sleep 1 Write-OK "Old process stopped" } else { Write-Warn "No running spectrometer process found -- will start fresh" } $specDir = Join-Path $Root "services\spectrometer" $python = "python" # Try project venv first $venvPy = Join-Path $Root "apps\gui\.venv\Scripts\python.exe" if (Test-Path $venvPy) { $python = $venvPy } Write-Host " Starting spectrometer at $specDir ..." -ForegroundColor DarkGray Start-Process $python ` -ArgumentList "manage.py runserver 0.0.0.0:8000" ` -WorkingDirectory $specDir ` -WindowStyle Normal Write-OK "Spectrometer started in new window" } # -- 5. Health check ----------------------------------------------------------- Write-Step "Checking service health" function Get-EnvPort($key, $default) { if (Test-Path $EnvFile) { $line = Get-Content $EnvFile | Select-String "^$key=(\d+)" if ($line) { return $line.Matches[0].Groups[1].Value } } return $default } $checks = @( @{ Name = "Orchestrator"; Url = "http://localhost:$(Get-EnvPort 'ORCHESTRATOR_PORT' '1717')/health"; Native = $false }, @{ Name = "Seq-Interp"; Url = "http://localhost:$(Get-EnvPort 'SEQ_INTERP_PORT' '7475')/health"; Native = $false }, @{ Name = "Spectroscopy"; Url = "http://localhost:$(Get-EnvPort 'SPECTROSCOPY_PORT' '8002')/health"; Native = $false }, @{ Name = "Spectrometer*"; Url = "http://localhost:$(Get-EnvPort 'SPECTROMETER_PORT' '8000')/api/"; Native = $true } ) function Test-Port($url) { try { $uri = [System.Uri]$url $port = if ($uri.Port -gt 0) { $uri.Port } else { 80 } $tcp = New-Object System.Net.Sockets.TcpClient $ar = $tcp.BeginConnect($uri.Host, $port, $null, $null) $ok = $ar.AsyncWaitHandle.WaitOne(1500, $false) try { $tcp.Close() } catch {} return $ok } catch { return $false } } $maxWait = 60; $interval = 3; $elapsed = 0 while ($elapsed -lt $maxWait) { $pending = @() foreach ($c in $checks) { if ($c.Native) { continue } # native services not waited on if (-not (Test-Port $c.Url)) { $pending += $c.Name } } if ($pending.Count -eq 0) { break } Write-Host (" ... {0}/{1} s waiting: {2}" -f $elapsed, $maxWait, ($pending -join ", ")) -ForegroundColor DarkGray Start-Sleep $interval; $elapsed += $interval } Write-Host "" foreach ($c in $checks) { $ok = Test-Port $c.Url $icon = if ($ok) { "[OK]" } else { "[--]" } $color = if ($ok) { "Green" } elseif ($c.Native) { "DarkGray" } else { "Yellow" } $suffix = if ($c.Native) { " (native -- start manually if needed)" } else { "" } Write-Host (" {0,-6} {1,-16} {2}{3}" -f $icon, $c.Name, $c.Url, $suffix) -ForegroundColor $color } # -- 6. Summary ---------------------------------------------------------------- Write-Host "" Write-Host "============================================================" -ForegroundColor Green Write-Host " Update complete" -ForegroundColor Green Write-Host "============================================================" -ForegroundColor Green Write-Host "" Write-Host " To rebuild only specific services next time:" Write-Host " .\update.ps1 -Services orchestrator,seq-interp" Write-Host "" Write-Host " To also restart the native spectrometer:" Write-Host " .\update.ps1 -RestartSpec" Write-Host "" Write-Host " Press Enter to close this window..." -ForegroundColor DarkGray $null = Read-Host