2026-09-10 11:38:10 -07:00
# 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 ] @ {}
2026-09-11 07:53:42 -07:00
foreach ( $name in @ ( 'arcadia-studio' , 'arcadia-server' , 'arcadia' )) {
2026-09-10 11:38:10 -07:00
$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 ] }
2026-09-11 07:53:42 -07:00
$notices = Get-ArcadiaNotices $repository $Target $NoticeManifest '' @ ( 'oa-desktop' , 'oa-server' , 'oa-cli' )
2026-09-10 11:38:10 -07:00
} 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
2026-09-11 07:53:42 -07:00
runtime = 'Ubuntu 24.04 x86-64 is the validation baseline. Direct ELF dependencies only are inspected; graphics/window dynamic loads must be verified on the actual runtime. Linux Open/Save uses application path entry.'
2026-09-10 11:38:10 -07:00
}
[ IO.File ]:: WriteAllText (( Join-Path $stage 'package.json' ), ( $metadata | ConvertTo-Json -Depth 14 ) + " `n " , $encoding )
2026-09-11 07:53:42 -07:00
[ IO.File ]:: WriteAllText (( Join-Path $stage 'START-HERE.txt' ), "Arcadia Studio portable Linux bundle `n Run ./arcadia-studio. Keep examples/release1 beside the executable. `n Read README.md and docs/linux-packaging.md. The optional server is ./arcadia-server. `n The source authoring CLI is ./arcadia; run ./arcadia --help for check, stabilization and alias rename commands. `n Source checkout required for Cargo/Docker instructions. Packaging is not runtime acceptance. `n " , $encoding )
2026-09-10 11:38:10 -07:00
$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.
}