param( [string]$SourceDir = "$PSScriptRoot/out/bin", [Parameter(Mandatory = $true)] [string]$ConfigFile, [string]$OutputDir = "$PSScriptRoot/dist/UpdateClient", [string]$ZipFile = "$PSScriptRoot/dist/UpdateClient.zip" ) $ErrorActionPreference = "Stop" $source = (Resolve-Path $SourceDir).Path $config = (Resolve-Path $ConfigFile).Path $settings = Get-Content $config -Raw -Encoding UTF8 | ConvertFrom-Json $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" } } $requiredFiles = @( $settings.main_executable, $settings.launcher_executable, $settings.updater_executable, $settings.bootstrap_executable ) foreach ($name in $requiredFiles) { if (-not (Test-Path (Join-Path $source $name))) { 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)" } $nestedMain = Get-ChildItem $source -Recurse -File -Filter $settings.main_executable | Where-Object { $_.DirectoryName -ne $source } | Select-Object -First 1 if ($nestedMain) { throw "Source directory contains a nested duplicate main executable. Use a clean Release root directory: $($nestedMain.FullName)" } $manifestName = "manifest_$($settings.current_version).json" $sourceManifest = Join-Path $source "update/manifest_cache/$manifestName" 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 $outputConfigDir = Join-Path $OutputDir "config" New-Item $outputConfigDir -ItemType Directory -Force | Out-Null Copy-Item $config (Join-Path $outputConfigDir "app_config.json") -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 "update/manifest_cache" 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"