Modules/businessdev.ALbuild.RuntimePackages/Private/Get-BcRuntimeAppFile.ps1
|
function Get-BcRuntimeAppFile { <# .SYNOPSIS Returns the compiled .app of a product for one platform version, compiling it once if needed. .DESCRIPTION A runtime package is produced from an app that was compiled AGAINST the target platform - the manifest is stamped to that version and the ONPREM / BC<major> preprocessor symbols are applied - so every (product, platform version) pair needs its own build. Results are cached per platform version inside the worker's private work root and reused. That matters more than it looks: within one container the dependency apps are compiled first and then installed again for every product that depends on them. Without the cache, 365 business API would be recompiled once per dependent, on every platform version. Everything happens inside -WorkRoot, on a copy of the project. The shared checkout is never touched, which is what allows several workers to run at once: the previous design rewrote app.json in place and restored it in a 'finally', so two concurrent versions would have fought over the same file. .PARAMETER Product The planned product entry (Name, Publisher, AppId, AppVersion, Projects). .PARAMETER WorkRoot The worker's private working folder. .PARAMETER PlatformVersion Target platform version. .PARAMETER Signing Splat for Invoke-BcAppSigning applied to the compiled app. Omitted = no signing. .PARAMETER SymbolFolder Package cache folders for the compiler (first-party symbols for this platform version). .OUTPUTS System.String - path to the compiled .app. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [ValidateNotNull()] [object] $Product, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $WorkRoot, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $PlatformVersion, [hashtable] $Signing, [string[]] $SymbolFolder = @() ) $cacheFolder = Join-Path (Join-Path $WorkRoot 'apps') $PlatformVersion if (-not (Test-Path -LiteralPath $cacheFolder)) { New-Item -ItemType Directory -Force -Path $cacheFolder | Out-Null } $cached = Join-Path $cacheFolder "$($Product.AppId).app" if (Test-Path -LiteralPath $cached) { return $cached } $projects = @(Get-BcRuntimeProperty -InputObject $Product -Name 'Projects' -Default @()) if ($projects.Count -eq 0) { throw "No project folder is configured for '$($Product.Name)', so it cannot be compiled for platform $PlatformVersion." } # One catalogue entry = one shipped app. Extra folders in a repo (tests, demo) are excluded by the # planner, so the first project is the app itself. $source = "$($projects[0])" if (-not (Test-Path -LiteralPath $source)) { throw "Project folder '$source' for '$($Product.Name)' does not exist." } # Private copy: the manifest is rewritten per platform version, and the shared checkout must stay # untouched so other workers are unaffected. $build = Join-Path (Join-Path $WorkRoot 'build') "$PlatformVersion-$($Product.AppId)" if (Test-Path -LiteralPath $build) { Remove-Item -LiteralPath $build -Recurse -Force } New-Item -ItemType Directory -Force -Path $build | Out-Null Copy-Item -LiteralPath $source -Destination $build -Recurse -Force $projectFolder = Join-Path $build (Split-Path -Leaf $source) $appJson = Join-Path $projectFolder 'app.json' if (-not (Test-Path -LiteralPath $appJson)) { throw "No app.json in '$projectFolder'." } # Stamp the RELEASED version, not the source's. The factory compiles from the product's master while # the version being shipped comes from the last CD build's artifact, and the runtime package is # requested from the service tier BY name and version - a mismatch means Get-NAVAppRuntimePackage # simply does not find the app that was just installed. Set-BcAppVersion -Path $projectFolder -Version "$($Product.AppVersion)" | Out-Null $major = ([version](ConvertTo-BcVersion $PlatformVersion)).Major Update-BcAppManifest -Path $appJson -BcVersion $PlatformVersion -PreprocessorSymbols @('ONPREM', "BC$major") | Out-Null $packageCache = @(Join-Path $projectFolder '.alpackages') + @($SymbolFolder) $compiled = Invoke-BcCompiler -ProjectFolder $projectFolder -Engine AlTool -OutputFolder $cacheFolder -PackageCachePath $packageCache if (-not $compiled.Success) { throw "AL compilation of '$($Product.Name)' for platform $PlatformVersion failed with exit code $($compiled.ExitCode)." } if ($Signing) { Invoke-BcAppSigning -Path $compiled.OutputFile @Signing } # Store under the app id: the compiler names the file from the manifest, and the dependency lookup # needs a name it can predict without re-reading it. Move-Item -LiteralPath $compiled.OutputFile -Destination $cached -Force return $cached } |