142 lines
7.3 KiB
PowerShell
142 lines
7.3 KiB
PowerShell
param(
|
|
[Parameter(Mandatory)]
|
|
[ValidateSet('linux-x64', 'linux-arm64', 'linux-musl-x64', 'linux-musl-arm64')]
|
|
[string]$RuntimeIdentifier,
|
|
[Parameter(Mandatory)]
|
|
[string]$Destination
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
|
|
$arch = if ($RuntimeIdentifier.EndsWith('arm64')) { 'arm64' } else { 'amd64' }
|
|
$root = Split-Path -Parent $PSScriptRoot
|
|
$cacheRoot = if ($env:MOSHIRO_QUIC_CACHE) {
|
|
$env:MOSHIRO_QUIC_CACHE
|
|
}
|
|
elseif ($env:NUGET_PACKAGES) {
|
|
Join-Path (Split-Path -Parent $env:NUGET_PACKAGES) 'moshiro-quic-runtime'
|
|
}
|
|
else {
|
|
Join-Path $root '.release\quic-package-cache'
|
|
}
|
|
$cache = Join-Path $cacheRoot $RuntimeIdentifier
|
|
$null = New-Item -ItemType Directory -Force -Path $cache, $Destination
|
|
Get-ChildItem -LiteralPath $Destination -Filter '*.so.*' -File -ErrorAction SilentlyContinue | Remove-Item -Force
|
|
|
|
function Invoke-Tar([string[]]$Arguments) {
|
|
$tar = if (Get-Command tar.exe -ErrorAction SilentlyContinue) { 'tar.exe' } else { 'tar' }
|
|
& $tar @Arguments
|
|
if ($LASTEXITCODE -ne 0) { throw "tar.exe failed ($LASTEXITCODE): $($Arguments -join ' ')" }
|
|
}
|
|
|
|
function Copy-LibrariesFromDataTar([string]$DataTar, [string]$ExtractRoot, [string]$ExcludePattern = '') {
|
|
$tar = if (Get-Command tar.exe -ErrorAction SilentlyContinue) { 'tar.exe' } else { 'tar' }
|
|
$entries = & $tar -tf $DataTar
|
|
if ($LASTEXITCODE -ne 0) { throw "Could not list $DataTar" }
|
|
foreach ($entry in $entries) {
|
|
$normalized = $entry -replace '^\./', ''
|
|
if ($normalized -notmatch '^(?:usr/)?lib/.+\.so\.\d+(?:\.\d+)+$') { continue }
|
|
$leaf = [IO.Path]::GetFileName($normalized)
|
|
if ($ExcludePattern -and $leaf -match $ExcludePattern) { continue }
|
|
$soname = [regex]::Match($leaf, '^(.+\.so\.\d+)')
|
|
if (-not $soname.Success) { continue }
|
|
Invoke-Tar @('-xf', $DataTar, '-C', $ExtractRoot, $entry)
|
|
$source = Join-Path $ExtractRoot ($normalized -replace '/', [IO.Path]::DirectorySeparatorChar)
|
|
Copy-Item -LiteralPath $source -Destination (Join-Path $Destination $soname.Groups[1].Value) -Force
|
|
}
|
|
}
|
|
|
|
function Copy-LibrariesFromTree([string]$ExtractRoot) {
|
|
foreach ($source in Get-ChildItem -LiteralPath $ExtractRoot -Recurse -File) {
|
|
if ($source.DirectoryName -notmatch '[\\/]usr[\\/]lib([\\/]|$)') { continue }
|
|
$soname = [regex]::Match($source.Name, '^(.+\.so\.\d+)\.\d+')
|
|
if ($soname.Success) {
|
|
Copy-Item -LiteralPath $source.FullName -Destination (Join-Path $Destination $soname.Groups[1].Value) -Force
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-DebLibrary([string]$IndexUrl, [string]$PackagePattern, [string]$Name, [string]$ExcludePattern = '') {
|
|
$index = (Invoke-WebRequest -Uri $IndexUrl -UseBasicParsing).Content
|
|
$links = [regex]::Matches($index, 'href="([^"]+\.deb)"') | ForEach-Object { $_.Groups[1].Value -replace '^\./', '' }
|
|
$file = $links | Where-Object { $_ -match $PackagePattern } | Sort-Object -Descending | Select-Object -First 1
|
|
if (-not $file) { throw "Could not find $Name ($arch) in $IndexUrl" }
|
|
|
|
$packagePath = Join-Path $cache $file
|
|
if (-not (Test-Path -LiteralPath $packagePath)) {
|
|
Invoke-WebRequest -Uri "$IndexUrl$file" -OutFile $packagePath -UseBasicParsing
|
|
}
|
|
$unpack = Join-Path $cache ([IO.Path]::GetFileNameWithoutExtension($file))
|
|
$null = New-Item -ItemType Directory -Force -Path $unpack
|
|
if (Get-Command ar -ErrorAction SilentlyContinue) {
|
|
Push-Location $unpack
|
|
try {
|
|
& ar x $packagePath
|
|
if ($LASTEXITCODE -ne 0) { throw "Could not unpack Debian package $file" }
|
|
}
|
|
finally { Pop-Location }
|
|
}
|
|
else {
|
|
Invoke-Tar @('-xf', $packagePath, '-C', $unpack)
|
|
}
|
|
$dataTar = Get-ChildItem -LiteralPath $unpack -Filter 'data.tar.*' | Select-Object -First 1
|
|
if (-not $dataTar) { throw "Debian package $file has no data archive" }
|
|
Copy-LibrariesFromDataTar $dataTar.FullName $unpack $ExcludePattern
|
|
}
|
|
|
|
function Get-ApkLibrary([string]$Repository, [string]$PackageName) {
|
|
$apkArch = if ($arch -eq 'amd64') { 'x86_64' } else { 'aarch64' }
|
|
$base = "https://dl-cdn.alpinelinux.org/alpine/v3.22/$Repository/$apkArch"
|
|
$indexPath = Join-Path $cache "$Repository-APKINDEX.tar.gz"
|
|
if (-not (Test-Path -LiteralPath $indexPath) -or (Get-Item -LiteralPath $indexPath).LastWriteTimeUtc -lt [DateTime]::UtcNow.AddHours(-24)) {
|
|
Invoke-WebRequest -Uri "$base/APKINDEX.tar.gz" -OutFile $indexPath -UseBasicParsing
|
|
}
|
|
$indexDirectory = Join-Path $cache "$Repository-index"
|
|
$null = New-Item -ItemType Directory -Force -Path $indexDirectory
|
|
Invoke-Tar @('-xzf', $indexPath, '-C', $indexDirectory)
|
|
$indexFile = Get-ChildItem -LiteralPath $indexDirectory -File | Where-Object Name -Like 'APKINDEX*' | Select-Object -First 1 -ExpandProperty FullName
|
|
if (-not $indexFile) { throw "Alpine index archive has no APKINDEX: $indexPath" }
|
|
$records = (Get-Content -LiteralPath $indexFile -Raw) -split "`n`n"
|
|
$record = $records | Where-Object { $_ -match "(?m)^P:$([regex]::Escape($PackageName))\r?$" } | Select-Object -First 1
|
|
if (-not $record) { throw "Could not find Alpine package $PackageName in $Repository/$apkArch" }
|
|
$version = [regex]::Match($record, '(?m)^V:(.+)$').Groups[1].Value.Trim()
|
|
$packageFile = "$PackageName-$version.apk"
|
|
if (-not $version -or -not $packageFile) { throw "Incomplete APKINDEX record for $PackageName" }
|
|
|
|
$apkPath = Join-Path $cache $packageFile
|
|
if (-not (Test-Path -LiteralPath $apkPath)) { Invoke-WebRequest -Uri "$base/$packageFile" -OutFile $apkPath -UseBasicParsing }
|
|
|
|
$unpack = Join-Path $cache "$PackageName-$version"
|
|
$null = New-Item -ItemType Directory -Force -Path $unpack
|
|
Invoke-Tar @('-xzf', $apkPath, '-C', $unpack)
|
|
Copy-LibrariesFromTree $unpack
|
|
}
|
|
|
|
if ($RuntimeIdentifier.StartsWith('linux-musl-')) {
|
|
Get-ApkLibrary 'community' 'libmsquic'
|
|
Get-ApkLibrary 'main' 'numactl'
|
|
Get-ApkLibrary 'main' 'lttng-ust'
|
|
Get-ApkLibrary 'main' 'zlib'
|
|
}
|
|
else {
|
|
# Keep these Debian 12 builds: selecting the newest package in the shared
|
|
# Debian pool can silently raise the minimum glibc above Bookworm's 2.36.
|
|
Get-DebLibrary 'https://deb.debian.org/debian/pool/main/n/numactl/' "^libnuma1_2\.0\.16-1_$arch\.deb$" 'libnuma'
|
|
Get-DebLibrary 'https://deb.debian.org/debian/pool/main/libz/libzstd/' "^libzstd1_1\.5\.4\+dfsg2-5_$arch\.deb$" 'libzstd'
|
|
Get-DebLibrary 'https://deb.debian.org/debian/pool/main/z/zlib/' "^zlib1g_1\.2\.13\.dfsg-1_$arch\.deb$" 'zlib'
|
|
# MsQuic's LTTng plugin is optional and is not loaded by the node runtime.
|
|
Get-DebLibrary 'https://packages.microsoft.com/debian/12/prod/pool/main/libm/libmsquic/' "^libmsquic_\d+(?:\.\d+){1,3}_$arch\.deb$" 'MsQuic' '^libmsquic\.lttng\.so\.'
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath (Join-Path $Destination 'libmsquic.so.2'))) {
|
|
throw "Bundled runtime is missing libmsquic.so.2 for $RuntimeIdentifier"
|
|
}
|
|
if (-not (Test-Path -LiteralPath (Join-Path $Destination 'libnuma.so.1'))) {
|
|
throw "Bundled runtime is missing libnuma.so.1 for $RuntimeIdentifier"
|
|
}
|
|
if (-not (Test-Path -LiteralPath (Join-Path $Destination 'libz.so.1'))) {
|
|
throw "Bundled runtime is missing libz.so.1 for $RuntimeIdentifier"
|
|
}
|
|
Get-ChildItem -LiteralPath $Destination -Filter '*.so.*' | ForEach-Object { Write-Output "bundled $($_.Name) for $RuntimeIdentifier" }
|