Modules/businessdev.ALbuild.Feeds/Public/New-BcNuGetPackage.ps1
|
function New-BcNuGetPackage { <# .SYNOPSIS Creates a NuGet package (.nupkg) that contains a Business Central .app. .DESCRIPTION Reads the .app manifest, derives the package id from the id scheme (or uses -PackageId), and produces a valid OPC NuGet package (with [Content_Types].xml and relationships) containing the .app and a generated .nuspec. Application/platform dependency ranges and extra dependencies can be declared (used by, for example, runtime packages). .PARAMETER AppFile Path to the .app (or .runtime.app) file. .PARAMETER PackageId Explicit package id. If omitted, derived from -IdScheme and the app identity. .PARAMETER IdScheme Package id template when -PackageId is not supplied. Default '{publisher}.{name}.{id}'. .PARAMETER Version Package version. Default: the app version. .PARAMETER Authors Package authors. Default: the app publisher. .PARAMETER Description Package description. Default: the app name. .PARAMETER Dependency Additional NuGet dependencies as @{ id = ...; version = ... } hashtables. .PARAMETER OutputFolder Output folder for the .nupkg. Default: the app file's folder. .EXAMPLE New-BcNuGetPackage -AppFile .\Publisher_App_1.0.0.0.app -IdScheme '{publisher}.{name}.symbols.{id}' .OUTPUTS System.String - the path to the created .nupkg. #> [CmdletBinding(SupportsShouldProcess)] [OutputType([string])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $AppFile, [string] $PackageId, [string] $IdScheme = '{publisher}.{name}.{id}', [string] $Version, [string] $Authors, [string] $Description, [object[]] $Dependency = @(), [string] $OutputFolder ) if (-not (Test-Path -LiteralPath $AppFile)) { throw "App file not found: '$AppFile'." } $info = Expand-BcAppFile -Path $AppFile if ($info.ExtractedPath -and (Test-Path $info.ExtractedPath)) { Remove-Item $info.ExtractedPath -Recurse -Force -ErrorAction SilentlyContinue } $normalize = { param($v) ($v -replace '[^A-Za-z0-9_\-]', '') } if (-not $PackageId) { $PackageId = $IdScheme.Replace('{publisher}', (& $normalize $info.Publisher)).Replace('{name}', (& $normalize $info.Name)).Replace('{id}', $info.Id) $PackageId = ($PackageId -replace '\.\.', '.').Trim('.') } if (-not $Version) { $Version = "$($info.Version)" } if (-not $Authors) { $Authors = $info.Publisher } if (-not $Description) { $Description = $info.Name } if (-not $OutputFolder) { $OutputFolder = Split-Path -Path (Resolve-Path -LiteralPath $AppFile).ProviderPath -Parent } $depXml = '' foreach ($dep in $Dependency) { $depXml += " <dependency id=`"$($dep.id)`" version=`"$($dep.version)`" />`n" } $nuspec = @" <?xml version="1.0" encoding="utf-8"?> <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> <metadata> <id>$PackageId</id> <version>$Version</version> <title>$($info.Name)</title> <authors>$Authors</authors> <owners>$Authors</owners> <requireLicenseAcceptance>false</requireLicenseAcceptance> <description>$Description</description> <dependencies> $depXml </dependencies> </metadata> </package> "@ $contentTypes = @' <?xml version="1.0" encoding="utf-8"?> <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"> <Default Extension="nuspec" ContentType="application/octet" /> <Default Extension="app" ContentType="application/octet" /> <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" /> </Types> '@ $relsId = 'R' + ([Guid]::NewGuid().ToString('N').Substring(0, 16)) $rels = @" <?xml version="1.0" encoding="utf-8"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> <Relationship Type="http://schemas.microsoft.com/packaging/2010/07/manifest" Target="/$PackageId.nuspec" Id="$relsId" /> </Relationships> "@ $nupkgPath = Join-Path $OutputFolder "$PackageId.$Version.nupkg" if (-not $PSCmdlet.ShouldProcess($nupkgPath, 'Create NuGet package')) { return } if (-not (Test-Path -LiteralPath $OutputFolder)) { New-Item -Path $OutputFolder -ItemType Directory -Force | Out-Null } if (Test-Path -LiteralPath $nupkgPath) { Remove-Item -LiteralPath $nupkgPath -Force } Add-Type -AssemblyName System.IO.Compression -ErrorAction SilentlyContinue Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue $utf8 = [System.Text.UTF8Encoding]::new($false) $zip = [System.IO.Compression.ZipFile]::Open($nupkgPath, [System.IO.Compression.ZipArchiveMode]::Create) try { $addText = { param($entryName, $text) $entry = $zip.CreateEntry($entryName) $stream = $entry.Open() try { $bytes = $utf8.GetBytes($text); $stream.Write($bytes, 0, $bytes.Length) } finally { $stream.Dispose() } } & $addText '[Content_Types].xml' $contentTypes & $addText '_rels/.rels' $rels & $addText "$PackageId.nuspec" $nuspec # Payload .app under the package root. $appEntryName = [System.IO.Path]::GetFileName($AppFile) [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, (Resolve-Path -LiteralPath $AppFile).ProviderPath, $appEntryName) | Out-Null } finally { $zip.Dispose() } Write-ALbuildLog -Level Success "Created NuGet package '$nupkgPath'." return $nupkgPath } |