Files
lislgosms/tools/start-local.ps1
T

326 lines
9.7 KiB
PowerShell

param(
[switch]$SkipInfra,
[switch]$SkipMigrate,
[switch]$SkipApi,
[switch]$SkipWeb,
[switch]$WithGateway,
[switch]$OnlyMinio
)
$ErrorActionPreference = 'Stop'
$root = Resolve-Path (Join-Path $PSScriptRoot '..')
$logDir = Join-Path $root 'logs'
New-Item -ItemType Directory -Force -Path $logDir | Out-Null
function Test-CommandAvailable {
param([string]$Name)
return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
}
function Test-PortOpen {
param([int]$Port)
return [bool](Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue)
}
function Test-TcpPort {
param(
[string]$HostName,
[int]$Port
)
try {
$client = [System.Net.Sockets.TcpClient]::new()
$connect = $client.BeginConnect($HostName, $Port, $null, $null)
if (-not $connect.AsyncWaitHandle.WaitOne(1000)) {
$client.Close()
return $false
}
$client.EndConnect($connect)
$client.Close()
return $true
} catch {
return $false
}
}
function Start-LoggedProcess {
param(
[string]$Name,
[string]$FilePath,
[string[]]$ArgumentList,
[string]$WorkingDirectory,
[string]$OutLog,
[string]$ErrLog
)
Write-Host "Starting $Name..."
Start-Process `
-FilePath $FilePath `
-ArgumentList $ArgumentList `
-WorkingDirectory $WorkingDirectory `
-RedirectStandardOutput $OutLog `
-RedirectStandardError $ErrLog `
-WindowStyle Hidden | Out-Null
}
function Wait-ForTcpPort {
param(
[string]$Name,
[string]$HostName,
[int]$Port,
[int]$TimeoutSeconds = 20
)
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
while ((Get-Date) -lt $deadline) {
if (Test-TcpPort -HostName $HostName -Port $Port) {
Write-Host "$Name is listening on ${HostName}:$Port."
return $true
}
Start-Sleep -Milliseconds 500
}
Write-Host "$Name is not listening on ${HostName}:$Port after ${TimeoutSeconds}s."
return $false
}
function Find-LocalPostgresBin {
$candidates = @(
'C:\cmpp-platform-local\pgsql\bin',
'C:\cmpp-platform-local\PostgreSQL16\bin',
'C:\Program Files\PostgreSQL\16\bin'
)
foreach ($candidate in $candidates) {
if ((Test-Path (Join-Path $candidate 'pg_ctl.exe')) -and (Test-Path (Join-Path $candidate 'pg_isready.exe'))) {
return $candidate
}
}
$pgCtl = Get-Command 'pg_ctl.exe' -ErrorAction SilentlyContinue
if ($pgCtl) {
return Split-Path $pgCtl.Source -Parent
}
return $null
}
function Start-LocalPostgres {
if (Test-TcpPort -HostName '127.0.0.1' -Port 5432) {
Write-Host 'PostgreSQL is already reachable on 127.0.0.1:5432.'
return $true
}
$pgBin = Find-LocalPostgresBin
$pgData = 'C:\cmpp-platform-local\postgres-data'
if (-not $pgBin -or -not (Test-Path (Join-Path $pgData 'PG_VERSION'))) {
Write-Host 'PostgreSQL is not reachable and no local PostgreSQL data directory was found.'
Write-Host 'Expected Docker Compose or local data at C:\cmpp-platform-local\postgres-data.'
return $false
}
Write-Host "Starting local PostgreSQL from $pgData..."
& (Join-Path $pgBin 'pg_ctl.exe') -D $pgData -l (Join-Path $logDir 'postgres.log') start | Out-Host
Start-Sleep -Seconds 2
if (Test-Path (Join-Path $pgBin 'pg_isready.exe')) {
& (Join-Path $pgBin 'pg_isready.exe') -h 127.0.0.1 -p 5432 -U cmpp -d cmpp_platform | Out-Host
}
return (Wait-ForTcpPort -Name 'PostgreSQL' -HostName '127.0.0.1' -Port 5432 -TimeoutSeconds 30)
}
function Start-LocalRedis {
if (Test-TcpPort -HostName '127.0.0.1' -Port 6379) {
Write-Host 'Redis is already reachable on 127.0.0.1:6379.'
return $true
}
$redisServer = Get-Command 'redis-server' -ErrorAction SilentlyContinue
if (-not $redisServer) {
Write-Host 'Redis is not reachable and redis-server was not found in PATH.'
return $false
}
$redisDir = Join-Path $root '.local-data\redis'
New-Item -ItemType Directory -Force -Path $redisDir | Out-Null
Start-LoggedProcess `
-Name 'Redis' `
-FilePath $redisServer.Source `
-ArgumentList @('--port', '6379', '--dir', $redisDir, '--dbfilename', 'dump.rdb') `
-WorkingDirectory $root `
-OutLog (Join-Path $logDir 'redis.out.log') `
-ErrLog (Join-Path $logDir 'redis.err.log')
return (Wait-ForTcpPort -Name 'Redis' -HostName '127.0.0.1' -Port 6379 -TimeoutSeconds 15)
}
function Find-LocalMinio {
$candidates = @(
'C:\cmpp-platform-local\minio.exe',
'C:\cmpp-platform-local\minio\minio.exe'
)
foreach ($candidate in $candidates) {
if (Test-Path $candidate) {
return $candidate
}
}
$minio = Get-Command 'minio.exe' -ErrorAction SilentlyContinue
if ($minio) {
return $minio.Source
}
return $null
}
function Start-LocalMinio {
if ((Test-TcpPort -HostName '127.0.0.1' -Port 9000) -and (Test-TcpPort -HostName '127.0.0.1' -Port 9001)) {
Write-Host 'MinIO is already reachable on 127.0.0.1:9000/9001.'
return $true
}
$minio = Find-LocalMinio
if (-not $minio) {
Write-Host 'MinIO is not reachable and minio.exe was not found.'
Write-Host 'Expected minio.exe at C:\cmpp-platform-local\minio.exe or in PATH.'
return $false
}
$minioData = 'C:\cmpp-platform-local\minio-data'
New-Item -ItemType Directory -Force -Path $minioData | Out-Null
if (-not $env:MINIO_ROOT_USER) {
$env:MINIO_ROOT_USER = 'cmpp_minio'
}
if (-not $env:MINIO_ROOT_PASSWORD) {
$env:MINIO_ROOT_PASSWORD = 'cmpp_minio_password'
}
Start-LoggedProcess `
-Name 'MinIO' `
-FilePath $minio `
-ArgumentList @('server', $minioData, '--address', ':9000', '--console-address', ':9001') `
-WorkingDirectory (Split-Path $minio -Parent) `
-OutLog (Join-Path $logDir 'minio.out.log') `
-ErrLog (Join-Path $logDir 'minio.err.log')
$apiReady = Wait-ForTcpPort -Name 'MinIO API' -HostName '127.0.0.1' -Port 9000 -TimeoutSeconds 20
$consoleReady = Wait-ForTcpPort -Name 'MinIO Console' -HostName '127.0.0.1' -Port 9001 -TimeoutSeconds 20
return ($apiReady -and $consoleReady)
}
function Test-Minio {
if ((Test-TcpPort -HostName '127.0.0.1' -Port 9000) -and (Test-TcpPort -HostName '127.0.0.1' -Port 9001)) {
Write-Host 'MinIO ports 9000/9001 are reachable.'
return $true
}
Write-Host 'MinIO is not fully reachable on 9000/9001. File upload smoke may be blocked.'
return $false
}
Write-Host "CMPP local service startup"
Write-Host "Workspace: $root"
$minioReady = $false
if ($OnlyMinio) {
$minioReady = Start-LocalMinio
if (-not $minioReady) {
exit 1
}
Write-Host ''
Write-Host 'MinIO startup command issued. Useful URLs:'
Write-Host ' MinIO API: http://localhost:9000'
Write-Host ' MinIO Console: http://localhost:9001'
Write-Host ''
Write-Host "Logs: $logDir"
return
}
if (-not $SkipInfra) {
if (Test-CommandAvailable 'docker') {
Write-Host "Starting PostgreSQL, Redis and MinIO via Docker Compose..."
& docker compose -f (Join-Path $root 'infra/docker-compose.yml') up -d
Wait-ForTcpPort -Name 'PostgreSQL' -HostName '127.0.0.1' -Port 5432 -TimeoutSeconds 30 | Out-Null
Wait-ForTcpPort -Name 'Redis' -HostName '127.0.0.1' -Port 6379 -TimeoutSeconds 20 | Out-Null
$minioReady = Test-Minio
} else {
Write-Host "Docker CLI is not available. Trying local PostgreSQL and Redis fallback..."
Start-LocalPostgres | Out-Null
Start-LocalRedis | Out-Null
$minioReady = Start-LocalMinio
}
} else {
$minioReady = Test-Minio
}
if (-not $minioReady) {
$localObjectRoot = Join-Path $root '.local-data\object-storage'
New-Item -ItemType Directory -Force -Path $localObjectRoot | Out-Null
$env:OBJECT_STORAGE_DRIVER = 'local'
$env:OBJECT_STORAGE_LOCAL_ROOT = $localObjectRoot
Write-Host "Object storage fallback enabled: $localObjectRoot"
}
if (-not $SkipInfra -and -not $SkipMigrate -and (Test-TcpPort -HostName '127.0.0.1' -Port 5432)) {
Write-Host 'Applying Prisma migrations...'
& npm.cmd --prefix api run prisma:migrate:deploy
}
if (-not $SkipApi) {
if (Test-PortOpen 3000) {
Write-Host "API port 3000 is already listening; leaving the existing API process untouched."
} else {
Start-LoggedProcess `
-Name 'NestJS API' `
-FilePath 'npm.cmd' `
-ArgumentList @('--prefix', 'api', 'run', 'start:dev') `
-WorkingDirectory $root `
-OutLog (Join-Path $logDir 'api-dev.out.log') `
-ErrLog (Join-Path $logDir 'api-dev.err.log')
}
}
if (-not $SkipWeb) {
if ((Test-PortOpen 5173) -or (Test-PortOpen 4173) -or (Test-PortOpen 4174)) {
Write-Host "A frontend port is already listening on 5173/4173/4174; leaving the existing web process untouched."
} else {
Start-LoggedProcess `
-Name 'frontend preview' `
-FilePath 'npm.cmd' `
-ArgumentList @('run', 'dev') `
-WorkingDirectory $root `
-OutLog (Join-Path $logDir 'frontend-dev.out.log') `
-ErrLog (Join-Path $logDir 'frontend-dev.err.log')
}
}
if ($WithGateway) {
if (-not (Test-CommandAvailable 'go')) {
Write-Host "Go CLI is not available. Skipping gateway startup."
} elseif (Test-PortOpen 8090) {
Write-Host "Gateway health port 8090 is already listening; leaving the existing gateway process untouched."
} else {
Start-LoggedProcess `
-Name 'Go gateway' `
-FilePath 'go' `
-ArgumentList @('run', './cmd/gateway') `
-WorkingDirectory (Join-Path $root 'gateway') `
-OutLog (Join-Path $logDir 'gateway.out.log') `
-ErrLog (Join-Path $logDir 'gateway.err.log')
}
}
Write-Host ''
Write-Host 'Startup command issued. Useful URLs:'
Write-Host ' API: http://localhost:3000/api'
Write-Host ' Frontend: http://localhost:5173 or http://localhost:4173'
if ($minioReady) {
Write-Host ' MinIO: http://localhost:9001'
} else {
Write-Host ' MinIO: not running; using local object storage fallback when API is started by this script'
}
Write-Host ''
Write-Host "Logs: $logDir"