The aarch64 leg ran npm with only cargo added to launchd's PATH, which omits node. Both clean-machine scripts said every binary runs and only looked for wai-pack and wai-remote-host: each now runs alone and says its usage. check-wai-release-quickstart.py read a step's lines for the script's path, so an echo of the path or a `|| true` after it passed; it now requires the script as the line's command, the step's exit status to be the script's, and the Windows throw after it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
136 lines
6.9 KiB
PowerShell
136 lines
6.9 KiB
PowerShell
# The quickstart as a new user runs it on Windows, from the archive alone, timed step by step:
|
|
#
|
|
# pwsh -File wai/quickstart/test/clean-machine.ps1 <archive.zip>
|
|
#
|
|
# The twin of clean-machine.sh, step for step. A machine with nothing of WAI on it: a fresh
|
|
# profile (USERPROFILE, HOME, APPDATA, LOCALAPPDATA, TEMP and TMP) and working directory, a PATH
|
|
# of the system's own directories, no cargo and no repository. The steps are the quickstart's:
|
|
# 1. check the archive against its .sha256 beside it, and unpack it;
|
|
# 2. the archive holds what `wai dev` and the quickstart name: bin/ with wai, wai-relay,
|
|
# wai-room, wai-ingest, wai-remote-host, wai-pack and wai-quantum, each of which runs (the
|
|
# last four here, the first three in the steps below), and share/wai/web/ and
|
|
# share/wai/studio/ (Studio's page and its core);
|
|
# 3. wai hello; 4. wai verify; 5. wai create my-room --template video-room;
|
|
# 6. wai dev --check in the project: the relay, the room service, the page and WAI Studio at
|
|
# /_wai/ on one origin, each checked through it.
|
|
# It prints each step's time, the total, and a JSON line; it exits non-zero when a step fails,
|
|
# naming it. Downloading the archive is not timed: the archive is given. It needs PowerShell 7
|
|
# and runs on any system it runs on (a .tar.gz archive elsewhere than Windows), so its steps can
|
|
# be checked off Windows too.
|
|
param([string]$Archive)
|
|
$ErrorActionPreference = 'Stop'
|
|
if (-not $Archive) {
|
|
Get-Content $PSCommandPath | Select-Object -First 19 | ForEach-Object { $_ -replace '^# ?', '' }
|
|
exit 2
|
|
}
|
|
$Archive = (Resolve-Path $Archive).Path
|
|
# The system's temporary directory, read before TEMP, TMP and TMPDIR point into the run's own.
|
|
$SystemTmp = [IO.Path]::GetTempPath()
|
|
$Root = Join-Path $SystemTmp ("wai-clean-" + [guid]::NewGuid().ToString('N'))
|
|
$HomeDir = Join-Path $Root 'home'
|
|
$Tmp = Join-Path $Root 'tmp'
|
|
$Work = Join-Path $Root 'work'
|
|
New-Item -ItemType Directory -Force -Path $HomeDir, $Tmp, $Work | Out-Null
|
|
$env:HOME = $HomeDir
|
|
$env:USERPROFILE = $HomeDir
|
|
$env:APPDATA = Join-Path $HomeDir 'AppData\Roaming'
|
|
$env:LOCALAPPDATA = Join-Path $HomeDir 'AppData\Local'
|
|
$env:TEMP = $Tmp
|
|
$env:TMP = $Tmp
|
|
$env:TMPDIR = $Tmp
|
|
New-Item -ItemType Directory -Force -Path $env:APPDATA, $env:LOCALAPPDATA | Out-Null
|
|
$Sep = [IO.Path]::PathSeparator
|
|
if ($IsWindows) {
|
|
$System = @("$env:SystemRoot\System32", $env:SystemRoot, "$env:SystemRoot\System32\Wbem", "$env:SystemRoot\System32\WindowsPowerShell\v1.0") -join $Sep
|
|
} else {
|
|
$System = '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin'
|
|
}
|
|
$env:PATH = $System
|
|
Set-Location $Work
|
|
|
|
$T0 = [Diagnostics.Stopwatch]::StartNew()
|
|
$Steps = [ordered]@{}
|
|
$Failed = ''
|
|
|
|
# Run one step, its output to <name>.log: its time, or FAILED and the log's tail.
|
|
function Step([string]$Name, [scriptblock]$Do) {
|
|
$log = Join-Path $Root "$Name.log"
|
|
$w = [Diagnostics.Stopwatch]::StartNew()
|
|
$ok = $true
|
|
try {
|
|
$global:LASTEXITCODE = 0
|
|
& $Do *> $log
|
|
if ($LASTEXITCODE -ne 0) { $ok = $false }
|
|
} catch {
|
|
$_ | Out-File -Append $log
|
|
$ok = $false
|
|
}
|
|
if ($ok) {
|
|
$script:Steps[$Name] = [math]::Round($w.Elapsed.TotalSeconds, 2).ToString([Globalization.CultureInfo]::InvariantCulture)
|
|
} else {
|
|
$script:Steps[$Name] = 'FAILED'
|
|
$script:Failed = $Name
|
|
Write-Output "FAIL ${Name}:"
|
|
if (Test-Path $log) { Get-Content $log -Tail 15 }
|
|
}
|
|
}
|
|
|
|
Step 'unpack' {
|
|
$want = ((Get-Content "$Archive.sha256" -Raw).Trim() -split '\s+')[0].ToLower()
|
|
$got = (Get-FileHash $Archive -Algorithm SHA256).Hash.ToLower()
|
|
if ($got -ne $want) { throw "SHA-256 $got, not $want" }
|
|
if ($Archive.EndsWith('.zip')) {
|
|
Expand-Archive -Path $Archive -DestinationPath $Work
|
|
} else {
|
|
tar -xzf $Archive -C $Work
|
|
}
|
|
}
|
|
$Bin = Get-ChildItem -Path $Work -Directory -Filter 'wai-*' | Select-Object -First 1 | ForEach-Object { Join-Path $_.FullName 'bin' }
|
|
if ($Bin) { $env:PATH = "$Bin$Sep$env:PATH" }
|
|
if (-not $Failed) {
|
|
Step 'contents' {
|
|
$exe = if ($IsWindows) { '.exe' } else { '' }
|
|
$missing = @()
|
|
foreach ($b in 'wai', 'wai-relay', 'wai-room', 'wai-ingest', 'wai-remote-host', 'wai-pack', 'wai-quantum') {
|
|
if (-not (Test-Path -PathType Leaf (Join-Path $Bin "$b$exe"))) { $missing += "bin/$b$exe" }
|
|
}
|
|
foreach ($f in 'share/wai/web/room/index.html', 'share/wai/studio/index.html', 'share/wai/studio/pkg/wai_studio_core_bg.wasm') {
|
|
if (-not (Test-Path -PathType Leaf (Join-Path (Split-Path $Bin -Parent) $f))) { $missing += $f }
|
|
}
|
|
if ($missing) { throw "the archive lacks: $($missing -join ' ')" }
|
|
wai-quantum --version
|
|
if ($LASTEXITCODE -ne 0) { throw "wai-quantum --version exits $LASTEXITCODE" }
|
|
# wai-ingest and wai-pack alone say how they are run and exit 2; wai-remote-host, 1.
|
|
foreach ($u in @{ n = 'wai-ingest'; c = 2 }, @{ n = 'wai-pack'; c = 2 }, @{ n = 'wai-remote-host'; c = 1 }) {
|
|
$err = Join-Path $Root "$($u.n).err"
|
|
$p = Start-Process -FilePath (Join-Path $Bin "$($u.n)$exe") -NoNewWindow -Wait -PassThru -RedirectStandardOutput (Join-Path $Root "$($u.n).out") -RedirectStandardError $err
|
|
$said = Get-Content $err -Raw
|
|
if ($p.ExitCode -ne $u.c -or $said -notmatch 'usage' -or $said -notmatch [regex]::Escape("$($u.n) ")) {
|
|
throw "$($u.n) alone exits $($p.ExitCode), not $($u.c) with its usage"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (-not $Failed) { Step 'hello' { wai hello } }
|
|
if (-not $Failed) { Step 'verify' { wai verify wai-hello } }
|
|
if (-not $Failed) { Step 'create' { wai create my-room --template video-room } }
|
|
# Every piece held, Studio among them: the archive's share/wai/studio, found beside wai.
|
|
if (-not $Failed) { Step 'dev-check' { Push-Location my-room; try { wai dev --check --port 0 | Tee-Object -Variable out; if ($LASTEXITCODE -eq 0 -and -not ($out | Select-String -SimpleMatch -Quiet 'ok WAI Studio at /_wai/')) { throw 'wai dev --check did not hold WAI Studio at /_wai/' } } finally { Pop-Location } } }
|
|
|
|
$Total = [math]::Round($T0.Elapsed.TotalSeconds, 2).ToString([Globalization.CultureInfo]::InvariantCulture)
|
|
$Os = [Runtime.InteropServices.RuntimeInformation]::OSDescription
|
|
$Arch = [Runtime.InteropServices.RuntimeInformation]::OSArchitecture
|
|
Write-Output "the quickstart from $(Split-Path $Archive -Leaf) on $Os $Arch, a fresh profile and directory:"
|
|
foreach ($k in $Steps.Keys) {
|
|
if ($Steps[$k] -eq 'FAILED') { Write-Output (" {0,-10} FAILED" -f $k) } else { Write-Output (" {0,-10} {1} s" -f $k, $Steps[$k]) }
|
|
}
|
|
$devLog = Join-Path $Root 'dev-check.log'
|
|
if (Test-Path $devLog) { Select-String -Path $devLog -Pattern 'checks held' | ForEach-Object { " $($_.Line)" } }
|
|
Write-Output (" total $Total s" + $(if ($Failed) { " (stopped at $Failed)" } else { '' }))
|
|
$stepsOut = [ordered]@{}
|
|
foreach ($k in $Steps.Keys) { $stepsOut[$k] = $Steps[$k] }
|
|
[ordered]@{ archive = (Split-Path $Archive -Leaf); total_s = [double]$Total; steps = $stepsOut; ok = (-not $Failed) } | ConvertTo-Json -Compress
|
|
Set-Location $SystemTmp
|
|
Remove-Item -Recurse -Force $Root -ErrorAction SilentlyContinue
|
|
if ($Failed) { exit 1 }
|
|
exit 0
|