update.ps1 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. # ==============================================================================
  2. # lf_mri_platform -- Pull latest code and rebuild services
  3. # Usage:
  4. # .\update.ps1 -- git pull + rebuild all containers
  5. # .\update.ps1 -Services o,s -- rebuild only listed services (comma-separated)
  6. # .\update.ps1 -SkipGit -- skip git pull (only rebuild)
  7. # .\update.ps1 -RestartSpec -- also restart the native spectrometer
  8. # ==============================================================================
  9. param(
  10. [string]$Services = "", # e.g. "orchestrator,seq-interp"
  11. [switch]$SkipGit,
  12. [switch]$RestartSpec
  13. )
  14. $ErrorActionPreference = "Stop"
  15. $Root = $PSScriptRoot
  16. $EnvFile = Join-Path $Root ".env"
  17. function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan }
  18. function Write-OK($msg) { Write-Host " [OK] $msg" -ForegroundColor Green }
  19. function Write-Warn($msg) { Write-Host " [!!] $msg" -ForegroundColor Yellow }
  20. function Write-Fail($msg) {
  21. Write-Host "`n[FAIL] $msg" -ForegroundColor Red
  22. Write-Host "`n Press Enter to close..." -ForegroundColor DarkGray
  23. $null = Read-Host
  24. exit 1
  25. }
  26. trap {
  27. Write-Host "`n[ERROR] $_" -ForegroundColor Red
  28. Write-Host "`n Press Enter to close..." -ForegroundColor DarkGray
  29. $null = Read-Host
  30. exit 1
  31. }
  32. # -- 1. Git pull ---------------------------------------------------------------
  33. if (-not $SkipGit) {
  34. Write-Step "Pulling latest code"
  35. Push-Location $Root
  36. try {
  37. $before = & git rev-parse HEAD 2>$null
  38. & git pull
  39. if ($LASTEXITCODE -ne 0) { Write-Fail "git pull failed" }
  40. $after = & git rev-parse HEAD 2>$null
  41. if ($before -eq $after) {
  42. Write-OK "Already up to date ($($after.Substring(0,8)))"
  43. } else {
  44. Write-OK "Updated $($before.Substring(0,8)) -> $($after.Substring(0,8))"
  45. Write-Host ""
  46. & git log --oneline "$before..$after"
  47. }
  48. } finally {
  49. Pop-Location
  50. }
  51. }
  52. # -- 2. Check Docker -----------------------------------------------------------
  53. Write-Step "Checking Docker"
  54. try { & docker info *>$null } catch {
  55. Write-Fail "Docker is not running. Start Docker Desktop and try again."
  56. }
  57. Write-OK "Docker is running"
  58. # -- 3. Rebuild containers -----------------------------------------------------
  59. Write-Step "Rebuilding containers"
  60. $envArgs = if (Test-Path $EnvFile) { @("--env-file", $EnvFile) } else { @() }
  61. if ($Services) {
  62. $svcList = $Services -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ }
  63. Write-Host " Services: $($svcList -join ', ')" -ForegroundColor DarkGray
  64. & docker compose @envArgs up --build -d @svcList
  65. } else {
  66. Write-Host " Services: all" -ForegroundColor DarkGray
  67. & docker compose @envArgs up --build -d
  68. }
  69. if ($LASTEXITCODE -ne 0) { Write-Fail "docker compose up --build failed" }
  70. Write-OK "Containers rebuilt and started"
  71. # -- 4. Optionally restart the native spectrometer ----------------------------
  72. if ($RestartSpec) {
  73. Write-Step "Restarting native spectrometer"
  74. $specProc = Get-Process -Name python* -ErrorAction SilentlyContinue |
  75. Where-Object { $_.CommandLine -like "*manage.py*runserver*" }
  76. if ($specProc) {
  77. Write-Host " Stopping old spectrometer process (PID $($specProc.Id))..." -ForegroundColor DarkGray
  78. Stop-Process -Id $specProc.Id -Force
  79. Start-Sleep 1
  80. Write-OK "Old process stopped"
  81. } else {
  82. Write-Warn "No running spectrometer process found -- will start fresh"
  83. }
  84. $specDir = Join-Path $Root "services\spectrometer"
  85. $python = "python"
  86. # Try project venv first
  87. $venvPy = Join-Path $Root "apps\gui\.venv\Scripts\python.exe"
  88. if (Test-Path $venvPy) { $python = $venvPy }
  89. Write-Host " Starting spectrometer at $specDir ..." -ForegroundColor DarkGray
  90. Start-Process $python `
  91. -ArgumentList "manage.py runserver 0.0.0.0:8000" `
  92. -WorkingDirectory $specDir `
  93. -WindowStyle Normal
  94. Write-OK "Spectrometer started in new window"
  95. }
  96. # -- 5. Health check -----------------------------------------------------------
  97. Write-Step "Checking service health"
  98. function Get-EnvPort($key, $default) {
  99. if (Test-Path $EnvFile) {
  100. $line = Get-Content $EnvFile | Select-String "^$key=(\d+)"
  101. if ($line) { return $line.Matches[0].Groups[1].Value }
  102. }
  103. return $default
  104. }
  105. $checks = @(
  106. @{ Name = "Orchestrator"; Url = "http://localhost:$(Get-EnvPort 'ORCHESTRATOR_PORT' '1717')/health"; Native = $false },
  107. @{ Name = "Seq-Interp"; Url = "http://localhost:$(Get-EnvPort 'SEQ_INTERP_PORT' '7475')/health"; Native = $false },
  108. @{ Name = "Spectroscopy"; Url = "http://localhost:$(Get-EnvPort 'SPECTROSCOPY_PORT' '8002')/health"; Native = $false },
  109. @{ Name = "Spectrometer*"; Url = "http://localhost:$(Get-EnvPort 'SPECTROMETER_PORT' '8000')/api/"; Native = $true }
  110. )
  111. function Test-Port($url) {
  112. try {
  113. $uri = [System.Uri]$url
  114. $port = if ($uri.Port -gt 0) { $uri.Port } else { 80 }
  115. $tcp = New-Object System.Net.Sockets.TcpClient
  116. $ar = $tcp.BeginConnect($uri.Host, $port, $null, $null)
  117. $ok = $ar.AsyncWaitHandle.WaitOne(1500, $false)
  118. try { $tcp.Close() } catch {}
  119. return $ok
  120. } catch { return $false }
  121. }
  122. $maxWait = 60; $interval = 3; $elapsed = 0
  123. while ($elapsed -lt $maxWait) {
  124. $pending = @()
  125. foreach ($c in $checks) {
  126. if ($c.Native) { continue } # native services not waited on
  127. if (-not (Test-Port $c.Url)) { $pending += $c.Name }
  128. }
  129. if ($pending.Count -eq 0) { break }
  130. Write-Host (" ... {0}/{1} s waiting: {2}" -f $elapsed, $maxWait, ($pending -join ", ")) -ForegroundColor DarkGray
  131. Start-Sleep $interval; $elapsed += $interval
  132. }
  133. Write-Host ""
  134. foreach ($c in $checks) {
  135. $ok = Test-Port $c.Url
  136. $icon = if ($ok) { "[OK]" } else { "[--]" }
  137. $color = if ($ok) { "Green" } elseif ($c.Native) { "DarkGray" } else { "Yellow" }
  138. $suffix = if ($c.Native) { " (native -- start manually if needed)" } else { "" }
  139. Write-Host (" {0,-6} {1,-16} {2}{3}" -f $icon, $c.Name, $c.Url, $suffix) -ForegroundColor $color
  140. }
  141. # -- 6. Summary ----------------------------------------------------------------
  142. Write-Host ""
  143. Write-Host "============================================================" -ForegroundColor Green
  144. Write-Host " Update complete" -ForegroundColor Green
  145. Write-Host "============================================================" -ForegroundColor Green
  146. Write-Host ""
  147. Write-Host " To rebuild only specific services next time:"
  148. Write-Host " .\update.ps1 -Services orchestrator,seq-interp"
  149. Write-Host ""
  150. Write-Host " To also restart the native spectrometer:"
  151. Write-Host " .\update.ps1 -RestartSpec"
  152. Write-Host ""
  153. Write-Host " Press Enter to close this window..." -ForegroundColor DarkGray
  154. $null = Read-Host