#Requires -Version 5.1 # Package already-built x86-64 glibc inputs or prepare strict server notices. [CmdletBinding(DefaultParameterSetName = 'Package')] param( [ValidateSet('x86_64-unknown-linux-gnu')] [string]$Target = 'x86_64-unknown-linux-gnu', [Parameter(Mandatory = $true, ParameterSetName = 'Package')] [ValidatePattern('^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$')] [string]$Version, [Parameter(Mandatory = $true, ParameterSetName = 'Package')] [string]$BinaryDirectory, [Parameter(Mandatory = $true, ParameterSetName = 'Notices')] [switch]$ServerNoticesOnly, [string]$BuildEvidence, [string]$Python = 'python', [string]$NoticeManifest = (Join-Path $PSScriptRoot 'windows-notices/manifest.json'), [string]$OutputRoot = (Join-Path $PSScriptRoot '../dist') ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $repository = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..')) $encoding = New-Object Text.UTF8Encoding($false) . (Join-Path $PSScriptRoot 'package-common.ps1') . (Join-Path $PSScriptRoot 'windows-notices.ps1') $inputs = [ordered]@{} $inspectedHashes = @{} $imports = [ordered]@{} $evidence = $null if (-not $ServerNoticesOnly) { $binaryHashes = [ordered]@{} foreach ($name in @('arcadia-studio', 'arcadia-server')) { $path = [IO.Path]::GetFullPath((Join-Path $BinaryDirectory $name)) $elf = Invoke-PackageHelper $Python @('elf', $path) $inputs[$name] = $path $imports[$name] = $elf $inspectedHashes[$name] = $elf.sha256 $binaryHashes[$name] = $elf.sha256 } $evidence = Read-PackageBuildEvidence $BuildEvidence $Target $binaryHashes $documentation = Get-PackageDocumentation $repository 'linux' $Python foreach ($name in $documentation.Keys) { $inputs[$name] = $documentation[$name] } $notices = Get-ArcadiaNotices $repository $Target $NoticeManifest '' } else { if ($BuildEvidence) { throw '-BuildEvidence applies to a binary package, not a notice-only bundle.' } $notices = Get-ArcadiaNotices $repository $Target $NoticeManifest '' @('oa-server') $inputs['LICENSE'] = Join-Path $repository 'LICENSE' } foreach ($name in $notices.Inputs.Keys) { if ($inputs.Contains($name)) { throw "Notice collides with package input: $name" } $inputs[$name] = $notices.Inputs[$name] $inspectedHashes[$name] = $notices.Hashes[$name] } $output = [IO.Path]::GetFullPath($OutputRoot) $packageName = if ($ServerNoticesOnly) { 'server-notices' } else { "ArcadiaStudio-$Version-$Target" } $stage = Join-Path $output $packageName $archive = "$stage.tar.gz" $checksum = "$archive.sha256" $lockPath = "$stage.packaging.lock" foreach ($path in @($stage, $archive, $checksum, $lockPath)) { if (Test-Path -LiteralPath $path) { throw "Output already exists; choose a fresh version/output root: $path" } } foreach ($directory in @('docs', 'examples', 'crates', 'scripts')) { $sourceRoot = [IO.Path]::GetFullPath((Join-Path $repository $directory)) + [IO.Path]::DirectorySeparatorChar if (($stage + [IO.Path]::DirectorySeparatorChar).StartsWith($sourceRoot, [StringComparison]::OrdinalIgnoreCase)) { throw 'Output must not be inside a packaged source directory.' } } [void][IO.Directory]::CreateDirectory($output) $lock = [IO.File]::Open($lockPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None) try { [void][IO.Directory]::CreateDirectory($stage) $inputHashes = Copy-PackageInputs $stage $inputs $inspectedHashes Write-PackageNotices $stage $notices if (-not $ServerNoticesOnly) { $metadata = [ordered]@{ version = $Version; target = $Target acceptance = 'Packaging integrity only; current-tree native Linux acceptance required.' build = 'Prebuilt inputs; no build profile, source identity or compiler inferred.' build_evidence = $evidence; imports = $imports; input_sha256 = $inputHashes runtime = 'Ubuntu 24.04 x86-64 is the validation baseline. Direct ELF dependencies only are inspected; graphics/window/portal dynamic loads must be verified on the actual runtime.' } [IO.File]::WriteAllText((Join-Path $stage 'package.json'), ($metadata | ConvertTo-Json -Depth 14) + "`n", $encoding) [IO.File]::WriteAllText((Join-Path $stage 'START-HERE.txt'), "Arcadia Studio portable Linux bundle`nRun ./arcadia-studio. Keep examples/release1 beside the executable.`nRead README.md and docs/linux-packaging.md. The optional server is ./arcadia-server.`nSource checkout required for Cargo/Docker instructions. Packaging is not runtime acceptance.`n", $encoding) $documentCheck = Invoke-PackageHelper $Python @('check-docs', '--stage', $stage) [IO.File]::WriteAllText((Join-Path $stage 'documentation-check.json'), ($documentCheck | ConvertTo-Json) + "`n", $encoding) } Write-PackageChecksums $stage if ($ServerNoticesOnly) { [pscustomobject]@{ Directory = $stage; Target = $Target; Files = @(Get-ChildItem -LiteralPath $stage -Recurse -File).Count; Scope = 'Server-only notices; no application binary or runtime claim.' } } else { $result = Invoke-PackageHelper $Python @('archive', '--stage', $stage, '--archive', $archive, '--name', $packageName) [IO.File]::WriteAllText($checksum, "$($result.sha256) $packageName.tar.gz`n", $encoding) [pscustomobject]@{ Directory = $stage; Archive = $archive; SHA256 = $result.sha256; Files = $result.files; NativeAcceptance = 'Pending' } } } finally { $lock.Dispose() # Claims and partial outputs intentionally remain. Never overwrite a failed attempt. }