The startup log proved config.yaml was not being found during migrate. Lookup covered the working directory and the executable's directory, but the server runs from server/ while config.yaml sits at the repository root — so it was found only when a launcher happened to export GOAUTO_CONFIG. Anyone running `go run .` by hand got no local config at all. Search the parent directory too, with the working directory still winning. The diagnostics also wrote to stderr, and the launcher pipes the server through `2>&1 | Tee-Object`, which turns every stderr write into a PowerShell NativeCommandError. The informational line I added to make this debuggable was itself rendering as a red error block. They go to stdout now. Launchers set the console to UTF-8: Go writes UTF-8 while the console decodes as the ANSI code page, which turned every Chinese log line into mojibake. Verified by running the built binary from server/ with no GOAUTO_CONFIG set: it loads ../config.yaml and the lines survive 2>/dev/null. Not verified: the two PowerShell edits, which need a Windows run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
111 lines
3.6 KiB
PowerShell
111 lines
3.6 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[string]$ConfigPath,
|
|
[switch]$ValidateConfigOnly
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
# Go 进程输出 UTF-8。不显式设定的话,中文日志会按控制台的 ANSI 代码页(简中为
|
|
# GBK)解码,显示成乱码——见 #48 启动日志。
|
|
try { [Console]::OutputEncoding = [Text.Encoding]::UTF8 } catch { }
|
|
$workspaceRoot = Split-Path -Parent $PSScriptRoot
|
|
$webDirectory = Join-Path $workspaceRoot "web"
|
|
|
|
function ConvertFrom-YamlScalar {
|
|
param([string]$Value)
|
|
|
|
$value = $Value.Trim()
|
|
if ($value.Length -ge 2) {
|
|
if ($value.StartsWith('"') -and $value.EndsWith('"')) {
|
|
return $value.Substring(1, $value.Length - 2).Replace('\"', '"').Replace('\\', '\')
|
|
}
|
|
if ($value.StartsWith("'") -and $value.EndsWith("'")) {
|
|
return $value.Substring(1, $value.Length - 2).Replace("''", "'")
|
|
}
|
|
}
|
|
return $value
|
|
}
|
|
|
|
function Read-PortConfig {
|
|
param([string]$Path)
|
|
|
|
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
|
|
throw "Local configuration file was not found: $Path. Copy config.example.yaml to config.yaml."
|
|
}
|
|
$values = @{}
|
|
$insidePorts = $false
|
|
foreach ($line in Get-Content -LiteralPath $Path) {
|
|
if ($line -match '^\s*(#.*)?$') {
|
|
continue
|
|
}
|
|
if ($line -match '^ports\s*:\s*$') {
|
|
$insidePorts = $true
|
|
continue
|
|
}
|
|
if ($insidePorts -and $line -match '^\S') {
|
|
break
|
|
}
|
|
if ($insidePorts -and $line -match '^\s+(server|web)\s*:\s*(.*?)\s*$') {
|
|
$values[$Matches[1]] = ConvertFrom-YamlScalar $Matches[2]
|
|
}
|
|
}
|
|
foreach ($key in 'server', 'web') {
|
|
$parsedPort = 0
|
|
if (-not $values.ContainsKey($key) -or
|
|
-not [int]::TryParse([string]$values[$key], [ref]$parsedPort) -or
|
|
$parsedPort -lt 1 -or $parsedPort -gt 65535) {
|
|
throw "ports.$key must be an integer between 1 and 65535 in: $Path"
|
|
}
|
|
$values[$key] = $parsedPort
|
|
}
|
|
if ($values.server -eq $values.web) {
|
|
throw "ports.server and ports.web must be different in: $Path"
|
|
}
|
|
return @{ Server = [int]$values.server; Web = [int]$values.web }
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($ConfigPath)) {
|
|
$ConfigPath = Join-Path $workspaceRoot "config.yaml"
|
|
}
|
|
elseif (-not [IO.Path]::IsPathRooted($ConfigPath)) {
|
|
$ConfigPath = Join-Path $workspaceRoot $ConfigPath
|
|
}
|
|
$ConfigPath = [IO.Path]::GetFullPath($ConfigPath)
|
|
$ports = Read-PortConfig $ConfigPath
|
|
|
|
Write-Host "GoAuto web UI" -ForegroundColor Cyan
|
|
Write-Host "Config: $ConfigPath"
|
|
Write-Host "Ports: server=$($ports.Server), web=$($ports.Web)"
|
|
if ($ValidateConfigOnly) {
|
|
Write-Host "Local port configuration is valid." -ForegroundColor Green
|
|
return
|
|
}
|
|
|
|
$pnpm = Get-Command pnpm.cmd -ErrorAction SilentlyContinue
|
|
if (-not $pnpm) {
|
|
throw "pnpm was not found. Install pnpm and try again."
|
|
}
|
|
|
|
Push-Location $webDirectory
|
|
try {
|
|
if (-not (Test-Path -LiteralPath "node_modules" -PathType Container)) {
|
|
Write-Host "Installing frontend dependencies..." -ForegroundColor Cyan
|
|
& $pnpm.Source install --frozen-lockfile
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Frontend dependency installation failed."
|
|
}
|
|
}
|
|
|
|
$env:VUE_APP_BASE_API = "http://127.0.0.1:$($ports.Server)"
|
|
Write-Host "Starting GoAuto web UI at http://127.0.0.1:$($ports.Web)" -ForegroundColor Green
|
|
& $pnpm.Source exec vite --host 127.0.0.1 --port $ports.Web --strictPort
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Frontend exited with code $LASTEXITCODE."
|
|
}
|
|
}
|
|
finally {
|
|
Remove-Item Env:VUE_APP_BASE_API -ErrorAction SilentlyContinue
|
|
Pop-Location
|
|
}
|