Files
qiweimanager-master/scripts/package-windows.ps1
yuanzhipeng a926ee6b1b chore(build): 更新.gitignore配置和清理Wails临时文件
- 添加dist/目录到.gitignore,用于排除打包输出的绿色免安装版
- 添加Wails打包过程中的临时文件和自动生成文件到.gitignore
- 删除build/windows/installer/wails_tools.nsh自动生成文件
- 添加Windows安装器临时目录和Webview2安装文件到忽略列表

feat(docs): 添加万川平台对接文档和产品素材

- 创建万川平台登录到获取模型信息的流程说明文档
- 添加万川平台对接实施计划文档
- 新增产品图片、公司简介图、宣传海报、教程截图、案例展示等素材文件

refactor(runtime): 扩展通知功能类型定义

- 添加NotificationOptions接口定义
- 添加NotificationAction接口定义
- 添加NotificationCategory接口定义
- 扩展通知相关的运行时API类型声明,包括初始化、发送、注册分类等功能
2026-06-25 18:13:11 +08:00

285 lines
11 KiB
PowerShell

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."
# 自动探测 NSIS 标准安装路径(未在 PATH 时也能找到),优先使用显式传入的 -MakensisPath
$makensisFallback = $null
$makensisCandidates = @()
if ($MakensisPath) { $makensisCandidates += $MakensisPath }
$makensisCandidates += @(
(Join-Path ${env:ProgramFiles(x86)} "NSIS\makensis.exe"),
(Join-Path $env:ProgramFiles "NSIS\makensis.exe"),
(Join-Path $env:LOCALAPPDATA "Programs\NSIS\makensis.exe")
)
foreach ($candidate in $makensisCandidates) {
if ($candidate -and (Test-Path -LiteralPath $candidate)) { $makensisFallback = $candidate; break }
}
$makensis = Resolve-RequiredTool -Name "makensis.exe" -FallbackPath $makensisFallback -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"
$silkBuilt = $false
if (-not (Get-Command gcc -ErrorAction SilentlyContinue)) {
Write-Warning "gcc not found; silkdecode requires cgo and will be skipped. Voice message transcoding will be unavailable."
} else {
New-Item -ItemType Directory -Force -Path (Split-Path $silkDecoderOut) | Out-Null
Push-Location (Join-Path $repoRoot "tools\audio\silkdecode")
try {
$oldCgo = $env:CGO_ENABLED; $env:CGO_ENABLED = "1"
& $go build -trimpath -ldflags "-s -w" -o $silkDecoderOut .
if ($LASTEXITCODE -eq 0) { $silkBuilt = $true } else { Write-Warning "silkdecode build failed, skipping." }
} finally {
Pop-Location
if ($null -eq $oldCgo) { Remove-Item Env:CGO_ENABLED -ErrorAction SilentlyContinue } else { $env:CGO_ENABLED = $oldCgo }
}
}
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 {
# 原生命令往 stderr 写警告会在 Stop 策略下被误判为失败,这里改按退出码判断
$oldEap = $ErrorActionPreference; $ErrorActionPreference = "Continue"
& $npm run build 2>&1 | ForEach-Object { "$_" }
$ErrorActionPreference = $oldEap
if ($LASTEXITCODE -ne 0) { throw "frontend build failed (exit $LASTEXITCODE)" }
} 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")
if ($silkBuilt -and (Test-Path -LiteralPath $silkDecoderOut)) {
Copy-RequiredFile -Source $silkDecoderOut -Destination (Join-Path $runtimeDir "tools\audio\silkdecode.exe")
} else {
Write-Warning "silkdecode.exe not bundled (gcc unavailable); voice transcoding disabled in this installer."
}
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"
$oldEap = $ErrorActionPreference; $ErrorActionPreference = "Continue"
& $wails build --nsis -webview2 embed -trimpath 2>&1 | ForEach-Object { "$_" }
$ErrorActionPreference = $oldEap
$installer = Join-Path $binDir "qiweimanager-amd64-installer.exe"
if (-not (Test-Path -LiteralPath $installer)) {
throw "Installer was not generated: $installer"
}
# 添加时间戳到安装包文件名
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$installerWithTime = Join-Path $binDir "qiweimanager-amd64-installer_$timestamp.exe"
Move-Item -LiteralPath $installer -Destination $installerWithTime -Force
Write-Host "==> Release complete: $installerWithTime"