154 lines
4.3 KiB
PowerShell
154 lines
4.3 KiB
PowerShell
# Shared config — project DB always lives in data/postgres on port 54320
|
|
$script:LocalDbPort = 54320
|
|
$script:LocalDbUser = 'eee_admin'
|
|
$script:LocalDbPassword = 'eee_password'
|
|
$script:LocalDbName = 'eee_dashboard'
|
|
|
|
function Get-ProjectRoot {
|
|
param([string]$FromScript = $PSScriptRoot)
|
|
return (Resolve-Path (Join-Path $FromScript '..')).Path
|
|
}
|
|
|
|
function Get-PgDataDir {
|
|
param([string]$Root)
|
|
return Join-Path $Root 'data\postgres'
|
|
}
|
|
|
|
function Get-PgCtlLogPath {
|
|
param([string]$Root)
|
|
return Join-Path $Root 'data\pg_ctl.log'
|
|
}
|
|
|
|
function Find-PgBin {
|
|
$cmd = Get-Command initdb -ErrorAction SilentlyContinue
|
|
if ($cmd) { return (Split-Path $cmd.Path -Parent) }
|
|
|
|
$candidates = @(
|
|
'C:\Program Files\PostgreSQL\16\bin',
|
|
'C:\Program Files\PostgreSQL\15\bin',
|
|
'C:\Program Files\PostgreSQL\14\bin'
|
|
)
|
|
foreach ($dir in $candidates) {
|
|
if (Test-Path (Join-Path $dir 'initdb.exe')) { return $dir }
|
|
}
|
|
return $null
|
|
}
|
|
|
|
function Test-DbPortOpen {
|
|
param([int]$Port = $script:LocalDbPort)
|
|
$client = $null
|
|
try {
|
|
$client = New-Object System.Net.Sockets.TcpClient
|
|
$connect = $client.BeginConnect('127.0.0.1', $Port, $null, $null)
|
|
if (-not $connect.AsyncWaitHandle.WaitOne(500, $false)) { return $false }
|
|
$client.EndConnect($connect)
|
|
return $client.Connected
|
|
} catch {
|
|
return $false
|
|
} finally {
|
|
if ($client) { $client.Dispose() }
|
|
}
|
|
}
|
|
|
|
function Clear-StalePostmasterLock {
|
|
param([string]$PgData)
|
|
$pidFile = Join-Path $PgData 'postmaster.pid'
|
|
if (-not (Test-Path $pidFile)) { return }
|
|
|
|
$firstLine = Get-Content $pidFile -TotalCount 1 -ErrorAction SilentlyContinue
|
|
$oldPid = 0
|
|
[void][int]::TryParse($firstLine, [ref]$oldPid)
|
|
|
|
$alive = $false
|
|
if ($oldPid -gt 0) {
|
|
$proc = Get-Process -Id $oldPid -ErrorAction SilentlyContinue
|
|
if ($proc -and $proc.ProcessName -match 'postgres') { $alive = $true }
|
|
}
|
|
|
|
if (-not $alive) {
|
|
Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
|
|
Write-Host ' Cleared stale postmaster.pid (folder moved or crash)'
|
|
}
|
|
}
|
|
|
|
function Get-DatabaseUrl {
|
|
return "postgresql://$($script:LocalDbUser):$($script:LocalDbPassword)@localhost:$($script:LocalDbPort)/$($script:LocalDbName)"
|
|
}
|
|
|
|
function Set-EnvLine {
|
|
param(
|
|
[string]$Content,
|
|
[string]$Key,
|
|
[string]$Value
|
|
)
|
|
$pattern = "(?m)^$Key="
|
|
$line = "$Key=`"$Value`""
|
|
if ($Content -match $pattern) {
|
|
return ($Content -replace "(?m)^$Key=.*$", $line)
|
|
}
|
|
return "$line`r`n$Content"
|
|
}
|
|
|
|
function Ensure-BackendEnv {
|
|
param([string]$Root)
|
|
|
|
$envPath = Join-Path $Root 'backend\.env'
|
|
$examplePath = Join-Path $Root 'backend\.env.example'
|
|
if (-not (Test-Path $envPath)) {
|
|
Copy-Item $examplePath $envPath
|
|
}
|
|
|
|
$url = Get-DatabaseUrl
|
|
$content = Get-Content $envPath -Raw -Encoding UTF8
|
|
$content = Set-EnvLine $content 'DATABASE_URL' $url
|
|
$content = Set-EnvLine $content 'HR_DATA_PATH' '../data/seed/hr-data.json'
|
|
$content = Set-EnvLine $content 'UPLOAD_DIR' '../uploads'
|
|
Set-Content -Path $envPath -Value $content.TrimEnd() -Encoding UTF8 -NoNewline
|
|
Add-Content -Path $envPath -Value '' -Encoding UTF8
|
|
}
|
|
|
|
function Set-PostgresPort {
|
|
param(
|
|
[string]$PgData,
|
|
[int]$Port = $script:LocalDbPort
|
|
)
|
|
$auto = Join-Path $PgData 'postgresql.auto.conf'
|
|
$wanted = @{
|
|
'port' = "port = $Port"
|
|
'logging_collector' = 'logging_collector = off'
|
|
}
|
|
$existing = @()
|
|
if (Test-Path $auto) {
|
|
$existing = @(Get-Content $auto -Encoding UTF8 -ErrorAction SilentlyContinue)
|
|
}
|
|
foreach ($key in $wanted.Keys) {
|
|
$line = $wanted[$key]
|
|
$found = $false
|
|
$existing = @($existing | ForEach-Object {
|
|
if ($_ -match "^\s*$key\s*=") { $found = $true; $line } else { $_ }
|
|
})
|
|
if (-not $found) { $existing += $line }
|
|
}
|
|
$utf8 = New-Object System.Text.UTF8Encoding $false
|
|
[System.IO.File]::WriteAllLines($auto, $existing, $utf8)
|
|
}
|
|
|
|
function Test-DockerReady {
|
|
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { return $false }
|
|
docker info 2>$null | Out-Null
|
|
return ($LASTEXITCODE -eq 0)
|
|
}
|
|
|
|
function Invoke-Psql {
|
|
param(
|
|
[string]$PgBin,
|
|
[int]$Port = $script:LocalDbPort,
|
|
[string]$User = $script:LocalDbUser,
|
|
[string]$Database = 'postgres',
|
|
[string]$Sql
|
|
)
|
|
$psql = Join-Path $PgBin 'psql.exe'
|
|
& $psql -h 127.0.0.1 -p $Port -U $User -d $Database -v ON_ERROR_STOP=1 -c $Sql 2>&1 | Out-Null
|
|
if ($LASTEXITCODE -ne 0) { throw "psql failed ($Sql)" }
|
|
}
|