150 lines
6.4 KiB
PowerShell
150 lines
6.4 KiB
PowerShell
param(
|
|
[string]$SourceDir = "",
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ConfigFile,
|
|
[string]$OutputDir = "",
|
|
[string]$ZipFile = ""
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$RepoRoot = Split-Path -Parent $PSScriptRoot
|
|
if ([string]::IsNullOrWhiteSpace($SourceDir)) {
|
|
$SourceDir = Join-Path $RepoRoot "out/bin"
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
|
|
$OutputDir = Join-Path $RepoRoot "dist/UpdateClient"
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($ZipFile)) {
|
|
$ZipFile = Join-Path $RepoRoot "dist/UpdateClient.zip"
|
|
}
|
|
|
|
$source = (Resolve-Path $SourceDir).Path
|
|
$config = (Resolve-Path $ConfigFile).Path
|
|
$settings = Get-Content $config -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
|
|
function Normalize-RelativePath([string]$PathValue) {
|
|
return ($PathValue -replace '\\', '/').Trim('/')
|
|
}
|
|
|
|
function Get-RelativePathUnderSource([string]$FullPath, [string]$Fallback) {
|
|
$full = (Resolve-Path $FullPath).Path
|
|
if ($full.StartsWith($source, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
return Normalize-RelativePath ($full.Substring($source.Length).TrimStart('\', '/'))
|
|
}
|
|
return Normalize-RelativePath $Fallback
|
|
}
|
|
|
|
$configRelativePath = Get-RelativePathUnderSource $config "config/app_config.json"
|
|
$configRelativeParent = Split-Path $configRelativePath -Parent
|
|
$runtimeDirRelative = Normalize-RelativePath (Split-Path $configRelativeParent -Parent)
|
|
if ($runtimeDirRelative -eq ".") { $runtimeDirRelative = "" }
|
|
|
|
function Join-RelativePath([string]$Base, [string]$Child) {
|
|
$baseNorm = Normalize-RelativePath $Base
|
|
$childNorm = Normalize-RelativePath $Child
|
|
if ([string]::IsNullOrWhiteSpace($baseNorm)) { return $childNorm }
|
|
if ([string]::IsNullOrWhiteSpace($childNorm)) { return $baseNorm }
|
|
return "$baseNorm/$childNorm"
|
|
}
|
|
|
|
$requiredFields = @(
|
|
"app_id", "channel", "api_base_url", "current_version",
|
|
"client_token", "launch_token", "license_key",
|
|
"main_executable", "launcher_executable", "updater_executable", "bootstrap_executable"
|
|
)
|
|
foreach ($field in $requiredFields) {
|
|
if (-not $settings.$field) {
|
|
throw "Config file is missing required field: $field"
|
|
}
|
|
}
|
|
|
|
$mainExecutable = Normalize-RelativePath $settings.main_executable
|
|
$launcherExecutable = Normalize-RelativePath $settings.launcher_executable
|
|
$updaterExecutable = Normalize-RelativePath $settings.updater_executable
|
|
$bootstrapExecutable = Normalize-RelativePath $settings.bootstrap_executable
|
|
|
|
$requiredFiles = @(
|
|
(Join-RelativePath $runtimeDirRelative $mainExecutable),
|
|
(Join-RelativePath $runtimeDirRelative $launcherExecutable),
|
|
(Join-RelativePath $runtimeDirRelative $updaterExecutable),
|
|
(Join-RelativePath $runtimeDirRelative $bootstrapExecutable)
|
|
)
|
|
foreach ($name in $requiredFiles) {
|
|
$nativeName = $name -replace '/', [IO.Path]::DirectorySeparatorChar
|
|
if (-not (Test-Path (Join-Path $source $nativeName))) {
|
|
throw "Source directory is missing required file: $name"
|
|
}
|
|
}
|
|
|
|
$debugArtifacts = Get-ChildItem $source -Recurse -File | Where-Object {
|
|
$_.Name -match '^(Qt5.*d|qwindowsd|libEGLd|libGLESv2d|msvcp.*d|vcruntime.*d)\.dll$' -or
|
|
$_.Extension -in @('.pdb', '.ilk')
|
|
}
|
|
if ($debugArtifacts) {
|
|
throw "Source directory contains Debug artifacts. Clean out/bin and rebuild Release first. Example: $($debugArtifacts[0].FullName)"
|
|
}
|
|
|
|
$expectedMainPath = Join-RelativePath $runtimeDirRelative $mainExecutable
|
|
$mainLeafName = Split-Path $mainExecutable -Leaf
|
|
$duplicateMain = Get-ChildItem $source -Recurse -File -Filter $mainLeafName | Where-Object {
|
|
$relative = Normalize-RelativePath ($_.FullName.Substring($source.Length).TrimStart('\', '/'))
|
|
$relative -ne $expectedMainPath
|
|
} | Select-Object -First 1
|
|
if ($duplicateMain) {
|
|
throw "Source directory contains a duplicate main executable outside $expectedMainPath. Use a clean Release root directory: $($duplicateMain.FullName)"
|
|
}
|
|
|
|
$manifestName = "manifest_$($settings.current_version).json"
|
|
$sourceManifestRelative = Join-RelativePath $runtimeDirRelative "update/manifest_cache/$manifestName"
|
|
$sourceManifest = Join-Path $source ($sourceManifestRelative -replace '/', [IO.Path]::DirectorySeparatorChar)
|
|
if (-not (Test-Path $sourceManifest)) {
|
|
$legacySourceManifest = Join-Path $source "update/manifest_cache/$manifestName"
|
|
if (Test-Path $legacySourceManifest) {
|
|
$sourceManifest = $legacySourceManifest
|
|
}
|
|
}
|
|
if (-not (Test-Path $sourceManifest)) {
|
|
throw "Missing signed Manifest cache for current version: $sourceManifest. Complete online update/verification for this version before packaging."
|
|
}
|
|
|
|
if (Test-Path $OutputDir) {
|
|
Remove-Item $OutputDir -Recurse -Force
|
|
}
|
|
New-Item $OutputDir -ItemType Directory -Force | Out-Null
|
|
|
|
Get-ChildItem $source -Force | Where-Object {
|
|
$_.Name -notin @("update", "update_temp")
|
|
} | Copy-Item -Destination $OutputDir -Recurse -Force
|
|
|
|
$outputRuntimeUpdateDir = Join-Path $OutputDir ((Join-RelativePath $runtimeDirRelative "update") -replace '/', [IO.Path]::DirectorySeparatorChar)
|
|
if (Test-Path $outputRuntimeUpdateDir) {
|
|
Remove-Item $outputRuntimeUpdateDir -Recurse -Force
|
|
}
|
|
$outputRuntimeTempDir = Join-Path $OutputDir ((Join-RelativePath $runtimeDirRelative "update_temp") -replace '/', [IO.Path]::DirectorySeparatorChar)
|
|
if (Test-Path $outputRuntimeTempDir) {
|
|
Remove-Item $outputRuntimeTempDir -Recurse -Force
|
|
}
|
|
|
|
$outputConfigPath = Join-Path $OutputDir ($configRelativePath -replace '/', [IO.Path]::DirectorySeparatorChar)
|
|
$outputConfigDir = Split-Path $outputConfigPath -Parent
|
|
New-Item $outputConfigDir -ItemType Directory -Force | Out-Null
|
|
Copy-Item $config $outputConfigPath -Force
|
|
|
|
@("client_identity.dat", "local_state.json", "version_policy.dat") | ForEach-Object {
|
|
$runtimeFile = Join-Path $outputConfigDir $_
|
|
if (Test-Path $runtimeFile) { Remove-Item $runtimeFile -Force }
|
|
}
|
|
|
|
$manifestDir = Join-Path $OutputDir ((Join-RelativePath $runtimeDirRelative "update/manifest_cache") -replace '/', [IO.Path]::DirectorySeparatorChar)
|
|
New-Item $manifestDir -ItemType Directory -Force | Out-Null
|
|
Copy-Item $sourceManifest (Join-Path $manifestDir $manifestName) -Force
|
|
|
|
$zipParent = Split-Path $ZipFile -Parent
|
|
New-Item $zipParent -ItemType Directory -Force | Out-Null
|
|
if (Test-Path $ZipFile) { Remove-Item $ZipFile -Force }
|
|
Compress-Archive -Path (Join-Path $OutputDir "*") -DestinationPath $ZipFile -CompressionLevel Optimal
|
|
|
|
Write-Host "Package directory: $OutputDir"
|
|
Write-Host "ZIP file: $ZipFile"
|