-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbuilder_chain.go
106 lines (87 loc) · 2.41 KB
/
builder_chain.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
97
98
99
100
101
102
103
104
105
106
package cmdchain
import (
"context"
"io"
"os/exec"
"sync"
)
type chain struct {
cmdDescriptors []cmdDescriptor
inputs []io.Reader
buildErrors MultipleErrors
streamErrors MultipleErrors
streamRoutinesWg sync.WaitGroup
errorChecker ErrorChecker
}
type cmdDescriptor struct {
command *exec.Cmd
outToIn bool
errToIn bool
outFork io.Writer
errFork io.Writer
commandApplier []CommandApplier
errorChecker ErrorChecker
inputStreams []io.Reader
outputStreams []io.Writer
errorStreams []io.Writer
}
// Builder creates a new command chain builder. This build flow will configure
// the commands more or less instantaneously. If any error occurs while building
// the chain you will receive them when you finally call Run of this chain.
func Builder() FirstCommandBuilder {
return &chain{
buildErrors: buildErrors(),
streamErrors: streamErrors(),
streamRoutinesWg: sync.WaitGroup{},
}
}
func (c *chain) WithInput(sources ...io.Reader) ChainBuilder {
c.inputs = sources
return c
}
func (c *chain) JoinCmd(cmd *exec.Cmd) CommandBuilder {
if cmd == nil {
return c
}
c.cmdDescriptors = append(c.cmdDescriptors, cmdDescriptor{
command: cmd,
outToIn: true,
})
c.streamErrors.addError(nil)
if len(c.cmdDescriptors) > 1 {
c.linkStreams(cmd)
}
return c
}
func (c *chain) Join(name string, args ...string) CommandBuilder {
return c.JoinCmd(exec.Command(name, args...))
}
func (c *chain) JoinWithContext(ctx context.Context, name string, args ...string) CommandBuilder {
return c.JoinCmd(exec.CommandContext(ctx, name, args...))
}
func (c *chain) Finalize() FinalizedBuilder {
if len(c.cmdDescriptors) == 0 {
return c
}
firstCmdDesc := &(c.cmdDescriptors[0])
is := firstCmdDesc.inputStreams
firstCmdDesc.inputStreams = append([]io.Reader{}, c.inputs...)
firstCmdDesc.inputStreams = append(firstCmdDesc.inputStreams, is...)
if len(c.inputs) == 1 {
firstCmdDesc.command.Stdin = c.inputs[0]
} else if len(c.inputs) > 1 {
var err error
firstCmdDesc.command.Stdin, err = c.combineStreamForCommand(0, c.inputs...)
if c.streamErrors.Errors()[0] == nil {
c.streamErrors.setError(0, err)
}
}
lastCmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
if lastCmdDesc.outFork != nil {
lastCmdDesc.command.Stdout = lastCmdDesc.outFork
}
if lastCmdDesc.errFork != nil {
lastCmdDesc.command.Stderr = lastCmdDesc.errFork
}
return c
}