Modules/businessdev.ALbuild.Containers/Private/Repair-BcArtifactCache.ps1
|
function Repair-BcArtifactCache { <# .SYNOPSIS Removes an incomplete/corrupt BC artifact from the shared cache so the container re-downloads it. .DESCRIPTION The BC container downloads its artifact into the mounted cache (host BcArtifactCacheFolder -> C:\dl) on first run and reuses it thereafter. An interrupted download - a killed container, an agent restart, a full disk, a dropped network - leaves the artifact folder present but INCOMPLETE (e.g. without 'manifest.json'). The image then finds the folder, assumes the artifact is cached, skips the re-download, and exits immediately with "Cannot find path 'C:\dl\<type>\<version>\<country>\manifest.json'". This validates the cached app (country) and platform artifacts for the given URL and deletes any that are incomplete, so the next container start performs a clean re-download. Validity: * app/country folder - must contain a PARSEABLE 'manifest.json' (exactly what the image reads). * platform folder - a parseable 'manifest.json' OR a 'lastused' marker with real content (older BC platform artifacts ship no manifest.json but always get a 'lastused' file on a completed download). A folder that does not exist is fine (nothing cached yet - the container will download it). .PARAMETER CacheFolder The host artifact cache mounted into the container at C:\dl (BcArtifactCacheFolder). .PARAMETER ArtifactUrl The artifact URL of the form https://.../{type}/{version}/{country}. .OUTPUTS System.String[] - the cache folders that were removed (empty when everything is valid/absent). #> [CmdletBinding(SupportsShouldProcess)] [OutputType([string[]])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $CacheFolder, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ArtifactUrl ) if (-not (Test-Path -LiteralPath $CacheFolder)) { return @() } # Parse .../{type}/{version}/{country} (query strings / SAS tokens are ignored by AbsolutePath). try { $segments = ([uri]$ArtifactUrl).AbsolutePath.Trim('/').Split('/') } catch { Write-ALbuildLog -Level Verbose "Could not parse artifact URL '$ArtifactUrl' for cache validation; skipping."; return @() } if ($segments.Count -lt 3) { Write-ALbuildLog -Level Verbose "Artifact URL '$ArtifactUrl' is not {type}/{version}/{country}; skipping cache validation."; return @() } $type = $segments[0]; $version = $segments[1]; $country = $segments[2] $versionRoot = Join-Path (Join-Path $CacheFolder $type) $version # A folder is complete when it has a parseable manifest.json; a platform folder may instead carry # only the 'lastused' completion marker (older BC platform artifacts have no manifest.json). $isComplete = { param([string] $Folder, [bool] $AllowLastUsedMarker) $manifest = Join-Path $Folder 'manifest.json' if (Test-Path -LiteralPath $manifest) { try { $null = Get-Content -LiteralPath $manifest -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop; return $true } catch { return $false } # present but truncated/corrupt JSON } if ($AllowLastUsedMarker -and (Test-Path -LiteralPath (Join-Path $Folder 'lastused'))) { return @(Get-ChildItem -LiteralPath $Folder -Force -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne 'lastused' }).Count -gt 0 } return $false } $removed = [System.Collections.Generic.List[string]]::new() $targets = @( [PSCustomObject]@{ Folder = (Join-Path $versionRoot $country); AllowLastUsedMarker = $false } # app: image requires manifest.json [PSCustomObject]@{ Folder = (Join-Path $versionRoot 'platform'); AllowLastUsedMarker = $true } ) foreach ($t in $targets) { if (-not (Test-Path -LiteralPath $t.Folder)) { continue } if (& $isComplete $t.Folder $t.AllowLastUsedMarker) { continue } Write-ALbuildLog -Level Warning "Cached BC artifact at '$($t.Folder)' is incomplete/corrupt (no valid manifest); removing it so the container re-downloads a clean copy." if ($PSCmdlet.ShouldProcess($t.Folder, 'Remove incomplete cached BC artifact')) { try { Remove-Item -LiteralPath $t.Folder -Recurse -Force -ErrorAction Stop; $removed.Add($t.Folder) } catch { Write-ALbuildLog -Level Warning "Could not remove '$($t.Folder)': $($_.Exception.Message). A stale artifact may still cause the container to fail; clear it manually." } } } if ($removed.Count -eq 0) { Write-ALbuildLog -Level Verbose "Cached BC artifact for '$type/$version/$country' is valid (or not yet present)." } return $removed.ToArray() } |