forked from goodrain/rainbond
/
command.go
96 lines (85 loc) · 2.45 KB
/
command.go
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package util
import (
"bytes"
"io"
"os/exec"
)
//PipeCommand PipeCommand
type PipeCommand struct {
stack []*exec.Cmd
finalStdout, finalStderr io.Reader
pipestack []*io.PipeWriter
}
//NewPipeCommand new pipe commands
func NewPipeCommand(stack ...*exec.Cmd) (*PipeCommand, error) {
var errorbuffer bytes.Buffer
pipestack := make([]*io.PipeWriter, len(stack)-1)
i := 0
for ; i < len(stack)-1; i++ {
stdinpipe, stdoutpipe := io.Pipe()
stack[i].Stdout = stdoutpipe
stack[i].Stderr = &errorbuffer
stack[i+1].Stdin = stdinpipe
pipestack[i] = stdoutpipe
}
finalStdout, err := stack[i].StdoutPipe()
if err != nil {
return nil, err
}
finalStderr, err := stack[i].StderrPipe()
if err != nil {
return nil, err
}
pipeCommand := &PipeCommand{
stack: stack,
pipestack: pipestack,
finalStdout: finalStdout,
finalStderr: finalStderr,
}
return pipeCommand, nil
}
//Run Run
func (p *PipeCommand) Run() error {
return call(p.stack, p.pipestack)
}
//GetFinalStdout get final command stdout reader
func (p *PipeCommand) GetFinalStdout() io.Reader {
return p.finalStdout
}
//GetFinalStderr get final command stderr reader
func (p *PipeCommand) GetFinalStderr() io.Reader {
return p.finalStderr
}
func call(stack []*exec.Cmd, pipes []*io.PipeWriter) (err error) {
if stack[0].Process == nil {
if err = stack[0].Start(); err != nil {
return err
}
}
if len(stack) > 1 {
if err = stack[1].Start(); err != nil {
return err
}
defer func() {
if err == nil {
pipes[0].Close()
err = call(stack[1:], pipes[1:])
}
}()
}
return stack[0].Wait()
}