1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
param(
[Parameter(Mandatory = $true)]
[string] $ExePath,
[string] $Session = "ci-windows-$([guid]::NewGuid().ToString('N'))"
)
$ErrorActionPreference = "Stop"
function Invoke-Checked {
param([string] $Command, [string[]] $Arguments)
& $Command @Arguments
if ($LASTEXITCODE -ne 0) {
throw "command failed with exit code $LASTEXITCODE`: $Command $($Arguments -join ' ')"
}
}
$exe = (Resolve-Path $ExePath).Path
$fakeDir = Join-Path ([System.IO.Path]::GetTempPath()) "herdr-fake-conpty-$([guid]::NewGuid().ToString('N'))"
New-Item -ItemType Directory -Force $fakeDir | Out-Null
$fakeSource = Join-Path $fakeDir "fake_conpty.rs"
$fakeDll = Join-Path $fakeDir "conpty.dll"
@'
#![allow(non_snake_case)]
use std::ffi::c_void;
#[repr(C)]
pub struct COORD {
pub X: i16,
pub Y: i16,
}
type HANDLE = *mut c_void;
type HRESULT = i32;
#[no_mangle]
pub extern "system" fn CreatePseudoConsole(
_size: COORD,
_h_input: HANDLE,
_h_output: HANDLE,
_flags: u32,
_hpc: *mut HANDLE,
) -> HRESULT {
-2147467259
}
#[no_mangle]
pub extern "system" fn ResizePseudoConsole(_hpc: HANDLE, _size: COORD) -> HRESULT {
-2147467259
}
#[no_mangle]
pub extern "system" fn ClosePseudoConsole(_hpc: HANDLE) {}
'@ | Set-Content -NoNewline -Encoding utf8 $fakeSource
Invoke-Checked rustc @("--crate-type", "cdylib", "--edition", "2021", $fakeSource, "-o", $fakeDll)
$oldPath = $env:PATH
$oldSession = $env:HERDR_SESSION
$env:PATH = "$fakeDir;$oldPath"
$env:HERDR_SESSION = $Session
$server = $null
try {
Invoke-Checked $exe @("--version")
& $exe --default-config | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "command failed with exit code $LASTEXITCODE`: $exe --default-config"
}
$server = Start-Process -FilePath $exe -ArgumentList "server" -PassThru -WindowStyle Hidden
$deadline = (Get-Date).AddSeconds(10)
do {
Start-Sleep -Milliseconds 250
$status = & $exe status server 2>&1
if ($LASTEXITCODE -eq 0 -and (($status -join "`n") -match "status: running")) {
break
}
} while ((Get-Date) -lt $deadline)
if ((Get-Date) -ge $deadline) {
throw "server did not become ready"
}
$created = & $exe workspace create --cwd $PWD.Path 2>&1
if ($LASTEXITCODE -ne 0) {
throw "workspace create failed with exit code $LASTEXITCODE`: $($created -join "`n")"
}
$paneId = (($created -join "`n") | ConvertFrom-Json).result.root_pane.pane_id
if ([string]::IsNullOrWhiteSpace($paneId)) {
throw "workspace create did not return a root pane id: $($created -join "`n")"
}
$marker = "HERDR_CONPTY_SMOKE_OK"
Invoke-Checked $exe @("pane", "run", $paneId, "echo $marker")
$text = ""
$deadline = (Get-Date).AddSeconds(15)
do {
Start-Sleep -Milliseconds 500
try {
$read = & $exe pane read $paneId --source recent-unwrapped --lines 40 --format text 2>&1
$readExitCode = $LASTEXITCODE
} catch {
$read = @($_.Exception.Message)
$readExitCode = 1
}
$text = $read -join "`n"
if ($readExitCode -eq 0 -and (($text -replace "\s", "") -match $marker)) {
break
}
} while ((Get-Date) -lt $deadline)
if (($text -replace "\s", "") -notmatch $marker) {
throw "pane read did not include the smoke marker: $text"
}
} finally {
if ($null -ne $server) {
try {
$stopOutput = & $exe server stop 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host "server stop during cleanup exited with $LASTEXITCODE`: $($stopOutput -join "`n")"
}
} catch {
Write-Host "server stop during cleanup failed: $($_.Exception.Message)"
}
Wait-Process -Id $server.Id -Timeout 10 -ErrorAction SilentlyContinue
}
$global:LASTEXITCODE = 0
$env:PATH = $oldPath
$env:HERDR_SESSION = $oldSession
Remove-Item -Recurse -Force $fakeDir -ErrorAction SilentlyContinue
}
|