mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-21 16:02:20 +00:00
`verify-windows-package.ps1` reads the Inno staging directory to check what
lands in {app} — the compiled setup.exe cannot be read back without
innoextract, which the runners do not carry. But `bundle-windows.ps1` deleted
that directory as its last act, so the verifier has failed on every Windows
build since the check arrived in #330: "the Inno staging directory is missing".
Nightly has been red for two nights (2026-08-05, 2026-08-06) and a stable
release would fail the same way — release.yml runs the same step.
Both workflows already expected the directory to survive: their upload steps
name it among the dist/ intermediates the asset globs deliberately skip. So
this drops the removal rather than teaching the verifier to tolerate an absent
payload, which would retire the check it was added to make.
Claude-Session: https://claude.ai/code/session_01H9QqEZ6JH3dGS6atEcf6ab
Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
117 lines
6.1 KiB
PowerShell
117 lines
6.1 KiB
PowerShell
# Usage: bundle-windows.ps1 <target-triple> <arch-label>
|
|
# Package the release binary twice from one staged payload:
|
|
# dist/tty7-<version>-windows-<arch>.zip portable (unzip anywhere)
|
|
# dist/tty7-<version>-windows-<arch>-setup.exe Inno Setup installer
|
|
# (Program Files or per-user, Start Menu shortcut, "Apps" uninstall entry)
|
|
#
|
|
# Fonts are embedded via include_bytes! and the app icon is compiled into the
|
|
# executable as a resource (see build.rs). So the payload is tty7-app.exe plus a
|
|
# sibling completions\ dir (loaded at runtime — see terminal::signature), the
|
|
# bundled ConPTY pair (loaded by the DLL search path — see below) and the
|
|
# license/readme. Windows release artifacts are intentionally unsigned. The
|
|
# in-app updater verifies the published SHA-256 checksum and PE file version
|
|
# before and after waiting for the GUI to exit.
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$Target = $args[0]
|
|
$Arch = $args[1]
|
|
$Version = (Select-String -Path Cargo.toml -Pattern '^version\s*=\s*"([^"]+)"').Matches[0].Groups[1].Value
|
|
# Inno accepts the full semantic version for AppVersion, but the PE version
|
|
# resource only accepts numeric components. Keep both values so Nightly and
|
|
# other prerelease builds retain their display version without breaking ISCC.
|
|
$VersionCore = ($Version -split '[-+]', 2)[0]
|
|
$VersionInfoVersion = "${VersionCore}.0"
|
|
$Name = "tty7-$Version-windows-$Arch"
|
|
$Stage = "dist/$Name"
|
|
$PackageUpdater = $env:TTY7_PACKAGE_UPDATE_HELPER -ne '0'
|
|
|
|
Remove-Item -Recurse -Force dist -ErrorAction SilentlyContinue
|
|
New-Item -ItemType Directory -Force -Path $Stage | Out-Null
|
|
|
|
Copy-Item "target/$Target/release/tty7-app.exe" "$Stage/tty7-app.exe"
|
|
# The CLI, staged beside the GUI so both the zip and the installer carry it.
|
|
# `core::cli_install` resolves it relative to tty7-app.exe and puts that
|
|
# directory on the user's PATH.
|
|
Copy-Item "target/$Target/release/tty7.exe" "$Stage/tty7.exe"
|
|
if ($PackageUpdater) {
|
|
# The installed copy is never executed in place during an update. The GUI
|
|
# first copies it to a private staging directory so Inno can replace every
|
|
# installed executable without colliding with Windows image locks.
|
|
Copy-Item "target/$Target/release/tty7-updater.exe" "$Stage/tty7-updater.exe"
|
|
}
|
|
New-Item -ItemType Directory -Force -Path "$Stage/completions" | Out-Null
|
|
Copy-Item "assets/completions/*.json" "$Stage/completions/"
|
|
Copy-Item LICENSE "$Stage/LICENSE.txt"
|
|
Copy-Item README.md "$Stage/README.md"
|
|
|
|
# Microsoft's redistributable ConPTY, which `portable-pty` prefers over the
|
|
# in-box conhost when it sits beside the running executable — and the daemon is
|
|
# `tty7-app.exe --daemon`, so beside it is exactly here. The in-box host
|
|
# swallows a pane's OSC 11 background query (#345); this pair forwards it. The
|
|
# two files are one unit, so a missing half is an error rather than a warning.
|
|
# See assets/windows/conpty/README.md.
|
|
$ConptyArch = @{ 'x86_64-pc-windows-msvc' = 'x64' }[$Target]
|
|
if (-not $ConptyArch) { throw "no vendored ConPTY for $Target - see assets/windows/conpty/README.md" }
|
|
foreach ($File in 'conpty.dll', 'OpenConsole.exe') {
|
|
$Source = "assets/windows/conpty/$ConptyArch/$File"
|
|
if (-not (Test-Path $Source)) { throw "missing bundled ConPTY file: $Source" }
|
|
Copy-Item $Source "$Stage/$File"
|
|
}
|
|
Copy-Item "assets/windows/conpty/LICENSE.txt" "$Stage/LICENSE-ConPTY.txt"
|
|
|
|
# The Linux musl `tty7-server`, staged at server/ so a WSL distro can be handed
|
|
# the binary this client shipped with (WSL downloads nothing). The
|
|
# lookup path is a contract with `daemon::install::wsl` — it searches
|
|
# <dir of tty7-app.exe>/server/<asset> first — so this directory name is not free to
|
|
# change on its own. Missing is a warning, not an error, matching `server-musl`'s
|
|
# own skip-don't-fail probe; WSL then fails at connect time with a message
|
|
# naming the directories it searched.
|
|
#
|
|
# The *filename* is a contract too, not just the directory: `wsl.rs` looks for
|
|
# `<dir>/<asset name>`, so this string has to stay whatever
|
|
# `install::asset::ASSET_X86_64` says it is.
|
|
$ServerAsset = "tty7-server-linux-x86_64-musl"
|
|
$ServerSrc = "bundled-server/$ServerAsset"
|
|
if (Test-Path $ServerSrc) {
|
|
New-Item -ItemType Directory -Force -Path "$Stage/server" | Out-Null
|
|
Copy-Item $ServerSrc "$Stage/server/$ServerAsset"
|
|
Write-Host "OK bundled $ServerAsset"
|
|
} else {
|
|
Write-Warning "no $ServerAsset to bundle - this build cannot serve WSL distros"
|
|
}
|
|
|
|
# The marker tells the in-app updater which of the two Windows layouts it is
|
|
# running from, and therefore which release asset can replace it. It says
|
|
# nothing about where updates come from: that is always the latest stable
|
|
# release. The Inno payload gets the mutually exclusive marker below.
|
|
if ($PackageUpdater) {
|
|
Set-Content -Path "$Stage/.tty7-portable" -Value 'portable-v1' -NoNewline -Encoding ascii
|
|
}
|
|
Compress-Archive -Path "$Stage/*" -DestinationPath "dist/$Name.zip" -Force
|
|
if ($PackageUpdater) {
|
|
# The Inno payload must never retain the mutually exclusive portable marker.
|
|
Remove-Item -LiteralPath "$Stage/.tty7-portable" -Force
|
|
Set-Content -Path "$Stage/.tty7-inno-install" -Value 'inno-v1' -NoNewline -Encoding ascii
|
|
}
|
|
|
|
# Installer, built from the same staged payload. ISCC is on PATH on GitHub's
|
|
# windows-latest image; fall back to the default install location.
|
|
$Iscc = (Get-Command ISCC.exe -ErrorAction SilentlyContinue).Source
|
|
if (-not $Iscc) { $Iscc = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe" }
|
|
& $Iscc `
|
|
"/DAppVersion=$Version" `
|
|
"/DVersionInfoVersion=$VersionInfoVersion" `
|
|
"/DStageDir=$((Resolve-Path $Stage).Path)" `
|
|
"/DOutputDir=$((Resolve-Path dist).Path)" `
|
|
"/DOutputName=$Name-setup" `
|
|
.github/scripts/windows-installer.iss
|
|
if ($LASTEXITCODE -ne 0) { throw "ISCC exited with $LASTEXITCODE" }
|
|
|
|
# The staging directory stays. It is what ISCC compiled the installer from, and
|
|
# reading the compiled setup.exe back would need innoextract, which the runners
|
|
# do not carry — so `verify-windows-package.ps1` reads the payload here instead.
|
|
# It never reaches the release: both workflows upload named file globs
|
|
# (*.zip, *-setup.exe, …), and a directory matches none of them.
|
|
Write-Host "OK dist/$Name.zip"
|
|
Write-Host "OK dist/$Name-setup.exe"
|