File size: 1,185 Bytes
6932c8c | 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 | package shell
import (
"bytes"
"context"
"os"
"sync"
)
// progressWriter wraps an io.Writer and calls onProgress with each write.
// It is safe for concurrent use from multiple goroutines (e.g. stdout and
// stderr writing simultaneously).
type progressWriter struct {
mu sync.Mutex
buf bytes.Buffer
onProgress func(string)
}
func (w *progressWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
n, err := w.buf.Write(p)
if n > 0 && w.onProgress != nil {
w.onProgress(string(p[:n]))
}
return n, err
}
// RunAndCaptureStream executes a shell command and streams output chunks
// to onProgress as they arrive. Returns the complete output and exit code.
func RunAndCaptureStream(ctx context.Context, opts RunOptions, onProgress func(string)) (CaptureResult, error) {
if opts.Env == nil {
opts.Env = os.Environ()
}
opts.Env = append(opts.Env, ptyColorEnvVars...)
buf := &progressWriter{onProgress: onProgress}
opts.Stdout = buf
opts.Stderr = buf
runErr := Run(ctx, opts)
exitCode := 0
if runErr != nil {
exitCode = ExitCode(runErr)
}
return CaptureResult{
Output: buf.buf.String(),
ExitCode: exitCode,
}, nil
}
|