pipe.go (1227B)
1 package giffer 2 3 import ( 4 "bytes" 5 "io" 6 "log" 7 "os/exec" 8 9 "github.com/pkg/errors" 10 ) 11 12 // CmdPipe executes a stack of commands, piping in order. 13 type CmdPipe struct { 14 In io.Reader 15 Out io.Writer 16 Stack []*exec.Cmd 17 18 Debug bool 19 } 20 21 // Run the commands. 22 func (p CmdPipe) Run() (err error) { 23 var errBuf bytes.Buffer 24 defer func() { 25 if p.Debug { 26 log.Printf("%s", errBuf.String()) 27 } 28 }() 29 pipes := make([]*io.PipeWriter, len(p.Stack)-1) 30 ii := 0 31 for ; ii < len(p.Stack)-1; ii++ { 32 if ii == 0 { 33 p.Stack[ii].Stdin = p.In 34 } 35 stdin, stdout := io.Pipe() 36 p.Stack[ii].Stdout = stdout 37 p.Stack[ii].Stderr = &errBuf 38 p.Stack[ii+1].Stdin = stdin 39 pipes[ii] = stdout 40 } 41 p.Stack[ii].Stdout = p.Out 42 p.Stack[ii].Stderr = &errBuf 43 if err := call(p.Stack, pipes); err != nil { 44 return errors.Wrap(err, string(errBuf.Bytes())) 45 } 46 return err 47 } 48 49 func call(stack []*exec.Cmd, pipes []*io.PipeWriter) (err error) { 50 if stack[0].Process == nil { 51 if err = stack[0].Start(); err != nil { 52 return err 53 } 54 } 55 if len(stack) > 1 { 56 if err = stack[1].Start(); err != nil { 57 return err 58 } 59 defer func() { 60 if err == nil { 61 pipes[0].Close() 62 err = call(stack[1:], pipes[1:]) 63 } 64 }() 65 } 66 return stack[0].Wait() 67 }