Initial qiwei secondary development handoff
This commit is contained in:
249
scripts/package-windows.ps1
Normal file
249
scripts/package-windows.ps1
Normal file
@@ -0,0 +1,249 @@
|
||||
param(
|
||||
[switch]$SkipTests,
|
||||
[switch]$SkipFrontendBuild,
|
||||
[string]$WailsPath,
|
||||
[string]$MakensisPath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$repoRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path
|
||||
$binDir = Join-Path $repoRoot "build\bin"
|
||||
$installerDir = Join-Path $repoRoot "build\windows\installer"
|
||||
$runtimeDir = Join-Path $installerDir "runtime"
|
||||
|
||||
function Resolve-RequiredTool {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Name,
|
||||
[string]$FallbackPath,
|
||||
[string]$InstallHint
|
||||
)
|
||||
|
||||
$command = Get-Command $Name -ErrorAction SilentlyContinue
|
||||
if ($command) {
|
||||
return $command.Source
|
||||
}
|
||||
if ($FallbackPath -and (Test-Path -LiteralPath $FallbackPath)) {
|
||||
return (Resolve-Path -LiteralPath $FallbackPath).Path
|
||||
}
|
||||
throw "Required tool not found: $Name. $InstallHint"
|
||||
}
|
||||
|
||||
function Assert-UnderDirectory {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Parent
|
||||
)
|
||||
|
||||
$parentPath = (Resolve-Path -LiteralPath $Parent).Path.TrimEnd('\')
|
||||
if (Test-Path -LiteralPath $Path) {
|
||||
$targetPath = (Resolve-Path -LiteralPath $Path).Path
|
||||
} else {
|
||||
$targetPath = [System.IO.Path]::GetFullPath($Path)
|
||||
}
|
||||
if (-not $targetPath.StartsWith($parentPath, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "Refusing to operate on $targetPath because it is not under $parentPath"
|
||||
}
|
||||
}
|
||||
|
||||
function Reset-Directory {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Parent
|
||||
)
|
||||
|
||||
Assert-UnderDirectory -Path $Path -Parent $Parent
|
||||
if (Test-Path -LiteralPath $Path) {
|
||||
Remove-Item -LiteralPath $Path -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $Path | Out-Null
|
||||
}
|
||||
|
||||
function Write-Utf8NoBom {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Content
|
||||
)
|
||||
|
||||
$encoding = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($Path, $Content, $encoding)
|
||||
}
|
||||
|
||||
function Copy-RequiredFile {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Source,
|
||||
[Parameter(Mandatory = $true)][string]$Destination
|
||||
)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $Source)) {
|
||||
throw "Missing release resource: $Source"
|
||||
}
|
||||
$destinationDir = Split-Path -Parent $Destination
|
||||
if ($destinationDir -and -not (Test-Path -LiteralPath $destinationDir)) {
|
||||
New-Item -ItemType Directory -Force -Path $destinationDir | Out-Null
|
||||
}
|
||||
try {
|
||||
Copy-Item -LiteralPath $Source -Destination $Destination -Force -ErrorAction Stop
|
||||
} catch {
|
||||
if (Test-Path -LiteralPath $Destination) {
|
||||
$sourceInfo = Get-Item -LiteralPath $Source
|
||||
$destinationInfo = Get-Item -LiteralPath $Destination
|
||||
if ($sourceInfo.Length -eq $destinationInfo.Length) {
|
||||
Write-Warning "Could not overwrite ${Destination}; existing file has the same size and will be kept. $($_.Exception.Message)"
|
||||
return
|
||||
}
|
||||
}
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
function Stop-RunningReleaseProcesses {
|
||||
$processes = Get-Process -Name "qiweimanager", "helper", "helper_auto_reply" -ErrorAction SilentlyContinue
|
||||
foreach ($process in $processes) {
|
||||
Write-Host "==> Stopping running release process: $($process.ProcessName) ($($process.Id))"
|
||||
Stop-Process -Id $process.Id -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
Set-Location $repoRoot
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $repoRoot ".gocache") | Out-Null
|
||||
$env:GOCACHE = (Resolve-Path (Join-Path $repoRoot ".gocache")).Path
|
||||
|
||||
$wailsFallback = if ($WailsPath) { $WailsPath } else { Join-Path $env:USERPROFILE "go\bin\wails.exe" }
|
||||
$wails = Resolve-RequiredTool -Name "wails.exe" -FallbackPath $wailsFallback -InstallHint "Install Wails CLI on the build machine first."
|
||||
$makensis = Resolve-RequiredTool -Name "makensis.exe" -FallbackPath $MakensisPath -InstallHint "Install NSIS on the build machine first, e.g. run as Administrator: choco install nsis -y; or pass -MakensisPath."
|
||||
$npm = Resolve-RequiredTool -Name "npm.cmd" -InstallHint "Install Node.js on the build machine first."
|
||||
$go = Resolve-RequiredTool -Name "go.exe" -InstallHint "Install Go on the build machine first."
|
||||
$pdftoppm = Get-Command "pdftoppm.exe" -ErrorAction SilentlyContinue
|
||||
$env:PATH = "$(Split-Path -Parent $makensis);$env:PATH"
|
||||
|
||||
Write-Host "==> Release root: $repoRoot"
|
||||
Write-Host "==> Wails: $wails"
|
||||
Write-Host "==> NSIS: $makensis"
|
||||
|
||||
if (-not $SkipTests) {
|
||||
Write-Host "==> Running Go tests"
|
||||
& $go test ./...
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $binDir | Out-Null
|
||||
|
||||
Stop-RunningReleaseProcesses
|
||||
|
||||
Write-Host "==> Building 32-bit helper.exe"
|
||||
$helperOut = Join-Path $binDir "helper.exe"
|
||||
$oldGoArch = $env:GOARCH
|
||||
try {
|
||||
$env:GOARCH = "386"
|
||||
Push-Location (Join-Path $repoRoot "helper")
|
||||
& $go build -trimpath -ldflags "-H windowsgui -s -w" -o $helperOut .
|
||||
} finally {
|
||||
Pop-Location
|
||||
if ($null -eq $oldGoArch) {
|
||||
Remove-Item Env:GOARCH -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
$env:GOARCH = $oldGoArch
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "==> Building bundled silk decoder"
|
||||
$silkDecoderOut = Join-Path $binDir "tools\audio\silkdecode.exe"
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path $silkDecoderOut) | Out-Null
|
||||
Push-Location (Join-Path $repoRoot "tools\audio\silkdecode")
|
||||
try {
|
||||
& $go build -trimpath -ldflags "-s -w" -o $silkDecoderOut .
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if ($pdftoppm) {
|
||||
Write-Host "==> Copying PDF renderer"
|
||||
Copy-RequiredFile -Source $pdftoppm.Source -Destination (Join-Path $binDir "tools\pdf\pdftoppm.exe")
|
||||
} else {
|
||||
Write-Warning "pdftoppm.exe not found; scanned PDF OCR fallback will be unavailable in this build."
|
||||
}
|
||||
|
||||
Write-Host "==> Copying DLLs to build\bin"
|
||||
$helperDll = Join-Path $repoRoot "Helper_4.1.33.6009.dll"
|
||||
$loaderDll = Join-Path $repoRoot "Loader_4.1.33.6009.dll"
|
||||
Copy-RequiredFile -Source $helperDll -Destination (Join-Path $binDir "Helper_4.1.33.6009.dll")
|
||||
Copy-RequiredFile -Source $loaderDll -Destination (Join-Path $binDir "Loader_4.1.33.6009.dll")
|
||||
|
||||
foreach ($staleFile in @("helper_auto_reply.exe", "qiweimanager.exe~")) {
|
||||
$path = Join-Path $binDir $staleFile
|
||||
if (Test-Path -LiteralPath $path) {
|
||||
try {
|
||||
Remove-Item -LiteralPath $path -Force -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Warning "Could not remove stale file ${path}: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipFrontendBuild) {
|
||||
Write-Host "==> Building frontend"
|
||||
Push-Location (Join-Path $repoRoot "frontend")
|
||||
try {
|
||||
& $npm run build
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "==> Staging NSIS runtime resources"
|
||||
Reset-Directory -Path $runtimeDir -Parent $installerDir
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $runtimeDir "config\knowledge") | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $runtimeDir "config\materials") | Out-Null
|
||||
|
||||
Copy-RequiredFile -Source $helperOut -Destination (Join-Path $runtimeDir "helper.exe")
|
||||
Copy-RequiredFile -Source $silkDecoderOut -Destination (Join-Path $runtimeDir "tools\audio\silkdecode.exe")
|
||||
if (Test-Path -LiteralPath (Join-Path $binDir "tools\pdf\pdftoppm.exe")) {
|
||||
Copy-RequiredFile -Source (Join-Path $binDir "tools\pdf\pdftoppm.exe") -Destination (Join-Path $runtimeDir "tools\pdf\pdftoppm.exe")
|
||||
}
|
||||
Copy-RequiredFile -Source (Join-Path $binDir "Helper_4.1.33.6009.dll") -Destination (Join-Path $runtimeDir "Helper_4.1.33.6009.dll")
|
||||
Copy-RequiredFile -Source (Join-Path $binDir "Loader_4.1.33.6009.dll") -Destination (Join-Path $runtimeDir "Loader_4.1.33.6009.dll")
|
||||
|
||||
Copy-Item -LiteralPath (Join-Path $repoRoot "requestdata") -Destination (Join-Path $runtimeDir "requestdata") -Recurse -Force
|
||||
Copy-Item -LiteralPath (Join-Path $repoRoot "eventdata") -Destination (Join-Path $runtimeDir "eventdata") -Recurse -Force
|
||||
|
||||
$defaultConfig = @'
|
||||
{
|
||||
"callbackConfig": {
|
||||
"callbackUrl": "",
|
||||
"callbackToken": "",
|
||||
"httpPort": "10001",
|
||||
"enableCallback": false,
|
||||
"enableCloudAuth": false,
|
||||
"fileUploadUrl": "",
|
||||
"deviceCode": ""
|
||||
},
|
||||
"lastUpdated": 0
|
||||
}
|
||||
'@
|
||||
Write-Utf8NoBom -Path (Join-Path $runtimeDir "config\config.json") -Content $defaultConfig
|
||||
Write-Utf8NoBom -Path (Join-Path $runtimeDir "config\client_status.json") -Content "{}"
|
||||
|
||||
$knowledgeKeep = Join-Path $repoRoot "config\knowledge\.keep"
|
||||
if (Test-Path -LiteralPath $knowledgeKeep) {
|
||||
Copy-Item -LiteralPath $knowledgeKeep -Destination (Join-Path $runtimeDir "config\knowledge\.keep") -Force
|
||||
} else {
|
||||
Write-Utf8NoBom -Path (Join-Path $runtimeDir "config\knowledge\.keep") -Content "placeholder for installer-created knowledge directory"
|
||||
}
|
||||
|
||||
$materialsIndex = Join-Path $repoRoot "config\materials\materials.json"
|
||||
if (Test-Path -LiteralPath $materialsIndex) {
|
||||
Copy-RequiredFile -Source $materialsIndex -Destination (Join-Path $runtimeDir "config\materials\materials.json")
|
||||
} else {
|
||||
Write-Utf8NoBom -Path (Join-Path $runtimeDir "config\materials\materials.json") -Content "{`"materials`":[]}"
|
||||
}
|
||||
|
||||
Write-Host "==> Building Wails NSIS installer"
|
||||
& $wails build --nsis -webview2 embed -trimpath
|
||||
|
||||
$installer = Join-Path $binDir "qiweimanager-amd64-installer.exe"
|
||||
if (-not (Test-Path -LiteralPath $installer)) {
|
||||
throw "Installer was not generated: $installer"
|
||||
}
|
||||
|
||||
Write-Host "==> Release complete: $installer"
|
||||
Reference in New Issue
Block a user