105 lines
3.3 KiB
PowerShell
105 lines
3.3 KiB
PowerShell
param(
|
|
[Parameter(Mandatory = $true)][string]$Executable,
|
|
[Parameter(Mandatory = $true)][string]$ArgumentsJsonPath,
|
|
[Parameter(Mandatory = $true)][string]$CapturePath,
|
|
[Parameter(Mandatory = $true)][string]$StdoutPath,
|
|
[Parameter(Mandatory = $true)][string]$StderrPath,
|
|
[Parameter(Mandatory = $true)][string]$StartedStatusPath,
|
|
[Parameter(Mandatory = $true)][string]$ResultStatusPath
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Write-JsonAtomically {
|
|
param(
|
|
[Parameter(Mandatory = $true)][object]$Value,
|
|
[Parameter(Mandatory = $true)][string]$Path
|
|
)
|
|
|
|
$temporaryPath = "$Path.tmp"
|
|
$json = $Value | ConvertTo-Json -Depth 8
|
|
$encoding = New-Object System.Text.UTF8Encoding($false)
|
|
[System.IO.File]::WriteAllText($temporaryPath, $json + [Environment]::NewLine, $encoding)
|
|
Move-Item -LiteralPath $temporaryPath -Destination $Path -Force
|
|
}
|
|
|
|
$decodedArguments = Get-Content -Raw -LiteralPath $ArgumentsJsonPath |
|
|
ConvertFrom-Json
|
|
if ($decodedArguments -isnot [System.Array]) {
|
|
throw 'ArgumentsJsonPath must contain a JSON array.'
|
|
}
|
|
$childArguments = @(
|
|
foreach ($argument in $decodedArguments) {
|
|
[string]$argument
|
|
}
|
|
)
|
|
$startedAt = [DateTimeOffset]::UtcNow
|
|
$finishedAt = $null
|
|
$childProcess = $null
|
|
$exitCode = $null
|
|
$runnerError = $null
|
|
$captureSize = 0
|
|
$sha256 = $null
|
|
|
|
try {
|
|
$startParameters = @{
|
|
FilePath = $Executable
|
|
ArgumentList = $childArguments
|
|
RedirectStandardOutput = $StdoutPath
|
|
RedirectStandardError = $StderrPath
|
|
PassThru = $true
|
|
WindowStyle = 'Hidden'
|
|
}
|
|
$childProcess = Start-Process @startParameters
|
|
# PowerShell 5 can lose ExitCode for redirected processes unless the
|
|
# underlying process handle is opened before WaitForExit().
|
|
$null = $childProcess.Handle
|
|
|
|
Write-JsonAtomically -Path $StartedStatusPath -Value ([ordered]@{
|
|
state = 'RUNNING'
|
|
pid = $childProcess.Id
|
|
started_at = $startedAt.ToString('o')
|
|
capture_path = $CapturePath
|
|
})
|
|
|
|
$childProcess.WaitForExit()
|
|
$childProcess.Refresh()
|
|
$exitCode = [int]$childProcess.ExitCode
|
|
} catch {
|
|
$runnerError = $_.Exception.ToString()
|
|
} finally {
|
|
$finishedAt = [DateTimeOffset]::UtcNow
|
|
if (Test-Path -LiteralPath $CapturePath) {
|
|
try {
|
|
$captureSize = [int64](Get-Item -LiteralPath $CapturePath).Length
|
|
$sha256 = (
|
|
Get-FileHash -LiteralPath $CapturePath -Algorithm SHA256
|
|
).Hash.ToLowerInvariant()
|
|
} catch {
|
|
$additionalError = $_.Exception.ToString()
|
|
if ([string]::IsNullOrWhiteSpace($runnerError)) {
|
|
$runnerError = $additionalError
|
|
} else {
|
|
$runnerError = $runnerError + [Environment]::NewLine + $additionalError
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-JsonAtomically -Path $ResultStatusPath -Value ([ordered]@{
|
|
pid = if ($null -ne $childProcess) { $childProcess.Id } else { $null }
|
|
started_at = $startedAt.ToString('o')
|
|
finished_at = $finishedAt.ToString('o')
|
|
duration = ($finishedAt - $startedAt).TotalSeconds
|
|
exit_code = $exitCode
|
|
capture_path = $CapturePath
|
|
capture_size = $captureSize
|
|
sha256 = $sha256
|
|
runner_error = $runnerError
|
|
})
|
|
}
|
|
|
|
if ($null -eq $exitCode) {
|
|
exit 255
|
|
}
|
|
exit $exitCode
|