feat: add versioned release packaging

This commit is contained in:
chengma
2026-07-07 14:21:30 +08:00
parent 148c4a73eb
commit 7838554c3d
14 changed files with 407 additions and 113 deletions
+127 -16
View File
@@ -1,20 +1,99 @@
$ErrorActionPreference = "Stop"
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Resolve-Path (Join-Path $scriptDir "..")
$repoRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path
Set-Location $repoRoot
$pythonVersion = python -c "import sys; print('%d.%d.%d' % sys.version_info[:3])"
Write-Host "Using Python: $pythonVersion"
if ([version]$pythonVersion -lt [version]"3.10.0") {
Write-Warning "Project target is Python 3.10+. Switch to a 3.10+ environment before official release builds."
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 ', ')"
}
}
$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"
}
python -m PyInstaller --noconfirm --clean $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"
@@ -37,19 +116,51 @@ $excluded = @(
"data"
)
$found = @()
foreach ($relative in $excluded) {
$candidate = Join-Path $distDir $relative
if (Test-Path -LiteralPath $candidate) {
$found += $relative
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 = "$appCodeName-$appVersion"
$releaseDir = Join-Path $releaseRoot $releaseName
$portableZip = Join-Path $releaseRoot "$releaseName-portable.zip"
foreach ($path in @($releaseDir, $portableZip)) {
Assert-InProject -Path $path
if (Test-Path -LiteralPath $path) {
Remove-Item -LiteralPath $path -Recurse -Force
}
}
if ($found.Count -gt 0) {
throw "Build output contains local user data: $($found -join ', ')"
}
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
Write-Host "Build complete: $exePath"
Write-Host "Do not copy local data into the release package."
$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-Archive -Path (Join-Path $releaseDir "*") -DestinationPath $portableZip -Force
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=")