Files

190 lines
7.3 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$ErrorActionPreference = "Stop"
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path
Set-Location $repoRoot
function Read-VersionValue {
param(
[string]$Path,
[string]$Name
)
$pattern = '^\s*{0}\s*=\s*"([^"]+)"' -f [regex]::Escape($Name)
foreach ($line in Get-Content -LiteralPath $Path -Encoding UTF8) {
if ($line -match $pattern) {
return $Matches[1]
}
}
throw "Cannot find $Name in $Path"
}
function Decode-Utf8Base64 {
param([string]$Text)
return [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Text))
}
function Assert-InProject {
param([string]$Path)
$resolvedRoot = (Resolve-Path -LiteralPath $repoRoot).Path
$rootPrefix = $resolvedRoot.TrimEnd("\") + "\"
if (Test-Path -LiteralPath $Path) {
$resolvedPath = (Resolve-Path -LiteralPath $Path).Path
if ($resolvedPath -ne $resolvedRoot -and -not $resolvedPath.StartsWith($rootPrefix, [System.StringComparison]::OrdinalIgnoreCase)) {
throw "Refusing to modify path outside project: $resolvedPath"
}
} else {
$fullPath = [System.IO.Path]::GetFullPath($Path)
if ($fullPath -ne $resolvedRoot -and -not $fullPath.StartsWith($rootPrefix, [System.StringComparison]::OrdinalIgnoreCase)) {
throw "Refusing to modify path outside project: $fullPath"
}
}
}
function Assert-NoExcludedData {
param(
[string]$Root,
[string[]]$Excluded
)
$found = @()
foreach ($relative in $Excluded) {
$candidate = Join-Path $Root $relative
if (Test-Path -LiteralPath $candidate) {
$found += $relative
}
}
if ($found.Count -gt 0) {
throw "Build output contains local user data: $($found -join ', ')"
}
}
function Compress-ArchiveWithRetry {
param(
[string]$SourcePath,
[string]$DestinationPath,
[int]$Attempts = 5,
[int]$DelaySeconds = 2
)
for ($attempt = 1; $attempt -le $Attempts; $attempt++) {
try {
if (Test-Path -LiteralPath $DestinationPath) {
Remove-Item -LiteralPath $DestinationPath -Force
}
Compress-Archive -Path $SourcePath -DestinationPath $DestinationPath -Force
return
} catch {
if ($attempt -ge $Attempts) {
throw
}
Write-Host "压缩发布包被临时文件占用阻塞,等待 $DelaySeconds 秒后重试 ($attempt/$Attempts):$($_.Exception.Message)"
Start-Sleep -Seconds $DelaySeconds
}
}
}
$versionFile = Join-Path $repoRoot "app\version.py"
if (-not (Test-Path -LiteralPath $versionFile)) {
throw "Missing app\version.py"
}
$appName = Read-VersionValue -Path $versionFile -Name "APP_NAME"
$appCodeName = Read-VersionValue -Path $versionFile -Name "APP_CODE_NAME"
$appVersion = Read-VersionValue -Path $versionFile -Name "APP_VERSION"
if ($appCodeName -ne "cmshopee") {
throw "APP_CODE_NAME must be cmshopee, current value: $appCodeName"
}
$pythonExe = "py"
$pythonArgs = @("-3.10")
$pythonVersionOutput = & $pythonExe @pythonArgs -c "import sys; print('%d.%d.%d' % sys.version_info[:3])"
if ($LASTEXITCODE -ne 0 -or -not $pythonVersionOutput) {
throw (Decode-Utf8Base64 "5pyq5om+5YiwIFB5dGhvbiAzLjEw44CC6K+35YWI5a6J6KOFIFB5dGhvbiAzLjEw77yM5bm256Gu6K6kIFdpbmRvd3MgUHl0aG9uIExhdW5jaGVyIOWPr+mAmui/hyBweSAtMy4xMCDosIPnlKjjgII=")
}
$pythonVersion = ($pythonVersionOutput | Select-Object -First 1).Trim()
Write-Host "$(Decode-Utf8Base64 "5L2/55SoIFB5dGhvbiAzLjEwOg==") $pythonVersion"
if (-not $pythonVersion.StartsWith("3.10.")) {
throw "$(Decode-Utf8Base64 "5b2T5YmN5omT5YyF6ISa5pys5Zu65a6a5L2/55SoIFB5dGhvbiAzLjEw77yM5b2T5YmN54mI5pys"): $pythonVersion"
}
$spec = Join-Path $repoRoot "cmshopee.spec"
if (-not (Test-Path -LiteralPath $spec)) {
throw "Missing cmshopee.spec"
}
Write-Host "$(Decode-Utf8Base64 "5q2j5Zyo5p6E5bu6") $appName $appVersion"
Write-Host (Decode-Utf8Base64 "5omT5YyF5ZG95Luk5Zu65a6a5L2/55SoIHB5IC0zLjEwIC1tIFB5SW5zdGFsbGVy44CC")
& $pythonExe @pythonArgs -m PyInstaller --noconfirm --clean $spec
if ($LASTEXITCODE -ne 0) {
throw "$(Decode-Utf8Base64 "UHlJbnN0YWxsZXIg5omT5YyF5aSx6LSl77yM6YCA5Ye656CB"): $LASTEXITCODE"
}
$distDir = Join-Path $repoRoot "dist\cmshopee"
$exePath = Join-Path $distDir "cmshopee.exe"
if (-not (Test-Path -LiteralPath $exePath)) {
throw "Build failed: $exePath not found"
}
$excluded = @(
"config.json",
"config\ai_models.json",
"cmshopee.db",
"cmshopee.db-wal",
"cmshopee.db-shm",
"db.sqlite",
"chrome_user_data_dir",
"images",
"logs",
"prompts",
"title_prompt.txt",
"data"
)
Assert-NoExcludedData -Root $distDir -Excluded $excluded
$internalDir = Join-Path $distDir "_internal"
if (-not (Test-Path -LiteralPath $internalDir)) {
throw "Build output missing _internal directory. Expected PyInstaller 6.x onedir layout (cmshopee.exe + _internal). Ensure PyInstaller >= 6.0 is installed: py -3.10 -m pip install -r requirements-build.txt"
}
Write-Host "Verified onedir layout: _internal present"
$releaseRoot = Join-Path $repoRoot "release"
$releaseName = "$appName$appVersion"
$releaseDir = Join-Path $releaseRoot $releaseName
$portableZip = Join-Path $releaseRoot "$releaseName.zip"
foreach ($path in @($releaseDir, $portableZip)) {
Assert-InProject -Path $path
if (Test-Path -LiteralPath $path) {
Remove-Item -LiteralPath $path -Recurse -Force
}
}
New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null
Get-ChildItem -LiteralPath $distDir -Force | Copy-Item -Destination $releaseDir -Recurse -Force
Set-Content -LiteralPath (Join-Path $releaseDir "version.txt") -Value $appVersion -Encoding ascii -NoNewline
$readme = @(
"$appName v$appVersion",
"",
(Decode-Utf8Base64 "5ZCv5Yqo5pa55byP77ya"),
(Decode-Utf8Base64 "5Y+M5Ye7IGNtc2hvcGVlLmV4ZSDlkK/liqjjgII="),
"",
(Decode-Utf8Base64 "5L2/55So6K+05piO77ya"),
(Decode-Utf8Base64 "LSDor7fmiormlbTkuKrmlofku7blpLnop6PljovliLDlj6/lhpnnm67lvZXvvIzkvovlpoIgRDpcY21zaG9wZWUg5oiW5qGM6Z2i44CC"),
(Decode-Utf8Base64 "LSDkuI3opoHmlL7liLAgQzpcUHJvZ3JhbSBGaWxlcyDmiJblhbbku5bpnIDopoHnrqHnkIblkZjmnYPpmZDlhpnlhaXnmoTnm67lvZXjgII="),
(Decode-Utf8Base64 "LSDpppbmrKHov5DooYzkvJrlnKjnqIvluo/lkIznuqfliJvlu7ogZGF0YVzvvIznlKjkuo7kv53lrZjotKblj7fjgIHku7vliqHjgIHlm77niYfjgIHml6Xlv5fjgIHphY3nva7lkoznmbvlvZXmgIHjgII="),
(Decode-Utf8Base64 "LSDljYfnuqfml7bopobnm5bmlrDniYjnqIvluo/mlofku7blkozkvp3otZbmlofku7bvvIzkvYblv4Xpobvkv53nlZnml6fnm67lvZXph4znmoQgZGF0YVzjgII="),
(Decode-Utf8Base64 "LSDkuI3opoHmioogZGF0YVwg5Y+R57uZ5YW25LuW5Lq677yM6YeM6Z2i5YyF5ZCr5pys5Zyw6YWN572u44CB5Lia5Yqh5pWw5o2u44CB5Zu+54mH5ZKM55m75b2V5oCB44CC")
)
Set-Content -LiteralPath (Join-Path $releaseDir "README.txt") -Value $readme -Encoding UTF8
Assert-NoExcludedData -Root $releaseDir -Excluded $excluded
Compress-ArchiveWithRetry -SourcePath (Join-Path $releaseDir "*") -DestinationPath $portableZip
Write-Host "$(Decode-Utf8Base64 "5p6E5bu65a6M5oiQOg==") $exePath"
Write-Host "$(Decode-Utf8Base64 "5Y+R5biD55uu5b2VOg==") $releaseDir"
Write-Host "$(Decode-Utf8Base64 "5L6/5pC65Y6L57yp5YyFOg==") $portableZip"
Write-Host (Decode-Utf8Base64 "5LiN6KaB5oqK5pys5ZywIGRhdGHjgIHphY3nva7jgIHmlbDmja7lupPjgIHlm77niYfjgIHml6Xlv5fmiJbnmbvlvZXmgIHlpI3liLbov5vlj5HluIPljIXjgII=")