mirror of
https://github.com/zrepl/zrepl.git
synced 2025-01-24 07:09:07 +01:00
63 lines
1.2 KiB
Go
63 lines
1.2 KiB
Go
package zfs
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os/exec"
|
|
)
|
|
|
|
// A ForkReader is an io.Reader for a forked process's stdout.
|
|
// It Wait()s for the process to exit and - if it exits with error - returns this exit error
|
|
// on subsequent Read()s.
|
|
type ForkExecReader struct {
|
|
Cmd *exec.Cmd
|
|
InStream io.Reader
|
|
StderrBuf *bytes.Buffer
|
|
}
|
|
|
|
func NewForkExecReader(command string, args ...string) (r *ForkExecReader, err error) {
|
|
|
|
r = &ForkExecReader{}
|
|
|
|
r.Cmd = exec.Command(command, args...)
|
|
|
|
r.InStream, err = r.Cmd.StdoutPipe()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
r.StderrBuf = bytes.NewBuffer(make([]byte, 0, 1024))
|
|
r.Cmd.Stderr = r.StderrBuf
|
|
|
|
if err = r.Cmd.Start(); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
type ForkExecReaderError struct {
|
|
WaitErr error
|
|
Stderr []byte
|
|
}
|
|
|
|
func (e ForkExecReaderError) Error() string {
|
|
return fmt.Sprintf("underlying process exited with error: %s\nstderr: %s\n", e.WaitErr, e.Stderr)
|
|
}
|
|
|
|
func (t *ForkExecReader) Read(buf []byte) (n int, err error) {
|
|
n, err = t.InStream.Read(buf)
|
|
if err == io.EOF {
|
|
waitErr := t.Cmd.Wait()
|
|
if waitErr != nil {
|
|
err = ForkExecReaderError{
|
|
WaitErr: waitErr,
|
|
Stderr: t.StderrBuf.Bytes(),
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|