Files

787 lines
25 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.
param(
[string]$Target,
[string]$Version,
[ValidateSet("INSTALLER", "PORTABLE", "BOTH")]
[string]$WindowsFormat
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
Set-Location $repoRoot
$script:ResolvedVersion = ""
$script:LinuxArch = ""
$script:WindowsInstallerDone = $false
$script:WindowsPortableDone = $false
$script:LinuxDone = $false
function Write-Section {
param([string]$Text)
Write-Host "========================================"
Write-Host " $Text"
Write-Host "========================================"
}
function Get-TrimmedText {
param([AllowNull()][string]$Value)
if ($null -eq $Value) {
return ""
}
return $Value.Trim()
}
function Assert-VersionValue {
param(
[Parameter(Mandatory = $true)]
[string]$Value,
[string]$Source = "版本号"
)
$trimmed = Get-TrimmedText $Value
if ($trimmed -eq "") {
throw "$Source 不能为空"
}
if ($trimmed -notmatch '^\d+\.\d+\.\d+(?:-[0-9A-Za-z\.-]+)?(?:\+[0-9A-Za-z\.-]+)?$') {
throw "$Source 格式无效: $trimmed`n 期望示例: 1.1.0 或 1.1.0-beta.1"
}
return $trimmed
}
function Invoke-NativeCommand {
param(
[Parameter(Mandatory = $true)]
[string]$FilePath,
[string[]]$Arguments = @()
)
& $FilePath @Arguments
if ($LASTEXITCODE -ne 0) {
$argText = if ($Arguments.Count -gt 0) { " $($Arguments -join ' ')" } else { "" }
throw "$FilePath$argText failed with exit code $LASTEXITCODE"
}
}
function Assert-RequiredSourceFiles {
param(
[Parameter(Mandatory = $true)]
[string]$Action,
[Parameter(Mandatory = $true)]
[string[]]$Paths
)
$missing = @()
foreach ($relativePath in $Paths) {
$fullPath = Join-Path $repoRoot $relativePath
if (-not (Test-Path -LiteralPath $fullPath -PathType Leaf)) {
$missing += $relativePath
}
}
if ($missing.Count -gt 0) {
throw "$Action requires a complete source tree. Missing files: $($missing -join ', ')"
}
}
function Resolve-Version {
param([string]$ExplicitVersion)
$explicit = Get-TrimmedText $ExplicitVersion
if ($explicit -ne "") {
$script:ResolvedVersion = Assert-VersionValue -Value $explicit -Source "传入版本号"
Write-Host "[1/3] 使用传入版本号..."
Write-Host "✓ 版本号: $script:ResolvedVersion"
Write-Host ""
return
}
Write-Host "[1/3] 读取版本号..."
$wailsConfigPath = Join-Path $repoRoot "wails.json"
if (-not (Test-Path -LiteralPath $wailsConfigPath -PathType Leaf)) {
throw "无法读取版本号:缺少 wails.json"
}
$wailsConfig = Get-Content -LiteralPath $wailsConfigPath -Raw | ConvertFrom-Json
$resolvedVersion = Get-TrimmedText ([string]$wailsConfig.info.productVersion)
if ($resolvedVersion -eq "") {
throw "无法从 wails.json 读取版本号"
}
$script:ResolvedVersion = Assert-VersionValue -Value $resolvedVersion -Source "wails.json productVersion"
Write-Host "✓ 版本号: $script:ResolvedVersion"
Write-Host ""
}
function Invoke-WithTemporaryWailsVersion {
param(
[Parameter(Mandatory = $true)]
[scriptblock]$ScriptBlock
)
$wailsConfigPath = Join-Path $repoRoot "wails.json"
if (-not (Test-Path -LiteralPath $wailsConfigPath -PathType Leaf)) {
& $ScriptBlock
return
}
$currentConfig = Get-Content -LiteralPath $wailsConfigPath -Raw | ConvertFrom-Json
$currentVersion = Get-TrimmedText ([string]$currentConfig.info.productVersion)
if ($currentVersion -eq $script:ResolvedVersion) {
& $ScriptBlock
return
}
Write-Host " 临时覆盖 wails.json productVersion: $currentVersion -> $script:ResolvedVersion"
$originalBytes = [System.IO.File]::ReadAllBytes($wailsConfigPath)
try {
$currentConfig.info.productVersion = $script:ResolvedVersion
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
$jsonText = ($currentConfig | ConvertTo-Json -Depth 100)
[System.IO.File]::WriteAllText($wailsConfigPath, $jsonText + "`n", $utf8NoBom)
& $ScriptBlock
}
finally {
[System.IO.File]::WriteAllBytes($wailsConfigPath, $originalBytes)
}
}
function Resolve-PublishTarget {
param([string]$InputTarget)
$normalized = (Get-TrimmedText $InputTarget).ToUpperInvariant()
$mapping = @{
"W" = "WINDOWS"
"WINDOWS" = "WINDOWS"
"L" = "LINUX"
"LINUX" = "LINUX"
"B" = "BOTH"
"BOTH" = "BOTH"
}
if ($normalized -ne "") {
if (-not $mapping.ContainsKey($normalized)) {
throw "无效的打包目标: $InputTarget`n 支持参数: W/L/B 或 WINDOWS/LINUX/BOTH"
}
$resolvedTarget = $mapping[$normalized]
Write-Host "[2/3] 使用预设打包目标: $resolvedTarget"
Write-Host ""
return $resolvedTarget
}
Write-Host "[2/3] 选择打包平台..."
Write-Host ""
Write-Host " [W] Windows"
Write-Host " [L] Linux(通过 Docker Desktop 执行)"
Write-Host " [B] Windows + Linux"
Write-Host ""
while ($true) {
$choice = (Read-Host "请选择打包目标 [W/L/B]").Trim().ToUpperInvariant()
if ($choice -eq "") {
continue
}
if ($mapping.ContainsKey($choice)) {
$resolvedTarget = $mapping[$choice]
Write-Host "✓ 已选择: $resolvedTarget"
Write-Host ""
return $resolvedTarget
}
Write-Host "✗ 未选择有效目标" -ForegroundColor Yellow
}
}
function Resolve-WindowsFormat {
param(
[string]$InputFormat,
[string]$PublishTarget,
[bool]$Interactive
)
$normalized = (Get-TrimmedText $InputFormat).ToUpperInvariant()
if ($normalized -ne "") {
if ($normalized -notin @("INSTALLER", "PORTABLE", "BOTH")) {
throw "无效的 Windows 输出格式: $InputFormat`n 支持参数: INSTALLER/PORTABLE/BOTH"
}
return $normalized
}
if ($PublishTarget -notin @("WINDOWS", "BOTH") -or -not $Interactive) {
return "INSTALLER"
}
$formatMapping = @{
"I" = "INSTALLER"
"INSTALLER" = "INSTALLER"
"Z" = "PORTABLE"
"ZIP" = "PORTABLE"
"P" = "PORTABLE"
"PORTABLE" = "PORTABLE"
"B" = "BOTH"
"BOTH" = "BOTH"
}
Write-Host "[2/3] 选择 Windows 输出格式..."
Write-Host ""
Write-Host " [I] 安装包(默认)"
Write-Host " [Z] 便携 ZIP"
Write-Host " [B] 安装包 + 便携 ZIP"
Write-Host ""
while ($true) {
$choice = (Read-Host "请选择 Windows 输出格式 [I/Z/B]").Trim().ToUpperInvariant()
if ($choice -eq "") {
$choice = "I"
}
if ($formatMapping.ContainsKey($choice)) {
$resolvedFormat = $formatMapping[$choice]
Write-Host "✓ 已选择: $resolvedFormat"
Write-Host ""
return $resolvedFormat
}
Write-Host "✗ 未选择有效输出格式" -ForegroundColor Yellow
}
}
function Resolve-NsisPath {
Write-Host "[Windows] 检测 NSIS 安装..."
Write-Host " 支持环境变量:MAKENSIS_PATH / NSIS_PATH / NSIS_HOME"
Write-Host ""
$candidates = @()
if ($env:MAKENSIS_PATH) {
$candidates += $env:MAKENSIS_PATH
}
if ($env:NSIS_PATH) {
$candidates += (Join-Path $env:NSIS_PATH "makensis.exe")
$candidates += $env:NSIS_PATH
}
if ($env:NSIS_HOME) {
$candidates += (Join-Path $env:NSIS_HOME "makensis.exe")
}
$whereMakensis = Get-Command makensis.exe -ErrorAction SilentlyContinue
if ($whereMakensis) {
$candidates += $whereMakensis.Source
}
$candidates += @(
"C:\Program Files (x86)\NSIS\makensis.exe",
"C:\Program Files\NSIS\makensis.exe"
)
foreach ($candidate in $candidates) {
$value = Get-TrimmedText $candidate
if ($value -eq "") {
continue
}
if (Test-Path -LiteralPath $value -PathType Leaf) {
Write-Host "✓ NSIS 已就绪: $value"
Write-Host ""
return $value
}
}
throw "未找到 NSISmakensis.exe`n`n 请安装 NSIS 后,通过以下任一方式配置(PowerShell):`n setx MAKENSIS_PATH ""D:\tools\NSIS\makensis.exe""`n setx NSIS_PATH ""D:\tools\NSIS""`n setx NSIS_HOME ""D:\tools\NSIS""`n`n 或下载安装:https://nsis.sourceforge.io/Download"
}
function Build-WindowsBinary {
Write-Host "[Windows] 执行 Wails 构建..."
$binaryPath = Join-Path $repoRoot "build/bin/ant-chrome.exe"
Assert-RequiredSourceFiles -Action "Windows packaging" -Paths @(
"go.mod",
"go.sum",
"main.go",
"wails.json"
)
$previousGoProxy = $env:GOPROXY
try {
$env:GOPROXY = "https://goproxy.cn,direct"
Push-Location (Join-Path $repoRoot "frontend")
try {
Write-Host "[Windows] 预检前端依赖..."
Invoke-NativeCommand -FilePath "npm" -Arguments @("ci", "--prefer-offline", "--no-audit", "--no-fund")
Invoke-NativeCommand -FilePath "npm" -Arguments @("run", "ensure:native")
Write-Host "✓ 前端依赖已就绪"
Write-Host ""
}
finally {
Pop-Location
}
Invoke-NativeCommand -FilePath "wails" -Arguments @("build")
}
finally {
$env:GOPROXY = $previousGoProxy
}
if (-not (Test-Path -LiteralPath $binaryPath -PathType Leaf)) {
throw "构建产物不存在: build\bin\ant-chrome.exe"
}
Write-Host "✓ 构建成功: build\bin\ant-chrome.exe"
Write-Host ""
}
function Assert-RuntimeHashes {
param(
[Parameter(Mandatory = $true)]
[string]$Target
)
$manifestPath = Join-Path $repoRoot "publish/runtime-manifest.json"
if (-not (Test-Path -LiteralPath $manifestPath -PathType Leaf)) {
throw "缺少运行时清单: publish\runtime-manifest.json"
}
Write-Host "[Windows] 校验运行时哈希..."
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
$entries = @($manifest.files | Where-Object { $_.targets -contains $Target })
if ($entries.Count -eq 0) {
throw "运行时清单中不存在目标平台: $Target"
}
$errors = New-Object System.Collections.Generic.List[string]
foreach ($entry in $entries) {
$relativePath = Get-TrimmedText ([string]$entry.path)
$expectedHash = (Get-TrimmedText ([string]$entry.sha256)).ToLowerInvariant()
if ($relativePath -eq "") {
$errors.Add("manifest entry has empty path")
continue
}
if ($expectedHash -eq "" -or $expectedHash.Contains("todo_replace_with_sha256")) {
$errors.Add("${relativePath}: sha256 is not initialized")
continue
}
$fullPath = Join-Path $repoRoot ($relativePath -replace '/', [System.IO.Path]::DirectorySeparatorChar)
if (-not (Test-Path -LiteralPath $fullPath -PathType Leaf)) {
$errors.Add("${relativePath}: file not found")
continue
}
$actualHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $fullPath).Hash.ToLowerInvariant()
if ($actualHash -ne $expectedHash) {
$errors.Add("${relativePath}: sha256 mismatch (expected $expectedHash, got $actualHash)")
}
}
if ($errors.Count -gt 0) {
throw "运行时哈希校验失败:`n - $($errors -join "`n - ")"
}
Write-Host "✓ 运行时哈希校验通过: $Target"
Write-Host ""
}
function Test-PeExecutable {
param(
[Parameter(Mandatory = $true)]
[string]$FilePath
)
if (-not (Test-Path -LiteralPath $FilePath -PathType Leaf)) {
return $false
}
try {
$stream = [System.IO.File]::OpenRead($FilePath)
try {
if ($stream.Length -lt 2) {
return $false
}
$header = New-Object byte[] 2
$read = $stream.Read($header, 0, $header.Length)
return ($read -eq 2 -and $header[0] -eq 0x4D -and $header[1] -eq 0x5A)
}
finally {
$stream.Dispose()
}
}
catch {
return $false
}
}
function Copy-DirectoryContents {
param(
[Parameter(Mandatory = $true)]
[string]$SourceDir,
[Parameter(Mandatory = $true)]
[string]$DestinationDir
)
if (-not (Test-Path -LiteralPath $SourceDir -PathType Container)) {
return
}
New-Item -ItemType Directory -Path $DestinationDir -Force | Out-Null
foreach ($entry in (Get-ChildItem -LiteralPath $SourceDir -Force)) {
Copy-Item -LiteralPath $entry.FullName -Destination (Join-Path $DestinationDir $entry.Name) -Recurse -Force
}
}
function Copy-WindowsChromePayload {
param(
[Parameter(Mandatory = $true)]
[string]$ChromeRoot,
[Parameter(Mandatory = $true)]
[string]$StagingDir
)
if (-not (Test-Path -LiteralPath $ChromeRoot -PathType Container)) {
Write-Host "[WARN] 缺少 chrome\ 目录,Windows 安装包将不包含浏览器内核"
return
}
$stagingChromeDir = Join-Path $StagingDir "chrome"
$chromeReadme = Join-Path $ChromeRoot "README.md"
$copiedCores = @()
$rootExecutable = Join-Path $ChromeRoot "chrome.exe"
if (Test-PeExecutable -FilePath $rootExecutable) {
Copy-DirectoryContents -SourceDir $ChromeRoot -DestinationDir $stagingChromeDir
$copiedCores += "chrome\"
}
else {
if (Test-Path -LiteralPath $chromeReadme -PathType Leaf) {
New-Item -ItemType Directory -Path $stagingChromeDir -Force | Out-Null
Copy-Item -LiteralPath $chromeReadme -Destination (Join-Path $stagingChromeDir "README.md") -Force
}
foreach ($entry in (Get-ChildItem -LiteralPath $ChromeRoot -Force)) {
if (-not $entry.PSIsContainer) {
continue
}
$candidateExe = Join-Path $entry.FullName "chrome.exe"
if (-not (Test-PeExecutable -FilePath $candidateExe)) {
continue
}
New-Item -ItemType Directory -Path $stagingChromeDir -Force | Out-Null
Copy-Item -LiteralPath $entry.FullName -Destination (Join-Path $stagingChromeDir $entry.Name) -Recurse -Force
$copiedCores += $entry.Name
}
}
if ($copiedCores.Count -gt 0) {
Write-Host ("✓ 自动打包 Windows 内核: {0}" -f ($copiedCores -join ", "))
return
}
if (Test-Path -LiteralPath $chromeReadme -PathType Leaf) {
Write-Host "✓ 保留 chrome\README.md(未发现可打包的 Windows 内核)"
}
else {
Write-Host "[WARN] 未发现可打包的 Windows 内核,且缺少 chrome\README.md"
}
}
function New-WindowsStaging {
Write-Host "[Windows] 组装 staging 目录..."
$stagingDir = Join-Path $repoRoot "publish/staging"
$releaseConfig = Join-Path $repoRoot "publish/config.init.yaml"
$binaryPath = Join-Path $repoRoot "build/bin/ant-chrome.exe"
$binDir = Join-Path $repoRoot "bin"
$chromeRoot = Join-Path $repoRoot "chrome"
if (Test-Path -LiteralPath $stagingDir) {
Remove-Item -LiteralPath $stagingDir -Recurse -Force
}
New-Item -ItemType Directory -Path $stagingDir -Force | Out-Null
Copy-Item -LiteralPath $binaryPath -Destination (Join-Path $stagingDir "ant-chrome.exe") -Force
if (-not (Test-Path -LiteralPath (Join-Path $stagingDir "ant-chrome.exe") -PathType Leaf)) {
throw "staging 中缺少 ant-chrome.exe"
}
Write-Host "✓ 复制 ant-chrome.exe"
if (-not (Test-Path -LiteralPath $releaseConfig -PathType Leaf)) {
throw "未找到发布配置模板: publish\config.init.yaml"
}
Copy-Item -LiteralPath $releaseConfig -Destination (Join-Path $stagingDir "config.yaml") -Force
Write-Host "✓ 复制发布配置模板 publish\config.init.yaml -> config.yaml"
$stagingBinDir = Join-Path $stagingDir "bin"
New-Item -ItemType Directory -Path $stagingBinDir -Force | Out-Null
foreach ($required in @("xray.exe", "sing-box.exe")) {
$source = Join-Path $binDir $required
if (-not (Test-Path -LiteralPath $source -PathType Leaf)) {
throw "缺少运行时文件: bin\$required"
}
Copy-Item -LiteralPath $source -Destination (Join-Path $stagingBinDir $required) -Force
}
Write-Host "✓ 复制 bin\xray.exe, sing-box.exe"
Copy-WindowsChromePayload -ChromeRoot $chromeRoot -StagingDir $stagingDir
New-Item -ItemType Directory -Path (Join-Path $stagingDir "data") -Force | Out-Null
Write-Host "✓ 创建空 data 目录(不打包 app.db,首次启动自动初始化)"
Write-Host ""
Write-Host "✓ staging 目录组装完成"
Write-Host ""
return $stagingDir
}
function Invoke-WindowsPackaging {
param(
[Parameter(Mandatory = $true)]
[string]$MakensisPath,
[Parameter(Mandatory = $true)]
[string]$StagingDir
)
Write-Host "[Windows] 调用 NSIS 打包..."
$outputDir = Join-Path $repoRoot "publish/output"
if (-not (Test-Path -LiteralPath $outputDir)) {
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
}
$installerPath = Join-Path $repoRoot "publish/installer.nsi"
$installerContent = [System.IO.File]::ReadAllText($installerPath, [System.Text.Encoding]::UTF8)
[System.IO.File]::WriteAllText($installerPath, $installerContent, [System.Text.UTF8Encoding]::new($true))
$stagingAbs = (Resolve-Path $StagingDir).Path
$compressionMode = if ($env:ANT_BROWSER_PUBLISH_BEST_COMPRESSION -eq "1") { "best" } else { "fast" }
$useNsisConfig = ($env:ANT_BROWSER_NSIS_USE_CONFIG -eq "1")
Write-Host " 压缩模式: $compressionMode"
if ($useNsisConfig) {
Write-Host " NSIS 全局配置: enabled"
}
else {
Write-Host " NSIS 全局配置: disabled (/NOCONFIG)"
}
$nsisArguments = @(
"/DVERSION=$script:ResolvedVersion",
"/DSTAGINGDIR=$stagingAbs",
"publish\installer.nsi"
)
if (-not $useNsisConfig) {
$nsisArguments = @("/NOCONFIG") + $nsisArguments
}
if ($compressionMode -eq "best") {
$nsisArguments = @("/DBESTCOMPRESSION") + $nsisArguments
}
Invoke-NativeCommand -FilePath $MakensisPath -Arguments $nsisArguments
Write-Host "✓ Windows 安装包生成成功"
Write-Host ""
}
function New-WindowsPortableArchive {
param(
[Parameter(Mandatory = $true)]
[string]$StagingDir
)
Write-Host "[Windows] 生成便携 ZIP..."
$outputDir = Join-Path $repoRoot "publish/output"
if (-not (Test-Path -LiteralPath $outputDir)) {
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
}
$archiveName = "AntBrowser-$script:ResolvedVersion-windows-amd64-portable.zip"
$archivePath = Join-Path $outputDir $archiveName
$rootName = "AntBrowser-$script:ResolvedVersion-windows-amd64-portable"
if (Test-Path -LiteralPath $archivePath) {
Remove-Item -LiteralPath $archivePath -Force
}
Add-Type -AssemblyName System.IO.Compression
$archiveStream = [System.IO.File]::Open(
$archivePath,
[System.IO.FileMode]::CreateNew,
[System.IO.FileAccess]::Write,
[System.IO.FileShare]::None
)
try {
$archive = New-Object System.IO.Compression.ZipArchive(
$archiveStream,
[System.IO.Compression.ZipArchiveMode]::Create,
$false
)
try {
$archive.CreateEntry("$rootName/") | Out-Null
foreach ($directory in (Get-ChildItem -LiteralPath $StagingDir -Directory -Recurse -Force)) {
$relativePath = $directory.FullName.Substring($StagingDir.Length).TrimStart('\', '/')
$entryName = "$rootName/$($relativePath.Replace('\', '/'))/"
$archive.CreateEntry($entryName) | Out-Null
}
foreach ($file in (Get-ChildItem -LiteralPath $StagingDir -File -Recurse -Force)) {
$relativePath = $file.FullName.Substring($StagingDir.Length).TrimStart('\', '/')
$entryName = "$rootName/$($relativePath.Replace('\', '/'))"
$entry = $archive.CreateEntry(
$entryName,
[System.IO.Compression.CompressionLevel]::Optimal
)
$inputStream = [System.IO.File]::OpenRead($file.FullName)
$outputStream = $entry.Open()
try {
$inputStream.CopyTo($outputStream)
}
finally {
$outputStream.Dispose()
$inputStream.Dispose()
}
}
}
finally {
$archive.Dispose()
}
}
finally {
$archiveStream.Dispose()
}
if (-not (Test-Path -LiteralPath $archivePath -PathType Leaf)) {
throw "便携 ZIP 生成失败: $archivePath"
}
$script:WindowsPortableDone = $true
Write-Host "✓ Windows 便携包生成成功: publish\output\$archiveName"
Write-Host ""
return $archivePath
}
function Remove-WindowsStaging {
param([string]$StagingDir)
if ($StagingDir -and (Test-Path -LiteralPath $StagingDir)) {
Write-Host "[Windows] 清理临时文件..."
Remove-Item -LiteralPath $StagingDir -Recurse -Force
Write-Host "✓ staging 目录已清理"
Write-Host ""
}
}
function Publish-Windows {
param(
[Parameter(Mandatory = $true)]
[string]$Format
)
Write-Host "[3/3] 开始 Windows 打包..."
Write-Host " 输出格式: $Format"
Write-Host ""
$makensisPath = $null
if ($Format -in @("INSTALLER", "BOTH")) {
$makensisPath = Resolve-NsisPath
}
Assert-RuntimeHashes -Target "windows-amd64"
Build-WindowsBinary
$stagingDir = $null
try {
$stagingDir = New-WindowsStaging
if ($Format -in @("INSTALLER", "BOTH")) {
Invoke-WindowsPackaging -MakensisPath $makensisPath -StagingDir $stagingDir
$script:WindowsInstallerDone = $true
}
if ($Format -in @("PORTABLE", "BOTH")) {
New-WindowsPortableArchive -StagingDir $stagingDir | Out-Null
}
}
finally {
Remove-WindowsStaging -StagingDir $stagingDir
}
Write-Host "✓ Windows 打包完成"
Write-Host ""
}
function Publish-Linux {
Write-Host "[3/3] 开始 Linux 打包..."
Write-Host ""
$linuxScript = Join-Path $repoRoot "publish/linux/publish-linux-docker.ps1"
$archOutFile = Join-Path $env:TEMP ("ant-browser-linux-arch-" + [guid]::NewGuid().ToString("N") + ".txt")
if (Test-Path -LiteralPath $archOutFile) {
Remove-Item -LiteralPath $archOutFile -Force
}
try {
& powershell -NoProfile -ExecutionPolicy Bypass -File $linuxScript -RepoRoot $repoRoot -ArchOutFile $archOutFile -Version $script:ResolvedVersion
if ($LASTEXITCODE -ne 0) {
throw "Linux 打包失败"
}
if (Test-Path -LiteralPath $archOutFile -PathType Leaf) {
$script:LinuxArch = (Get-Content -LiteralPath $archOutFile -Raw).Trim()
}
}
finally {
Remove-Item -LiteralPath $archOutFile -Force -ErrorAction SilentlyContinue
}
$script:LinuxDone = $true
Write-Host "✓ Linux 打包完成"
Write-Host ""
}
try {
Write-Section "Ant Browser - 发布打包脚本"
Write-Host ""
Write-Host "当前工作目录: $repoRoot"
Write-Host ""
Resolve-Version -ExplicitVersion $Version
$targetWasProvided = (Get-TrimmedText $Target) -ne ""
$publishTarget = Resolve-PublishTarget -InputTarget $Target
$resolvedWindowsFormat = Resolve-WindowsFormat -InputFormat $WindowsFormat -PublishTarget $publishTarget -Interactive (-not $targetWasProvided)
Invoke-WithTemporaryWailsVersion {
switch ($publishTarget) {
"WINDOWS" {
Publish-Windows -Format $resolvedWindowsFormat
}
"LINUX" {
Publish-Linux
}
"BOTH" {
Publish-Windows -Format $resolvedWindowsFormat
Publish-Linux
}
default {
throw "不支持的打包目标: $publishTarget"
}
}
}
Write-Host ""
Write-Section "✓ 发布完成!"
Write-Host ""
if ($script:WindowsInstallerDone) {
Write-Host "Windows 安装包: publish\output\AntBrowser-Setup-$script:ResolvedVersion.exe"
}
if ($script:WindowsPortableDone) {
Write-Host "Windows 便携包: publish\output\AntBrowser-$script:ResolvedVersion-windows-amd64-portable.zip"
}
if ($script:LinuxDone) {
Write-Host "Linux 产物目录: publish\output\"
if ($script:LinuxArch -ne "") {
Write-Host "Linux 架构: $script:LinuxArch"
}
}
Write-Host ""
Write-Host "提示:用户安装后可将旧的 data\ 目录粘贴到安装目录覆盖初始数据"
exit 0
}
catch {
Write-Host ""
Write-Section "✗ 发布失败"
Write-Host ""
Write-Host $_.Exception.Message
exit 1
}