package infra import ( "time" ) // ProcessWait waits for a subprocess to finish and collects its output. // If timeoutSec > 0 and the process has not exited by then, ProcessKill is // called with graceSec=5 and the result is marked Killed=true. func ProcessWait(handle *ProcessHandle, timeoutSec int) (ProcessResult, error) { // Wait for the process in a goroutine. waitCh := make(chan error, 1) go func() { waitCh <- handle.Cmd.Wait() }() killed := false if timeoutSec > 0 { timer := time.NewTimer(time.Duration(timeoutSec) * time.Second) defer timer.Stop() select { case <-timer.C: // Timeout exceeded — kill the process group. _ = ProcessKill(handle, 5) killed = true <-waitCh case <-waitCh: } } else { <-waitCh } // After Wait() returns, buffers are safe to read. exitCode := 0 if handle.Cmd.ProcessState != nil { exitCode = handle.Cmd.ProcessState.ExitCode() } else if killed { exitCode = -1 } duration := time.Since(handle.StartTime) return ProcessResult{ ExitCode: exitCode, Stdout: handle.stdout.String(), Stderr: handle.stderr.String(), DurationMs: duration.Milliseconds(), Killed: killed, }, nil }