112 lines
3.8 KiB
PowerShell
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)
|