Files
zfjia 35751b4f00
IT-0 verify / verify (push) Waiting to run
1111
2026-11-11 18:30:31 +08:00

110 lines
4.8 KiB
PowerShell

<#
Apply IT-2 SQL scripts to apt_rev01 (idempotent, replayable).
Credentials come from dev/.env first, then APT_DB_* environment variables.
Passwords are never printed.
SQL files are streamed to mysql stdin as raw UTF-8 bytes: PowerShell 5.1's
text pipeline can replace Chinese literals with '?'.
Usage:
powershell -ExecutionPolicy Bypass -File dev/scripts/apply-it2-sql.ps1
powershell -ExecutionPolicy Bypass -File dev/scripts/apply-it2-sql.ps1 -DryRun
powershell -ExecutionPolicy Bypass -File dev/scripts/apply-it2-sql.ps1 -EnvFile C:\secrets\apt.env
#>
param(
[string]$EnvFile = '',
[string]$MysqlPath = 'C:\Program Files\MySQL\MySQL Server 9.5\bin\mysql.exe',
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
$devDir = Split-Path $PSScriptRoot -Parent
$sqlDir = Join-Path $devDir 'sql/apt_rev01'
$scripts = @('10_it2_columns.sql', '11_it2_seed.sql', '12_it2_permissions.sql', '13_it2_frontend_menus.sql')
foreach ($name in $scripts) {
$file = Join-Path $sqlDir $name
if (-not [System.IO.File]::Exists($file)) { throw "Missing SQL file: $file" }
}
if ($EnvFile -eq '') { $EnvFile = Join-Path $devDir '.env' }
$values = @{}
if ([System.IO.File]::Exists($EnvFile)) {
foreach ($line in [System.IO.File]::ReadAllLines($EnvFile)) {
$trimmed = $line.Trim()
if ($trimmed -eq '' -or $trimmed.StartsWith('#')) { continue }
if ($trimmed -match '^([A-Za-z0-9_]+)\s*=\s*(.*)$') { $values[$Matches[1]] = $Matches[2] }
}
Write-Host "Credentials source: $EnvFile"
} else {
Write-Host "No credentials file at $EnvFile; using APT_DB_* environment variables."
foreach ($key in @('APT_DB_HOST','APT_DB_PORT','APT_DB_NAME','APT_DB_USER','APT_DB_PASSWORD')) {
$values[$key] = [Environment]::GetEnvironmentVariable($key)
}
}
$dbHost = $values['APT_DB_HOST']; if ([string]::IsNullOrEmpty($dbHost)) { $dbHost = '127.0.0.1' }
$dbPort = $values['APT_DB_PORT']; if ([string]::IsNullOrEmpty($dbPort)) { $dbPort = '3306' }
$dbName = $values['APT_DB_NAME']; if ([string]::IsNullOrEmpty($dbName)) { $dbName = 'apt_rev01' }
$dbUser = $values['APT_DB_USER']; if ([string]::IsNullOrEmpty($dbUser)) { $dbUser = 'iotlocks' }
if ($DryRun) {
Write-Host '--- DRY RUN: no database connection, no credentials required ---'
Write-Host ("Target database: {0}:{1}/{2} (user {3})" -f $dbHost, $dbPort, $dbName, $dbUser)
foreach ($name in $scripts) {
$file = Join-Path $sqlDir $name
$lineCount = ([System.IO.File]::ReadAllLines($file, [System.Text.Encoding]::UTF8)).Count
Write-Host (" would apply {0} ({1} lines)" -f $name, $lineCount)
}
Write-Host 'Validation SELECTs in 11/12/13 print Mock marker counts, permission and frontend menu checks.'
return
}
if ([string]::IsNullOrEmpty($values['APT_DB_PASSWORD'])) {
$hint = @'
Missing APT_DB_PASSWORD. Provide one of:
1) copy dev/.env.example to dev/.env, fill APT_DB_PASSWORD, then re-run this script
2) set APT_DB_PASSWORD (plus optional APT_DB_HOST/PORT/NAME/USER) in the environment
Use -DryRun to preview SQL files without connecting to MySQL.
'@
throw $hint
}
if (-not [System.IO.File]::Exists($MysqlPath)) { throw "Missing mysql client: $MysqlPath" }
[Environment]::SetEnvironmentVariable('MYSQL_PWD', $values['APT_DB_PASSWORD'], 'Process')
try {
foreach ($name in $scripts) {
$file = Join-Path $sqlDir $name
Write-Host "--- applying $name ---"
$arguments = "--host=$dbHost --port=$dbPort --user=$dbUser --database=$dbName" +
' --default-character-set=utf8mb4 --batch'
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $MysqlPath
$psi.Arguments = $arguments
$psi.UseShellExecute = $false
$psi.RedirectStandardInput = $true
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.StandardOutputEncoding = [System.Text.Encoding]::UTF8
$psi.StandardErrorEncoding = [System.Text.Encoding]::UTF8
$process = [System.Diagnostics.Process]::Start($psi)
$bytes = [System.IO.File]::ReadAllBytes($file)
$offset = 0
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$offset = 3
}
$process.StandardInput.BaseStream.Write($bytes, $offset, $bytes.Length - $offset)
$process.StandardInput.BaseStream.Flush()
$process.StandardInput.Close()
$stdout = $process.StandardOutput.ReadToEnd()
$stderr = $process.StandardError.ReadToEnd()
$process.WaitForExit()
if ($stdout) { Write-Host $stdout }
if ($stderr) { Write-Host $stderr }
if ($process.ExitCode -ne 0) { throw "SQL failed: $name (exit $($process.ExitCode))" }
}
Write-Host 'IT-2 SQL scripts applied successfully.'
} finally {
[Environment]::SetEnvironmentVariable('MYSQL_PWD', $null, 'Process')
}