Modules/businessdev.ALbuild.Apps/Private/Get-BcContainerSymbolFolder.ps1
|
function Get-BcContainerSymbolFolder { <# .SYNOPSIS Selects the in-container first-party symbol (package cache) folders for a Container-engine compile. .DESCRIPTION Runs INSIDE the build container (its source is injected into the container command by Invoke-BcCompiler, because the container has no access to the module). Given the container's artifact cache and platform install, it returns the folders that hold the compiled Microsoft first-party symbol packages (Application / Base Application / System Application / Business Foundation, the test toolkit, ...) that alc needs, coping with every artifact layout: * SANDBOX: the apps sit TOP-LEVEL in '<country>\Extensions' and '<country>\Applications.<country>'. * ON-PREM: there is no 'Extensions'; the full country-specific first-party set is NESTED as '<country>\Applications\<App>\Source\Microsoft_<App>.app', and the file name carries NO version - so matching folder NAMES alone misses it. Every folder that actually holds '*.app' is taken. Two hazards are handled: * Version scoping - a shared artifact cache (self-hosted agents reuse one C:\dl / bcartifacts.cache) can hold several BC versions; feeding alc a different version's apps makes it reject ALL of them (AL1023). The search is scoped to the container's own platform major (derived from the installed 'Microsoft Dynamics NAV\<nnn>' folder, e.g. '260' -> '26.'). * Localization vs. W1 - on-prem ships both a localized '<country>\Applications' tree and a 'platform\Applications' (W1) tree. Feeding both duplicates app ids / lets the W1 copy shadow the localization (e.g. the German 'Delivery Reminder'), so '\platform\' folders are dropped whenever a country tree is present. The platform 'System.app' is added separately (it is not a country app). A widened fallback covers images/caches that keep the base symbol packages outside the artifact. .OUTPUTS PSCustomObject with SymbolFolders (string[] to pass as /packagecachepath), VersionPrefix, ApplicationFound (folders that contain a 'Microsoft_Application*.app') and Widened (fallback folders). .NOTES All roots are parameters (defaulting to the real container paths) so the selection rule can be unit-tested against fake sandbox/on-prem trees without a container. #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [string] $NavProgramFiles = 'C:\Program Files\Microsoft Dynamics NAV', [string] $DlGlob = 'C:\dl\*\*', [string] $ContainerRoot = 'C:\', [string] $SystemAppGlob = 'C:\dl\*\*\platform\ModernDev', [string[]] $WidenRoot = @('C:\Applications', 'C:\dl', 'C:\build', 'C:\run', 'C:\bcartifacts.cache', 'C:\Program Files\Microsoft Dynamics NAV', 'C:\ProgramData\Microsoft\Microsoft Dynamics NAV'), [string] $VersionPrefix ) # Target platform major, e.g. '260' -> '26.'. Scopes the artifact search to the container's own version. if (-not $PSBoundParameters.ContainsKey('VersionPrefix')) { $navDirs = @(Get-ChildItem $NavProgramFiles -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^\d+$' }) $navName = ($navDirs | Sort-Object { [int]$_.Name } -Descending | Select-Object -First 1).Name $VersionPrefix = if ($navName) { "$([int]$navName.Substring(0, $navName.Length - 1))." } else { '' } } $cand = New-Object System.Collections.Generic.List[string] $artRoots = @(Get-ChildItem $DlGlob -Directory -ErrorAction SilentlyContinue) # C:\dl\<type>\<ver> if ($VersionPrefix) { $artRoots = @($artRoots | Where-Object { $_.Name -like "$VersionPrefix*" }) } foreach ($ar in $artRoots) { $withApps = @(Get-ChildItem $ar.FullName -Recurse -Directory -ErrorAction SilentlyContinue | Where-Object { Get-ChildItem -LiteralPath $_.FullName -Filter '*.app' -File -ErrorAction SilentlyContinue | Select-Object -First 1 }) $nonPlat = @($withApps | Where-Object { $_.FullName -notmatch '(?i)[\\/]platform[\\/]' }) $use = if ($nonPlat.Count -gt 0) { $nonPlat } else { $withApps } foreach ($d in $use) { $cand.Add($d.FullName) } } # The container's own application folders (some images keep compiled first-party apps here). Get-ChildItem $ContainerRoot -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^Applications(\..+)?$' } | ForEach-Object { $cand.Add($_.FullName) } # The platform 'System' symbol package ships as System.app under the AL Development Environment. $sysApp = Get-ChildItem $NavProgramFiles -Recurse -Filter 'System.app' -File -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $sysApp) { $sysApp = Get-ChildItem $SystemAppGlob -Recurse -Filter 'System.app' -File -ErrorAction SilentlyContinue | Select-Object -First 1 } if ($sysApp) { $cand.Add($sysApp.DirectoryName) } # Keep only folders that actually contain .app packages (drops app-source folders), de-duplicated. $symDirs = @($cand | Select-Object -Unique | Where-Object { $_ -and (Get-ChildItem -LiteralPath $_ -Filter '*.app' -File -ErrorAction SilentlyContinue | Select-Object -First 1) }) # 'Microsoft_Application*.app' matches both the sandbox '_<version>' and on-prem unversioned name. $appLoc = @($symDirs | Where-Object { Get-ChildItem -LiteralPath $_ -Filter 'Microsoft_Application*.app' -File -ErrorAction SilentlyContinue }) # If the scoped search did not find 'Application', widen it across the likely container roots for the # base symbol packages of the TARGET version (the version filter keeps a newer cached version's apps out). $widened = @() if (-not $appLoc -and $VersionPrefix) { $vEsc = [regex]::Escape($VersionPrefix) foreach ($pr in $WidenRoot) { if (-not (Test-Path -LiteralPath $pr)) { continue } Get-ChildItem -LiteralPath $pr -Recurse -File -Filter '*.app' -ErrorAction SilentlyContinue | Where-Object { ($_.Name -like 'Microsoft_Application_*' -or $_.Name -like 'Microsoft_Base Application_*' -or $_.Name -like 'Microsoft_System Application_*') -and $_.Name -match "_$vEsc" } | ForEach-Object { $widened += $_.DirectoryName } } $widened = @($widened | Select-Object -Unique) foreach ($w in $widened) { if ($symDirs -notcontains $w) { $symDirs += $w } } $appLoc = @($symDirs | Where-Object { Get-ChildItem -LiteralPath $_ -Filter 'Microsoft_Application*.app' -File -ErrorAction SilentlyContinue }) } return [PSCustomObject]@{ SymbolFolders = @($symDirs) VersionPrefix = $VersionPrefix ApplicationFound = @($appLoc) Widened = @($widened) } } |