From d497ee14dd3f2b5325a16d0de779ed6bd62178ee Mon Sep 17 00:00:00 2001 From: Can Celik Date: Tue, 18 Aug 2026 03:45:53 +0300 Subject: fix: retry Windows installer activation after transient locks (#2921) refs #2916 --- scripts/windows_arm64_installer_test.ps1 | 49 +++++++++++++++++++++ scripts/windows_install_conpty_package_test.ps1 | 58 +++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 scripts/windows_arm64_installer_test.ps1 (limited to 'scripts') diff --git a/scripts/windows_arm64_installer_test.ps1 b/scripts/windows_arm64_installer_test.ps1 new file mode 100644 index 00000000..7f5d7174 --- /dev/null +++ b/scripts/windows_arm64_installer_test.ps1 @@ -0,0 +1,49 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$architecture = [System.Runtime.InteropServices.RuntimeInformation, mscorlib]::OSArchitecture.ToString() +Write-Host "OS architecture: $architecture" +Write-Host "Process architecture: $([System.Runtime.InteropServices.RuntimeInformation, mscorlib]::ProcessArchitecture)" +Write-Host "PowerShell: $($PSVersionTable.PSVersion) $($PSVersionTable.PSEdition)" +Write-Host "Windows: $([Environment]::OSVersion.VersionString)" +if ($architecture -ne "Arm64") { + throw "This test requires Windows ARM64, found $architecture." +} + +$root = Join-Path $env:RUNNER_TEMP "herdr-windows-arm64-installer-test" +$env:HERDR_HOME = Join-Path $root "home" +$env:HERDR_INSTALL_DIR = Join-Path $root "bin" +$env:HERDR_CHANNEL = "preview" +Remove-Item -LiteralPath $root -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $root | Out-Null +$installer = (Resolve-Path (Join-Path $PSScriptRoot "..\website\install.ps1")).Path + +$previousErrorActionPreference = $ErrorActionPreference +$ErrorActionPreference = "Continue" +try { + $installerOutput = & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $installer 2>&1 + $installerExitCode = $LASTEXITCODE +} finally { + $ErrorActionPreference = $previousErrorActionPreference +} +$installerOutput | ForEach-Object { Write-Host $_ } +if ($installerExitCode -ne 0) { + throw "The installer failed on Windows ARM64 with exit code $installerExitCode." +} + +$installedHerdr = Join-Path $env:HERDR_INSTALL_DIR "herdr.exe" +if (-not (Test-Path -LiteralPath $installedHerdr -PathType Leaf)) { + throw "The installer exited successfully without activating herdr.exe." +} +& $installedHerdr --version +if ($LASTEXITCODE -ne 0) { + throw "The installed x86_64 Herdr executable failed with exit code $LASTEXITCODE." +} + +$releases = Join-Path $env:HERDR_HOME "packages\standalone\releases" +if (@(Get-ChildItem -LiteralPath $releases -Force -Directory -Filter ".staging.*" -ErrorAction SilentlyContinue).Count -ne 0) { + throw "The installer succeeded but left a staging directory behind." +} + +Write-Host "Windows ARM64 installer test passed." diff --git a/scripts/windows_install_conpty_package_test.ps1 b/scripts/windows_install_conpty_package_test.ps1 index 4b0e73f3..95b31c4a 100644 --- a/scripts/windows_install_conpty_package_test.ps1 +++ b/scripts/windows_install_conpty_package_test.ps1 @@ -212,6 +212,64 @@ try { $manifest | Out-File -LiteralPath $manifestPath -Encoding utf8 $stagedConpty = Join-Path $releasesDir ".staging.$($releaseDir.Name).$PID\conpty\conpty.dll" + + $transientLockState = @{ Handle = $null; Acquired = $false; Released = $false } + $transientLockTimer = New-Object System.Timers.Timer + $transientLockTimer.Interval = 300 + $transientLockTimer.AutoReset = $false + $transientLockSource = "HerdrTransientInstallerLock-$PID" + $transientLockRelease = Register-ObjectEvent ` + -InputObject $transientLockTimer ` + -EventName Elapsed ` + -SourceIdentifier $transientLockSource ` + -MessageData $transientLockState ` + -Action { + $state = $event.MessageData + if ($null -ne $state.Handle) { + $state.Handle.Dispose() + $state.Handle = $null + } + $state.Released = $true + } + $lockStagedFileTransiently = { + if (-not $transientLockState.Acquired) { + $transientLockState.Handle = [System.IO.File]::Open( + $stagedConpty, + [System.IO.FileMode]::Open, + [System.IO.FileAccess]::Read, + [System.IO.FileShare]::Read + ) + $transientLockState.Acquired = $true + $transientLockTimer.Start() + } + }.GetNewClosure() + $transientLockBreakpoint = Set-PSBreakpoint -Script $installerPath -Variable "backupDir" -Mode Write -Action $lockStagedFileTransiently + try { + & "$PSScriptRoot\..\website\install.ps1" ` + -ManifestUrl $manifestUrl ` + -InstallDir $installDir ` + -ExpectedBuildId "installer-test" + if (-not $transientLockState.Acquired) { + throw "installer did not acquire the transient staged-file lock" + } + if (-not $transientLockState.Released) { + throw "installer activated the release before the transient lock was released" + } + if (-not (Test-Path -LiteralPath (Join-Path $releaseDir.FullName "conpty\conpty.dll") -PathType Leaf)) { + throw "installer did not repair the release after the transient lock cleared" + } + } finally { + Remove-PSBreakpoint -Breakpoint $transientLockBreakpoint + $transientLockTimer.Stop() + Unregister-Event -SourceIdentifier $transientLockSource -ErrorAction SilentlyContinue + Remove-Job -Id $transientLockRelease.Id -Force -ErrorAction SilentlyContinue + if ($null -ne $transientLockState.Handle) { + $transientLockState.Handle.Dispose() + } + $transientLockTimer.Dispose() + } + + Remove-Item -LiteralPath (Join-Path $releaseDir.FullName "conpty\conpty.dll") -Force $lockState = @{ Handle = $null } $lockStagedFile = { if ($null -eq $lockState.Handle) { -- cgit v1.2.3