Files
kefu/wechat_rpa/build_windows_exe.ps1
T
2026-08-18 17:25:22 +08:00

112 lines
3.8 KiB
PowerShell

param(
[string]$PythonPath = ""
)
$ErrorActionPreference = "Stop"
$projectRoot = [System.IO.Path]::GetFullPath($PSScriptRoot)
$buildEnvironment = Join-Path $projectRoot ".build-venv"
$buildPython = Join-Path $buildEnvironment "Scripts\python.exe"
$requirements = Join-Path $projectRoot "requirements.txt"
$spec = Join-Path $projectRoot "wechat_rpa.spec"
$versionLine = Select-String -LiteralPath (Join-Path $projectRoot "app_version.py") -Pattern '^APP_VERSION\s*=\s*"([^"]+)"$'
if (-not $versionLine) {
throw "Cannot read APP_VERSION from app_version.py"
}
$version = $versionLine.Matches[0].Groups[1].Value
$env:WECOM_BUILD_VERSION = $version
$env:UV_CACHE_DIR = Join-Path $projectRoot ".uv-cache"
function Test-BuildPython([string]$Candidate) {
if (-not $Candidate -or -not (Test-Path -LiteralPath $Candidate)) {
return $false
}
& $Candidate -c "import PyInstaller, PySide6, requests, numpy, PIL, pyautogui, pyperclip, win32gui, mcp, rapidocr_onnxruntime" *> $null
return $LASTEXITCODE -eq 0
}
$candidates = @()
if ($PythonPath) {
$candidates += [System.IO.Path]::GetFullPath($PythonPath)
}
try {
$launcherPython = (& py -3.11 -c "import sys; print(sys.executable)" 2>$null | Select-Object -Last 1).Trim()
if ($launcherPython) { $candidates += $launcherPython }
}
catch {}
if (Test-Path -LiteralPath $buildPython) {
$candidates += $buildPython
}
$python = $candidates | Where-Object { Test-BuildPython $_ } | Select-Object -First 1
if (-not $python) {
if (-not (Test-Path -LiteralPath $buildPython)) {
& uv venv --python 3.12 $buildEnvironment
if ($LASTEXITCODE -ne 0) { throw "Failed to create the EXE build environment" }
}
& uv pip install --python $buildPython -r $requirements pyinstaller
if ($LASTEXITCODE -ne 0) { throw "Failed to install EXE build dependencies" }
$python = $buildPython
}
Write-Output ("Build Python: " + $python)
Push-Location $projectRoot
try {
& $python -m PyInstaller --noconfirm --clean $spec
if ($LASTEXITCODE -ne 0) { throw "PyInstaller build failed" }
}
finally {
Pop-Location
}
$appName = "ZhenAI-WeCom-Assistant-v$version"
$appDir = Join-Path $projectRoot "dist\$appName"
$exe = Join-Path $appDir "$appName.exe"
if (-not (Test-Path -LiteralPath $exe)) {
throw ("Build completed but EXE was not found: " + $exe)
}
$internalDir = Join-Path $appDir "_internal"
$requiredRuntimeFiles = @(
"PySide6\QtWebEngineProcess.exe",
"PySide6\resources\qtwebengine_resources.pak",
"PySide6\resources\icudtl.dat",
"PySide6\translations\qtwebengine_locales\zh-CN.pak",
"VCRUNTIME140.dll"
)
foreach ($requiredFile in $requiredRuntimeFiles) {
if (-not (Test-Path -LiteralPath (Join-Path $internalDir $requiredFile))) {
throw ("Required embedded runtime file is missing: " + $requiredFile)
}
}
Write-Output "Embedded browser and VC runtime files verified"
# 有证书时给主程序签名(无证书自动跳过)。签名要在自检前完成,
# 保证自检跑的就是最终分发的那个文件。
& (Join-Path $projectRoot "sign_artifact.ps1") -Path $exe
if ($LASTEXITCODE -ne 0) { throw "Code signing step failed" }
$selfCheck = Start-Process -FilePath $exe -ArgumentList "--packaging-self-check" -PassThru -WindowStyle Hidden
try {
if (-not $selfCheck.WaitForExit(90000)) {
$selfCheck.Kill()
throw "Packaged Qt WebEngine self-check timed out"
}
if ($selfCheck.ExitCode -ne 0) {
throw ("Packaged Qt WebEngine self-check failed with exit code " + $selfCheck.ExitCode)
}
}
finally {
if ($selfCheck -and -not $selfCheck.HasExited) {
$selfCheck.Kill()
}
}
Write-Output "Packaged Qt WebEngine self-check passed"
$hash = (Get-FileHash -LiteralPath $exe -Algorithm SHA256).Hash
Write-Output ("App folder: " + $appDir)
Write-Output ("EXE: " + $exe)
Write-Output ("SHA256: " + $hash)