119 lines
6.9 KiB
PowerShell
119 lines
6.9 KiB
PowerShell
param([string]$MediaMTXPath = '')
|
|
Set-StrictMode -Version 3.0
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$senseRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..'))
|
|
$serverRoot = Join-Path $senseRoot 'server'
|
|
$uiRoot = Join-Path $senseRoot 'ui'
|
|
$distRoot = Join-Path $senseRoot 'dist'
|
|
$target = Join-Path $distRoot 'sense-windows-amd64'
|
|
$archive = Join-Path $distRoot 'sense-windows-amd64.zip'
|
|
$staging = Join-Path $distRoot ('.sense-windows-amd64.staging-' + $PID)
|
|
|
|
function Assert-ChildPath([string]$Parent, [string]$Child) {
|
|
$parentPath = [IO.Path]::GetFullPath($Parent).TrimEnd('\') + '\'
|
|
$childPath = [IO.Path]::GetFullPath($Child)
|
|
if (-not $childPath.StartsWith($parentPath, [StringComparison]::OrdinalIgnoreCase)) {
|
|
throw "Unsafe build path outside $Parent`: $Child"
|
|
}
|
|
}
|
|
|
|
function Get-SenseFileSha256([string]$Path) {
|
|
$sha256 = [Security.Cryptography.SHA256]::Create()
|
|
$stream = [IO.File]::OpenRead($Path)
|
|
try {
|
|
return ([BitConverter]::ToString($sha256.ComputeHash($stream))).Replace('-', '')
|
|
} finally {
|
|
$stream.Dispose()
|
|
$sha256.Dispose()
|
|
}
|
|
}
|
|
|
|
Assert-ChildPath $senseRoot $distRoot
|
|
Assert-ChildPath $distRoot $target
|
|
Assert-ChildPath $distRoot $archive
|
|
Assert-ChildPath $distRoot $staging
|
|
|
|
$goVersion = ''
|
|
Push-Location $serverRoot
|
|
try { $goVersion = (& go env GOVERSION).Trim() } finally { Pop-Location }
|
|
$nodeVersion = (& node --version).Trim().TrimStart('v')
|
|
$pnpmVersion = (& corepack pnpm@9.15.1 --version).Trim()
|
|
if ($goVersion -ne 'go1.26.5') { throw "Go 1.26.5 is required; module toolchain reported $goVersion." }
|
|
if ($nodeVersion -ne '22.22.1') { throw "Node 22.22.1 is required; found $nodeVersion." }
|
|
if ($pnpmVersion -ne '9.15.1') { throw "pnpm 9.15.1 is required; corepack reported $pnpmVersion." }
|
|
|
|
$hadNodeModules = Test-Path -LiteralPath (Join-Path $uiRoot 'node_modules')
|
|
$hadUIDist = Test-Path -LiteralPath (Join-Path $uiRoot 'dist')
|
|
try {
|
|
New-Item -ItemType Directory -Force -Path $distRoot | Out-Null
|
|
if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Recurse -Force }
|
|
New-Item -ItemType Directory -Path $staging | Out-Null
|
|
|
|
Push-Location $uiRoot
|
|
try {
|
|
& corepack pnpm@9.15.1 install --frozen-lockfile
|
|
if ($LASTEXITCODE -ne 0) { throw 'pnpm install failed.' }
|
|
& corepack pnpm@9.15.1 run build:prod
|
|
if ($LASTEXITCODE -ne 0) { throw 'Sense UI production build failed.' }
|
|
} finally { Pop-Location }
|
|
|
|
$oldGOOS, $oldGOARCH, $oldCGO = $env:GOOS, $env:GOARCH, $env:CGO_ENABLED
|
|
try {
|
|
$env:GOOS = 'windows'; $env:GOARCH = 'amd64'; $env:CGO_ENABLED = '0'
|
|
Push-Location $serverRoot
|
|
try {
|
|
& go build -trimpath -ldflags '-s -w' -o (Join-Path $staging 'sense.exe') .
|
|
if ($LASTEXITCODE -ne 0) { throw 'Sense server Windows build failed.' }
|
|
} finally { Pop-Location }
|
|
} finally {
|
|
$env:GOOS, $env:GOARCH, $env:CGO_ENABLED = $oldGOOS, $oldGOARCH, $oldCGO
|
|
}
|
|
|
|
Copy-Item -LiteralPath (Join-Path $uiRoot 'dist') -Destination (Join-Path $staging 'web') -Recurse
|
|
New-Item -ItemType Directory -Path (Join-Path $staging 'scripts\runtime'), (Join-Path $staging 'config'), (Join-Path $staging 'bin') | Out-Null
|
|
Copy-Item -Path (Join-Path $senseRoot 'scripts\runtime\*.ps1') -Destination (Join-Path $staging 'scripts\runtime')
|
|
foreach ($name in @('start-sense', 'stop-sense', 'check-sense', 'migrate-sense', 'backup-sense', 'restore-sense', 'initialize-admin')) {
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot "scripts\runtime\$name.bat") -Destination (Join-Path $staging "$name.bat")
|
|
}
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'config\sense.env.example') -Destination (Join-Path $staging 'config\sense.env.example')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'config\sense.env.example') -Destination (Join-Path $staging 'config\sense.env')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'config\sense.demo.env.example') -Destination (Join-Path $staging 'config\sense.demo.env.example')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'config\sense.demo.env.example') -Destination (Join-Path $staging 'config\sense.demo.env')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'config\mediamtx.yml') -Destination (Join-Path $staging 'config\mediamtx.yml')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'config\mediamtx-shards.example.json') -Destination (Join-Path $staging 'config\mediamtx-shards.example.json')
|
|
Copy-Item -LiteralPath (Join-Path $serverRoot 'config\db.sql') -Destination (Join-Path $staging 'config\db.sql')
|
|
Copy-Item -LiteralPath (Join-Path $serverRoot 'config\pg.sql') -Destination (Join-Path $staging 'config\pg.sql')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'README-WINDOWS.md') -Destination (Join-Path $staging 'README-WINDOWS.md')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'package\README-MEDIAMTX.txt') -Destination (Join-Path $staging 'bin\README-MEDIAMTX.txt')
|
|
Copy-Item -LiteralPath (Join-Path $senseRoot 'LICENSES') -Destination (Join-Path $staging 'LICENSES') -Recurse
|
|
if (-not [string]::IsNullOrWhiteSpace($MediaMTXPath)) {
|
|
$mediaSource = [IO.Path]::GetFullPath($MediaMTXPath)
|
|
if (-not (Test-Path -LiteralPath $mediaSource -PathType Leaf)) { throw "MediaMTX binary not found: $mediaSource" }
|
|
Copy-Item -LiteralPath $mediaSource -Destination (Join-Path $staging 'bin\mediamtx.exe')
|
|
}
|
|
$commit = (& git -C (Split-Path $senseRoot -Parent) rev-parse HEAD).Trim()
|
|
[IO.File]::WriteAllLines((Join-Path $staging 'VERSION.txt'), @(
|
|
"source_commit=$commit", 'go=1.26.5', 'node=22.22.1', 'pnpm=9.15.1'
|
|
), (New-Object Text.UTF8Encoding($false)))
|
|
|
|
& (Join-Path $PSScriptRoot 'test-package.ps1') -PackageRoot $staging
|
|
if ($LASTEXITCODE -ne 0) { throw 'Sense package audit failed.' }
|
|
$manifest = foreach ($file in Get-ChildItem -LiteralPath $staging -Recurse -File | Sort-Object FullName) {
|
|
$relative = $file.FullName.Substring($staging.Length + 1).Replace('\', '/')
|
|
"$(Get-SenseFileSha256 -Path $file.FullName) $relative"
|
|
}
|
|
[IO.File]::WriteAllLines((Join-Path $staging 'MANIFEST.sha256'), $manifest, (New-Object Text.UTF8Encoding($false)))
|
|
|
|
if (Test-Path -LiteralPath $target) { Remove-Item -LiteralPath $target -Recurse -Force }
|
|
Move-Item -LiteralPath $staging -Destination $target
|
|
if (Test-Path -LiteralPath $archive) { Remove-Item -LiteralPath $archive -Force }
|
|
Compress-Archive -LiteralPath $target -DestinationPath $archive -CompressionLevel Optimal
|
|
Write-Host "Sense Windows package: $target"
|
|
Write-Host "Sense Windows archive: $archive"
|
|
} finally {
|
|
if (Test-Path -LiteralPath $staging) { Remove-Item -LiteralPath $staging -Recurse -Force }
|
|
if (-not $hadUIDist -and (Test-Path -LiteralPath (Join-Path $uiRoot 'dist'))) { Remove-Item -LiteralPath (Join-Path $uiRoot 'dist') -Recurse -Force }
|
|
if (-not $hadNodeModules -and (Test-Path -LiteralPath (Join-Path $uiRoot 'node_modules'))) { Remove-Item -LiteralPath (Join-Path $uiRoot 'node_modules') -Recurse -Force }
|
|
}
|