255 lines
9.3 KiB
PowerShell
255 lines
9.3 KiB
PowerShell
$script:MoonWellExtensionNames = @(
|
|
'MoonWell',
|
|
'wxl-db2',
|
|
'wxl-fdid-moonwell',
|
|
'wxl-grasswind',
|
|
'wxl-modern-adt',
|
|
'wxl-modern-blp',
|
|
'wxl-modern-m2',
|
|
'wxl-modern-wmo',
|
|
'wxl-moonwell-storage-fallback',
|
|
'wxl-unit-outline'
|
|
)
|
|
|
|
$patchLayoutPath = Join-Path $PSScriptRoot 'patch-layout.json'
|
|
if (-not (Test-Path -LiteralPath $patchLayoutPath -PathType Leaf)) {
|
|
throw "Patch layout was not found: $patchLayoutPath"
|
|
}
|
|
$patchLayout = Get-Content -LiteralPath $patchLayoutPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$script:MoonWellRepositoryPatches = @($patchLayout.repositoryPatches)
|
|
$script:MoonWellGraphicsPatches = @($patchLayout.graphicsPatches)
|
|
|
|
function Get-MoonWellExtensionNames {
|
|
return @($script:MoonWellExtensionNames)
|
|
}
|
|
|
|
function Get-MoonWellRepositoryPatchPaths {
|
|
return @($script:MoonWellRepositoryPatches)
|
|
}
|
|
|
|
function Get-MoonWellGraphicsPatchPaths {
|
|
return @($script:MoonWellGraphicsPatches)
|
|
}
|
|
|
|
function Test-MoonWellRepositoryPatch {
|
|
param([Parameter(Mandatory)][string]$RelativePath)
|
|
|
|
foreach ($repositoryPatch in $script:MoonWellRepositoryPatches) {
|
|
if ($RelativePath.Replace('/', '\').Equals(
|
|
$repositoryPatch.Replace('/', '\'),
|
|
[System.StringComparison]::OrdinalIgnoreCase)) {
|
|
return $true
|
|
}
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Test-MoonWellGraphicsPatch {
|
|
param([Parameter(Mandatory)][string]$RelativePath)
|
|
|
|
foreach ($graphicsPatch in $script:MoonWellGraphicsPatches) {
|
|
if ($RelativePath.Replace('/', '\').Equals(
|
|
$graphicsPatch.Replace('/', '\'),
|
|
[System.StringComparison]::OrdinalIgnoreCase)) {
|
|
return $true
|
|
}
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Test-MoonWellPreservedDataPatch {
|
|
param([Parameter(Mandatory)][string]$RelativePath)
|
|
|
|
if (Test-MoonWellRepositoryPatch -RelativePath $RelativePath) {
|
|
return $false
|
|
}
|
|
return Test-MoonWellGraphicsPatch -RelativePath $RelativePath
|
|
}
|
|
|
|
function Assert-SafePackagePath {
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$PackagePath,
|
|
[Parameter(Mandatory)]
|
|
[string]$RepositoryPath,
|
|
[Parameter()]
|
|
[string]$ClientPath
|
|
)
|
|
|
|
$packageRoot = [System.IO.Path]::GetFullPath($PackagePath).TrimEnd('\')
|
|
$repositoryRoot = [System.IO.Path]::GetFullPath($RepositoryPath).TrimEnd('\')
|
|
$pathRoot = [System.IO.Path]::GetPathRoot($packageRoot).TrimEnd('\')
|
|
|
|
if (-not $packageRoot -or $packageRoot -eq $pathRoot) {
|
|
throw "Refusing to use a filesystem root as package staging: $packageRoot"
|
|
}
|
|
if ($packageRoot.Equals($repositoryRoot, [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$repositoryRoot.StartsWith($packageRoot + '\', [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
throw 'Package staging must not be the repository root or one of its ancestors.'
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($ClientPath)) {
|
|
$clientRoot = [System.IO.Path]::GetFullPath($ClientPath).TrimEnd('\')
|
|
$packageIsClientOrChild =
|
|
$packageRoot.Equals($clientRoot, [System.StringComparison]::OrdinalIgnoreCase) -or
|
|
$packageRoot.StartsWith($clientRoot + '\', [System.StringComparison]::OrdinalIgnoreCase)
|
|
$packageContainsClient =
|
|
$clientRoot.StartsWith($packageRoot + '\', [System.StringComparison]::OrdinalIgnoreCase)
|
|
if ($packageIsClientOrChild -or $packageContainsClient) {
|
|
throw 'Package staging must be separate from the installed client tree.'
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-RelativeFilePaths {
|
|
param([Parameter(Mandatory)][string]$Root)
|
|
|
|
if (-not (Test-Path -LiteralPath $Root -PathType Container)) {
|
|
return @()
|
|
}
|
|
|
|
$absoluteRoot = [System.IO.Path]::GetFullPath($Root).TrimEnd('\')
|
|
return @(
|
|
Get-ChildItem -LiteralPath $absoluteRoot -Recurse -Force -File |
|
|
ForEach-Object { $_.FullName.Substring($absoluteRoot.Length + 1) }
|
|
)
|
|
}
|
|
|
|
function Remove-EmptyMoonWellDirectories {
|
|
param([Parameter(Mandatory)][string]$Destination)
|
|
|
|
foreach ($relativeRoot in @('Data\Patch-WXL.MPQ', 'Extensions', 'Utils')) {
|
|
$managedRoot = Join-Path $Destination $relativeRoot
|
|
if (-not (Test-Path -LiteralPath $managedRoot -PathType Container)) {
|
|
continue
|
|
}
|
|
|
|
$directories = @(
|
|
Get-ChildItem -LiteralPath $managedRoot -Recurse -Force -Directory |
|
|
Sort-Object { $_.FullName.Length } -Descending
|
|
)
|
|
$directories += Get-Item -LiteralPath $managedRoot
|
|
|
|
foreach ($directory in $directories) {
|
|
if (-not @(Get-ChildItem -LiteralPath $directory.FullName -Force).Count) {
|
|
Remove-Item -LiteralPath $directory.FullName -Force
|
|
Write-Host "Removed empty managed directory: $($directory.FullName)"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function Reset-MoonWellPackageStaging {
|
|
param(
|
|
[Parameter(Mandatory)][string]$PackagePath,
|
|
[Parameter(Mandatory)][string]$RepositoryPath,
|
|
[Parameter(Mandatory)][string]$ClientPath
|
|
)
|
|
|
|
Assert-SafePackagePath `
|
|
-PackagePath $PackagePath `
|
|
-RepositoryPath $RepositoryPath `
|
|
-ClientPath $ClientPath
|
|
|
|
if (Test-Path -LiteralPath $PackagePath) {
|
|
Remove-Item -LiteralPath $PackagePath -Recurse -Force
|
|
}
|
|
New-Item -ItemType Directory -Path $PackagePath -Force | Out-Null
|
|
}
|
|
|
|
function Remove-MoonWellRuntimeGarbage {
|
|
param([Parameter(Mandatory)][string]$Destination)
|
|
|
|
if (-not (Test-Path -LiteralPath $Destination -PathType Container)) {
|
|
return
|
|
}
|
|
|
|
$allowedExtensions = @{}
|
|
foreach ($name in $script:MoonWellExtensionNames) {
|
|
$allowedExtensions[$name.ToLowerInvariant()] = $true
|
|
}
|
|
|
|
$extensionsRoot = Join-Path $Destination 'Extensions'
|
|
if (Test-Path -LiteralPath $extensionsRoot -PathType Container) {
|
|
foreach ($entry in Get-ChildItem -LiteralPath $extensionsRoot -Force) {
|
|
$isAllowedDirectory = $entry.PSIsContainer -and
|
|
$allowedExtensions.ContainsKey($entry.Name.ToLowerInvariant())
|
|
if (-not $isAllowedDirectory) {
|
|
Remove-Item -LiteralPath $entry.FullName -Recurse -Force
|
|
Write-Host "Removed unmanaged WarcraftXL extension artifact: $($entry.FullName)"
|
|
continue
|
|
}
|
|
|
|
foreach ($dll in Get-ChildItem -LiteralPath $entry.FullName -Force -File -Filter '*.dll') {
|
|
$expectedName = "$($entry.Name).dll"
|
|
if (-not $dll.Name.Equals($expectedName, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
Remove-Item -LiteralPath $dll.FullName -Force
|
|
Write-Host "Removed stale extension DLL: $($dll.FullName)"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($dll in Get-ChildItem -LiteralPath $Destination -Force -File -Filter 'WarcraftXL*.dll') {
|
|
if (-not $dll.Name.Equals('WarcraftXL.dll', [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
Remove-Item -LiteralPath $dll.FullName -Force
|
|
Write-Host "Removed stale WarcraftXL DLL: $($dll.FullName)"
|
|
}
|
|
}
|
|
|
|
$utilsRoot = Join-Path $Destination 'Utils'
|
|
if (Test-Path -LiteralPath $utilsRoot -PathType Container) {
|
|
foreach ($legacyFile in Get-ChildItem -LiteralPath $utilsRoot -Force -File -Filter 'WarcraftXLHost*') {
|
|
Remove-Item -LiteralPath $legacyFile.FullName -Force
|
|
Write-Host "Removed obsolete WarcraftXL 1.0 host artifact: $($legacyFile.FullName)"
|
|
}
|
|
}
|
|
|
|
# GlueXML is shipped by patch-ruRU-4.MPQ. Historical development copies in
|
|
# the client root override that archive and can restore the password form.
|
|
foreach ($relativePath in @(
|
|
'Interface\GlueXML\AccountLogin.lua',
|
|
'Interface\GlueXML\AccountLogin.xml'
|
|
)) {
|
|
$legacyOverride = Join-Path $Destination $relativePath
|
|
if (Test-Path -LiteralPath $legacyOverride -PathType Leaf) {
|
|
Remove-Item -LiteralPath $legacyOverride -Force
|
|
Write-Host "Removed obsolete loose GlueXML override: $legacyOverride"
|
|
}
|
|
}
|
|
|
|
Remove-EmptyMoonWellDirectories -Destination $Destination
|
|
}
|
|
|
|
function Remove-StalePackageFilesFromClient {
|
|
param(
|
|
[Parameter(Mandatory)][string]$ClientPath,
|
|
[Parameter(Mandatory)][AllowEmptyCollection()][string[]]$PreviousFiles,
|
|
[Parameter(Mandatory)][AllowEmptyCollection()][string[]]$CurrentFiles
|
|
)
|
|
|
|
$current = @{}
|
|
foreach ($relativePath in $CurrentFiles) {
|
|
$current[$relativePath.ToLowerInvariant()] = $true
|
|
}
|
|
|
|
$clientRoot = [System.IO.Path]::GetFullPath($ClientPath).TrimEnd('\')
|
|
foreach ($relativePath in $PreviousFiles) {
|
|
if ($current.ContainsKey($relativePath.ToLowerInvariant()) -or
|
|
(Test-MoonWellPreservedDataPatch -RelativePath $relativePath)) {
|
|
continue
|
|
}
|
|
|
|
$target = [System.IO.Path]::GetFullPath((Join-Path $clientRoot $relativePath))
|
|
if (-not $target.StartsWith($clientRoot + '\', [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
throw "Package inventory contains a path outside the client: $relativePath"
|
|
}
|
|
if (Test-Path -LiteralPath $target -PathType Leaf) {
|
|
Remove-Item -LiteralPath $target -Force
|
|
Write-Host "Removed stale packaged file from client: $target"
|
|
}
|
|
}
|
|
|
|
Remove-EmptyMoonWellDirectories -Destination $ClientPath
|
|
}
|