aboutsummaryrefslogtreecommitdiff
path: root/scripts/windows_smoke_conpty_path.ps1
blob: bec93b66f489ecb10b022aac6a3776427269ce17 (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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
$oldSocket = $env:HERDR_SOCKET_PATH
$oldClientSocket = $env:HERDR_CLIENT_SOCKET_PATH
$env:PATH = "$fakeDir;$oldPath"
$env:HERDR_SESSION = $Session
Remove-Item Env:HERDR_SOCKET_PATH, Env:HERDR_CLIENT_SOCKET_PATH -ErrorAction SilentlyContinue

$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"
    }

    $savedErrorActionPreference = $ErrorActionPreference
    try {
        $ErrorActionPreference = "Continue"
        $created = & $exe workspace create --cwd $PWD.Path 2>&1
        $createdExitCode = $LASTEXITCODE
    } finally {
        $ErrorActionPreference = $savedErrorActionPreference
    }
    if ($createdExitCode -ne 0) {
        throw "workspace create failed with exit code $createdExitCode`: $($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
        $server.Refresh()
        if (-not $server.HasExited) {
            & taskkill.exe /PID $server.Id /T /F 2>&1 | Out-Null
        }
    }
    $global:LASTEXITCODE = 0
    $env:PATH = $oldPath
    if ($null -eq $oldSession) {
        Remove-Item Env:HERDR_SESSION -ErrorAction SilentlyContinue
    } else {
        $env:HERDR_SESSION = $oldSession
    }
    if ($null -eq $oldSocket) {
        Remove-Item Env:HERDR_SOCKET_PATH -ErrorAction SilentlyContinue
    } else {
        $env:HERDR_SOCKET_PATH = $oldSocket
    }
    if ($null -eq $oldClientSocket) {
        Remove-Item Env:HERDR_CLIENT_SOCKET_PATH -ErrorAction SilentlyContinue
    } else {
        $env:HERDR_CLIENT_SOCKET_PATH = $oldClientSocket
    }
    Remove-Item -Recurse -Force $fakeDir -ErrorAction SilentlyContinue
}