Use direct process streaming in scratch runner
This commit is contained in:
@@ -67,16 +67,6 @@ function Format-ProcessArgument {
|
|||||||
return '"' + ($Value -replace '(\\*)"', '$1$1\"' -replace '(\\+)$', '$1$1') + '"'
|
return '"' + ($Value -replace '(\\*)"', '$1$1\"' -replace '(\\+)$', '$1$1') + '"'
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConvertTo-PowerShellLiteral {
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory = $true)]
|
|
||||||
[AllowEmptyString()]
|
|
||||||
[string]$Value
|
|
||||||
)
|
|
||||||
|
|
||||||
return "'" + ($Value -replace "'", "''") + "'"
|
|
||||||
}
|
|
||||||
|
|
||||||
function Invoke-External {
|
function Invoke-External {
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
@@ -88,9 +78,6 @@ function Invoke-External {
|
|||||||
)
|
)
|
||||||
|
|
||||||
Push-Location $WorkingDirectory
|
Push-Location $WorkingDirectory
|
||||||
$stdoutPath = New-LogCapturePath -Suffix '.stdout.log'
|
|
||||||
$stderrPath = New-LogCapturePath -Suffix '.stderr.log'
|
|
||||||
$wrapperPath = New-LogCapturePath -Suffix '.invoke.ps1'
|
|
||||||
try {
|
try {
|
||||||
$resolvedFilePath = $FilePath
|
$resolvedFilePath = $FilePath
|
||||||
if (Test-Path $FilePath) {
|
if (Test-Path $FilePath) {
|
||||||
@@ -99,60 +86,85 @@ function Invoke-External {
|
|||||||
|
|
||||||
$startFilePath = $resolvedFilePath
|
$startFilePath = $resolvedFilePath
|
||||||
$startArgumentList = @($ArgumentList)
|
$startArgumentList = @($ArgumentList)
|
||||||
$powershellPath = (Get-Command powershell.exe -ErrorAction Stop).Source
|
|
||||||
|
|
||||||
if ([System.IO.Path]::GetExtension($resolvedFilePath).Equals('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) {
|
if ([System.IO.Path]::GetExtension($resolvedFilePath).Equals('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||||
|
$powershellPath = (Get-Command powershell.exe -ErrorAction Stop).Source
|
||||||
$startFilePath = $powershellPath
|
$startFilePath = $powershellPath
|
||||||
$startArgumentList = @('-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $resolvedFilePath) + @($ArgumentList)
|
$startArgumentList = @('-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $resolvedFilePath) + @($ArgumentList)
|
||||||
}
|
}
|
||||||
|
|
||||||
$invocationExpression = '& ' + (ConvertTo-PowerShellLiteral -Value $startFilePath)
|
$startInfo = [System.Diagnostics.ProcessStartInfo]::new()
|
||||||
if ($startArgumentList.Count -gt 0) {
|
$startInfo.FileName = $startFilePath
|
||||||
$invocationExpression += ' ' + (($startArgumentList | ForEach-Object { ConvertTo-PowerShellLiteral -Value $_ }) -join ' ')
|
$startInfo.WorkingDirectory = $WorkingDirectory
|
||||||
|
$startInfo.UseShellExecute = $false
|
||||||
|
$startInfo.RedirectStandardOutput = $true
|
||||||
|
$startInfo.RedirectStandardError = $true
|
||||||
|
foreach ($argument in $startArgumentList) {
|
||||||
|
[void]$startInfo.ArgumentList.Add([string]$argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
$wrapperContent = @(
|
$process = [System.Diagnostics.Process]::new()
|
||||||
'$ErrorActionPreference = ''Stop'''
|
$process.StartInfo = $startInfo
|
||||||
"$invocationExpression 1> $(ConvertTo-PowerShellLiteral -Value $stdoutPath) 2> $(ConvertTo-PowerShellLiteral -Value $stderrPath)"
|
|
||||||
'exit $LASTEXITCODE'
|
|
||||||
''
|
|
||||||
)
|
|
||||||
Set-Content -Path $wrapperPath -Value $wrapperContent -Encoding UTF8
|
|
||||||
|
|
||||||
$formattedArgumentList = @(@('-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $wrapperPath) | ForEach-Object { Format-ProcessArgument -Value $_ })
|
$stdoutQueue = [System.Collections.Concurrent.ConcurrentQueue[string]]::new()
|
||||||
|
$stderrQueue = [System.Collections.Concurrent.ConcurrentQueue[string]]::new()
|
||||||
|
|
||||||
$process = Start-Process `
|
$stdoutHandler = [System.Diagnostics.DataReceivedEventHandler]{
|
||||||
-FilePath $powershellPath `
|
param($sender, $eventArgs)
|
||||||
-ArgumentList $formattedArgumentList `
|
if ($null -ne $eventArgs.Data) {
|
||||||
-WorkingDirectory $WorkingDirectory `
|
$stdoutQueue.Enqueue($eventArgs.Data)
|
||||||
-PassThru
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$stdoutIndex = 0
|
$stderrHandler = [System.Diagnostics.DataReceivedEventHandler]{
|
||||||
$stderrIndex = 0
|
param($sender, $eventArgs)
|
||||||
|
if ($null -ne $eventArgs.Data) {
|
||||||
|
$stderrQueue.Enqueue($eventArgs.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$process.add_OutputDataReceived($stdoutHandler)
|
||||||
|
$process.add_ErrorDataReceived($stderrHandler)
|
||||||
|
|
||||||
|
if (-not $process.Start()) {
|
||||||
|
throw "Failed to start process: $resolvedFilePath"
|
||||||
|
}
|
||||||
|
|
||||||
|
$process.BeginOutputReadLine()
|
||||||
|
$process.BeginErrorReadLine()
|
||||||
|
|
||||||
|
$dequeuedLine = $null
|
||||||
while (-not $process.HasExited) {
|
while (-not $process.HasExited) {
|
||||||
Write-LogCaptureDelta -Path $stdoutPath -LineIndex ([ref]$stdoutIndex)
|
while ($stdoutQueue.TryDequeue([ref]$dequeuedLine)) {
|
||||||
Write-LogCaptureDelta -Path $stderrPath -LineIndex ([ref]$stderrIndex)
|
$dequeuedLine | Out-Host
|
||||||
|
$dequeuedLine = $null
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($stderrQueue.TryDequeue([ref]$dequeuedLine)) {
|
||||||
|
$dequeuedLine | Out-Host
|
||||||
|
$dequeuedLine = $null
|
||||||
|
}
|
||||||
|
|
||||||
Start-Sleep -Milliseconds 500
|
Start-Sleep -Milliseconds 500
|
||||||
$process.Refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$process.WaitForExit()
|
$process.WaitForExit()
|
||||||
$process.Refresh()
|
|
||||||
Write-LogCaptureDelta -Path $stdoutPath -LineIndex ([ref]$stdoutIndex)
|
while ($stdoutQueue.TryDequeue([ref]$dequeuedLine)) {
|
||||||
Write-LogCaptureDelta -Path $stderrPath -LineIndex ([ref]$stderrIndex)
|
$dequeuedLine | Out-Host
|
||||||
|
$dequeuedLine = $null
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($stderrQueue.TryDequeue([ref]$dequeuedLine)) {
|
||||||
|
$dequeuedLine | Out-Host
|
||||||
|
$dequeuedLine = $null
|
||||||
|
}
|
||||||
|
|
||||||
if ($process.ExitCode -ne 0) {
|
if ($process.ExitCode -ne 0) {
|
||||||
throw "Command failed: $resolvedFilePath $($ArgumentList -join ' ')"
|
throw "Command failed: $resolvedFilePath $($ArgumentList -join ' ')"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
foreach ($capturePath in @($stdoutPath, $stderrPath, $wrapperPath)) {
|
|
||||||
if (Test-Path $capturePath) {
|
|
||||||
Remove-Item $capturePath -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Pop-Location
|
Pop-Location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user