|
| 1 | +param( |
| 2 | + [Parameter(Mandatory = $true)] |
| 3 | + [ValidateSet("stable", "insiders")] |
| 4 | + [string] $Quality, |
| 5 | + |
| 6 | + [Parameter(Mandatory = $true)] |
| 7 | + [int] $Port, |
| 8 | + |
| 9 | + [Parameter(Mandatory = $true)] |
| 10 | + [string] $Workspace |
| 11 | +) |
| 12 | + |
| 13 | +$ErrorActionPreference = "Stop" |
| 14 | + |
| 15 | +switch ($Quality) { |
| 16 | + "stable" { |
| 17 | + $cli = "code" |
| 18 | + $installHint = "Shell Command: Install 'code' command in PATH" |
| 19 | + } |
| 20 | + "insiders" { |
| 21 | + $cli = "code-insiders" |
| 22 | + $installHint = "Shell Command: Install 'code-insiders' command in PATH" |
| 23 | + } |
| 24 | +} |
| 25 | + |
| 26 | +if (-not (Get-Command $cli -ErrorAction SilentlyContinue)) { |
| 27 | + [Console]::Error.WriteLine("Missing '$cli' in PATH.`nInstall it from the target VS Code Command Palette:`n $installHint`nThen restart the terminal and try again.") |
| 28 | + exit 127 |
| 29 | +} |
| 30 | + |
| 31 | +function Get-ProcessCommandLine { |
| 32 | + param([int] $ProcessId) |
| 33 | + |
| 34 | + try { |
| 35 | + $processInfo = Get-CimInstance Win32_Process -Filter "ProcessId = $ProcessId" |
| 36 | + return $processInfo.CommandLine |
| 37 | + } catch { |
| 38 | + return "" |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +try { |
| 43 | + $connections = @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue) |
| 44 | +} catch { |
| 45 | + Write-Warning "Get-NetTCPConnection is unavailable; skipping stale inspector cleanup for port $Port." |
| 46 | + $connections = @() |
| 47 | +} |
| 48 | + |
| 49 | +function Test-PortListening { |
| 50 | + try { |
| 51 | + return [bool](Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue) |
| 52 | + } catch { |
| 53 | + return $false |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +function Wait-ForPortRelease { |
| 58 | + for ($attempt = 0; $attempt -lt 10; $attempt++) { |
| 59 | + if (-not (Test-PortListening)) { |
| 60 | + return |
| 61 | + } |
| 62 | + Start-Sleep -Milliseconds 200 |
| 63 | + } |
| 64 | + |
| 65 | + [Console]::Error.WriteLine("Port $Port is still in use after stopping stale extension host processes.") |
| 66 | + exit 1 |
| 67 | +} |
| 68 | + |
| 69 | +$processIds = @($connections | ForEach-Object { $_.OwningProcess } | Where-Object { $_ } | Sort-Object -Unique) |
| 70 | +$stoppedProcess = $false |
| 71 | + |
| 72 | +foreach ($processId in $processIds) { |
| 73 | + $commandLine = Get-ProcessCommandLine -ProcessId $processId |
| 74 | + |
| 75 | + if ([string]::IsNullOrWhiteSpace($commandLine)) { |
| 76 | + [Console]::Error.WriteLine("Port $Port is already used by PID $processId, but its command line could not be inspected.`nRefusing to stop it automatically.") |
| 77 | + exit 1 |
| 78 | + } |
| 79 | + |
| 80 | + $isExtensionHost = $commandLine -like "*--inspect=127.0.0.1:$Port*" ` |
| 81 | + -or $commandLine -like "*--inspect-brk=127.0.0.1:$Port*" ` |
| 82 | + -or $commandLine -like "*--inspect=localhost:$Port*" ` |
| 83 | + -or $commandLine -like "*--inspect-brk=localhost:$Port*" |
| 84 | + |
| 85 | + if ($isExtensionHost) { |
| 86 | + Stop-Process -Id $processId -Force -ErrorAction SilentlyContinue |
| 87 | + $stoppedProcess = $true |
| 88 | + continue |
| 89 | + } |
| 90 | + |
| 91 | + [Console]::Error.WriteLine("Port $Port is already used by PID $processId, but it does not look like a VS Code extension host:`n$commandLine`nRefusing to stop it automatically.") |
| 92 | + exit 1 |
| 93 | +} |
| 94 | + |
| 95 | +if ($stoppedProcess) { |
| 96 | + Wait-ForPortRelease |
| 97 | +} |
| 98 | + |
| 99 | +& $cli ` |
| 100 | + --new-window ` |
| 101 | + "--inspect-extensions=$Port" ` |
| 102 | + "--extensionDevelopmentPath=$Workspace" ` |
| 103 | + $Workspace |
| 104 | + |
| 105 | +if ($LASTEXITCODE) { |
| 106 | + exit $LASTEXITCODE |
| 107 | +} |
0 commit comments