Skip to content

Commit 0d01ac2

Browse files
committed
implements some more convenience functions for stream handling and chain executing
1 parent 29e3f84 commit 0d01ac2

File tree

5 files changed

+288
-19
lines changed

5 files changed

+288
-19
lines changed

builder_chain.go

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,33 @@ func (c *chain) JoinWithContext(ctx context.Context, name string, args ...string
7474
}
7575

7676
func (c *chain) Finalize() FinalizedBuilder {
77-
if len(c.cmdDescriptors) > 0 {
78-
firstCmdDesc := &(c.cmdDescriptors[0])
79-
80-
is := firstCmdDesc.inputStreams
81-
firstCmdDesc.inputStreams = append([]io.Reader{}, c.inputs...)
82-
firstCmdDesc.inputStreams = append(firstCmdDesc.inputStreams, is...)
83-
84-
if len(c.inputs) == 1 {
85-
firstCmdDesc.command.Stdin = c.inputs[0]
86-
} else if len(c.inputs) > 1 {
87-
var err error
88-
firstCmdDesc.command.Stdin, err = c.combineStreamForCommand(0, c.inputs...)
89-
if c.streamErrors.Errors()[0] == nil {
90-
c.streamErrors.setError(0, err)
91-
}
77+
if len(c.cmdDescriptors) == 0 {
78+
return c
79+
}
80+
81+
firstCmdDesc := &(c.cmdDescriptors[0])
82+
83+
is := firstCmdDesc.inputStreams
84+
firstCmdDesc.inputStreams = append([]io.Reader{}, c.inputs...)
85+
firstCmdDesc.inputStreams = append(firstCmdDesc.inputStreams, is...)
86+
87+
if len(c.inputs) == 1 {
88+
firstCmdDesc.command.Stdin = c.inputs[0]
89+
} else if len(c.inputs) > 1 {
90+
var err error
91+
firstCmdDesc.command.Stdin, err = c.combineStreamForCommand(0, c.inputs...)
92+
if c.streamErrors.Errors()[0] == nil {
93+
c.streamErrors.setError(0, err)
9294
}
9395
}
96+
97+
lastCmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
98+
if lastCmdDesc.outFork != nil {
99+
lastCmdDesc.command.Stdout = lastCmdDesc.outFork
100+
}
101+
if lastCmdDesc.errFork != nil {
102+
lastCmdDesc.command.Stderr = lastCmdDesc.errFork
103+
}
104+
94105
return c
95106
}

builder_command.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (c *chain) DiscardStdOut() CommandBuilder {
3030

3131
func (c *chain) WithOutputForks(targets ...io.Writer) CommandBuilder {
3232
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
33-
cmdDesc.outputStreams = append(cmdDesc.outputStreams, targets...)
33+
cmdDesc.outputStreams = targets
3434

3535
if len(targets) > 1 {
3636
cmdDesc.outFork = io.MultiWriter(targets...)
@@ -41,9 +41,22 @@ func (c *chain) WithOutputForks(targets ...io.Writer) CommandBuilder {
4141
return c
4242
}
4343

44+
func (c *chain) WithAdditionalOutputForks(targets ...io.Writer) CommandBuilder {
45+
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
46+
cmdDesc.outputStreams = append(cmdDesc.outputStreams, targets...)
47+
48+
if len(cmdDesc.outputStreams) > 1 {
49+
cmdDesc.outFork = io.MultiWriter(cmdDesc.outputStreams...)
50+
} else if len(cmdDesc.outputStreams) == 1 {
51+
cmdDesc.outFork = cmdDesc.outputStreams[0]
52+
}
53+
54+
return c
55+
}
56+
4457
func (c *chain) WithErrorForks(targets ...io.Writer) CommandBuilder {
4558
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
46-
cmdDesc.errorStreams = append(cmdDesc.errorStreams, targets...)
59+
cmdDesc.errorStreams = targets
4760

4861
if len(targets) > 1 {
4962
cmdDesc.errFork = io.MultiWriter(targets...)
@@ -53,6 +66,18 @@ func (c *chain) WithErrorForks(targets ...io.Writer) CommandBuilder {
5366
return c
5467
}
5568

69+
func (c *chain) WithAdditionalErrorForks(targets ...io.Writer) CommandBuilder {
70+
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
71+
cmdDesc.errorStreams = append(cmdDesc.errorStreams, targets...)
72+
73+
if len(cmdDesc.errorStreams) > 1 {
74+
cmdDesc.errFork = io.MultiWriter(cmdDesc.errorStreams...)
75+
} else if len(cmdDesc.errorStreams) == 1 {
76+
cmdDesc.errFork = cmdDesc.errorStreams[0]
77+
}
78+
return c
79+
}
80+
5681
func (c *chain) WithInjections(sources ...io.Reader) CommandBuilder {
5782
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
5883
cmdDesc.inputStreams = append(cmdDesc.inputStreams, sources...)

builder_finalized.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package cmdchain
22

33
import (
4+
"bytes"
45
"fmt"
56
"io"
67
)
78

89
func (c *chain) WithOutput(targets ...io.Writer) FinalizedBuilder {
910
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
10-
cmdDesc.outputStreams = append(cmdDesc.outputStreams, targets...)
11+
cmdDesc.outputStreams = targets
1112

1213
if len(targets) == 1 {
1314
cmdDesc.command.Stdout = targets[0]
@@ -18,9 +19,22 @@ func (c *chain) WithOutput(targets ...io.Writer) FinalizedBuilder {
1819
return c
1920
}
2021

22+
func (c *chain) WithAdditionalOutput(targets ...io.Writer) FinalizedBuilder {
23+
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
24+
cmdDesc.outputStreams = append(cmdDesc.outputStreams, targets...)
25+
26+
if len(cmdDesc.outputStreams) == 1 {
27+
cmdDesc.command.Stdout = cmdDesc.outputStreams[0]
28+
} else if len(cmdDesc.outputStreams) > 1 {
29+
cmdDesc.command.Stdout = io.MultiWriter(cmdDesc.outputStreams...)
30+
}
31+
32+
return c
33+
}
34+
2135
func (c *chain) WithError(targets ...io.Writer) FinalizedBuilder {
2236
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
23-
cmdDesc.errorStreams = append(cmdDesc.errorStreams, targets...)
37+
cmdDesc.errorStreams = targets
2438

2539
if len(targets) == 1 {
2640
cmdDesc.command.Stderr = targets[0]
@@ -31,11 +45,33 @@ func (c *chain) WithError(targets ...io.Writer) FinalizedBuilder {
3145
return c
3246
}
3347

48+
func (c *chain) WithAdditionalError(targets ...io.Writer) FinalizedBuilder {
49+
cmdDesc := &(c.cmdDescriptors[len(c.cmdDescriptors)-1])
50+
cmdDesc.errorStreams = append(cmdDesc.errorStreams, targets...)
51+
52+
if len(cmdDesc.errorStreams) == 1 {
53+
cmdDesc.command.Stderr = cmdDesc.errorStreams[0]
54+
} else if len(cmdDesc.errorStreams) > 1 {
55+
cmdDesc.command.Stderr = io.MultiWriter(cmdDesc.errorStreams...)
56+
}
57+
58+
return c
59+
}
60+
3461
func (c *chain) WithGlobalErrorChecker(errorChecker ErrorChecker) FinalizedBuilder {
3562
c.errorChecker = errorChecker
3663
return c
3764
}
3865

66+
func (c *chain) RunAndGet() (string, string, error) {
67+
streamOut := &bytes.Buffer{}
68+
streamErr := &bytes.Buffer{}
69+
70+
err := c.WithAdditionalOutput(streamOut).WithAdditionalError(streamErr).Run()
71+
72+
return streamOut.String(), streamErr.String(), err
73+
}
74+
3975
func (c *chain) Run() error {
4076
if c.buildErrors.hasError {
4177
return c.buildErrors

chain_test.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,31 @@ func TestSimple(t *testing.T) {
3838
runAndCompare(t, toTest, "1\n")
3939
}
4040

41+
func TestSimple_runAndGet(t *testing.T) {
42+
stdout, stderr, err := Builder().
43+
Join(testHelper, "-e", "ERROR", "-o", "TEST").
44+
Finalize().RunAndGet()
45+
46+
assert.NoError(t, err)
47+
assert.Equal(t, "TEST\n", stdout)
48+
assert.Equal(t, "ERROR\n", stderr)
49+
}
50+
51+
func TestSimple_runAndGet_withForks(t *testing.T) {
52+
outFork := &bytes.Buffer{}
53+
errFork := &bytes.Buffer{}
54+
55+
stdout, stderr, err := Builder().
56+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithOutputForks(outFork).WithErrorForks(errFork).
57+
Finalize().RunAndGet()
58+
59+
assert.NoError(t, err)
60+
assert.Equal(t, "TEST\n", outFork.String())
61+
assert.Equal(t, "TEST\n", stdout)
62+
assert.Equal(t, "ERROR\n", errFork.String())
63+
assert.Equal(t, "ERROR\n", stderr)
64+
}
65+
4166
func TestSimple_apply(t *testing.T) {
4267
toTest := Builder().
4368
Join(testHelper, "-pwd").Apply(func(_ int, command *exec.Cmd) {
@@ -73,6 +98,106 @@ func TestSimple_stderr(t *testing.T) {
7398
assert.Equal(t, "ERROR\n", output.String())
7499
}
75100

101+
func TestSimple_with_error(t *testing.T) {
102+
output := &bytes.Buffer{}
103+
output2 := &bytes.Buffer{}
104+
105+
err := Builder().
106+
Join(testHelper, "-e", "ERROR", "-o", "TEST").
107+
Finalize().WithError(output).WithError(output2).Run()
108+
109+
assert.NoError(t, err)
110+
assert.Equal(t, "", output.String(), "first output stream should be overwritten")
111+
assert.Equal(t, "ERROR\n", output2.String())
112+
}
113+
114+
func TestSimple_with_additional_error_fork(t *testing.T) {
115+
output := &bytes.Buffer{}
116+
output2 := &bytes.Buffer{}
117+
118+
err := Builder().
119+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithErrorForks(output).WithAdditionalErrorForks(output2).
120+
Finalize().Run()
121+
122+
assert.NoError(t, err)
123+
assert.Equal(t, "ERROR\n", output.String())
124+
assert.Equal(t, "ERROR\n", output2.String())
125+
}
126+
127+
func TestSimple_with_additional_error_fork2(t *testing.T) {
128+
output := &bytes.Buffer{}
129+
130+
err := Builder().
131+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithAdditionalErrorForks(output).
132+
Finalize().Run()
133+
134+
assert.NoError(t, err)
135+
assert.Equal(t, "ERROR\n", output.String())
136+
}
137+
138+
func TestSimple_with_additional_error(t *testing.T) {
139+
output := &bytes.Buffer{}
140+
output2 := &bytes.Buffer{}
141+
142+
err := Builder().
143+
Join(testHelper, "-e", "ERROR", "-o", "TEST").
144+
Finalize().WithAdditionalError(output).WithAdditionalError(output2).Run()
145+
146+
assert.NoError(t, err)
147+
assert.Equal(t, "ERROR\n", output.String())
148+
assert.Equal(t, "ERROR\n", output2.String())
149+
}
150+
151+
func TestSimple_with_output(t *testing.T) {
152+
output := &bytes.Buffer{}
153+
output2 := &bytes.Buffer{}
154+
155+
err := Builder().
156+
Join(testHelper, "-e", "ERROR", "-o", "TEST").
157+
Finalize().WithOutput(output).WithOutput(output2).Run()
158+
159+
assert.NoError(t, err)
160+
assert.Equal(t, "", output.String(), "first output stream should be overwritten")
161+
assert.Equal(t, "TEST\n", output2.String())
162+
}
163+
164+
func TestSimple_with_additional_output_fork(t *testing.T) {
165+
output := &bytes.Buffer{}
166+
output2 := &bytes.Buffer{}
167+
168+
err := Builder().
169+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithOutputForks(output).WithAdditionalOutputForks(output2).
170+
Finalize().Run()
171+
172+
assert.NoError(t, err)
173+
assert.Equal(t, "TEST\n", output.String())
174+
assert.Equal(t, "TEST\n", output2.String())
175+
}
176+
177+
func TestSimple_with_additional_output_fork2(t *testing.T) {
178+
output := &bytes.Buffer{}
179+
180+
err := Builder().
181+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithAdditionalOutputForks(output).
182+
Finalize().Run()
183+
184+
assert.NoError(t, err)
185+
assert.Equal(t, "TEST\n", output.String())
186+
}
187+
188+
func TestSimple_with_additional_output(t *testing.T) {
189+
output := &bytes.Buffer{}
190+
output2 := &bytes.Buffer{}
191+
192+
err := Builder().
193+
Join(testHelper, "-e", "ERROR", "-o", "TEST").
194+
Finalize().WithAdditionalOutput(output).WithAdditionalOutput(output2).Run()
195+
196+
assert.NoError(t, err)
197+
assert.Equal(t, "TEST\n", output.String())
198+
assert.Equal(t, "TEST\n", output2.String())
199+
}
200+
76201
func TestSimple_multi_stdout(t *testing.T) {
77202
output1 := &bytes.Buffer{}
78203
output2 := &bytes.Buffer{}
@@ -85,6 +210,19 @@ func TestSimple_multi_stdout(t *testing.T) {
85210
assert.Equal(t, output1.String(), output2.String())
86211
}
87212

213+
func TestSimple_multi_stdout_mixed(t *testing.T) {
214+
output1 := &bytes.Buffer{}
215+
output2 := &bytes.Buffer{}
216+
217+
err := Builder().
218+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithOutputForks(output1).
219+
Finalize().WithAdditionalOutput(output2).Run()
220+
221+
assert.NoError(t, err)
222+
assert.Equal(t, "TEST\n", output1.String())
223+
assert.Equal(t, "TEST\n", output2.String())
224+
}
225+
88226
func TestSimple_multi_stderr(t *testing.T) {
89227
output1 := &bytes.Buffer{}
90228
output2 := &bytes.Buffer{}
@@ -97,6 +235,45 @@ func TestSimple_multi_stderr(t *testing.T) {
97235
assert.Equal(t, output1.String(), output2.String())
98236
}
99237

238+
func TestSimple_multi_stderr_mixed(t *testing.T) {
239+
output1 := &bytes.Buffer{}
240+
output2 := &bytes.Buffer{}
241+
242+
err := Builder().
243+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithErrorForks(output1).
244+
Finalize().WithAdditionalError(output2).Run()
245+
246+
assert.NoError(t, err)
247+
assert.Equal(t, "ERROR\n", output1.String())
248+
assert.Equal(t, "ERROR\n", output2.String())
249+
}
250+
251+
func TestSimple_withOutput_overrides_prev(t *testing.T) {
252+
output1 := &bytes.Buffer{}
253+
output2 := &bytes.Buffer{}
254+
255+
err := Builder().
256+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithOutputForks(output1).
257+
Finalize().WithOutput(output2).Run()
258+
259+
assert.NoError(t, err)
260+
assert.Equal(t, "", output1.String(), "first output stream should be overwritten")
261+
assert.Equal(t, "TEST\n", output2.String())
262+
}
263+
264+
func TestSimple_withError_overrides_prev(t *testing.T) {
265+
output1 := &bytes.Buffer{}
266+
output2 := &bytes.Buffer{}
267+
268+
err := Builder().
269+
Join(testHelper, "-e", "ERROR", "-o", "TEST").WithErrorForks(output1).
270+
Finalize().WithError(output2).Run()
271+
272+
assert.NoError(t, err)
273+
assert.Equal(t, "", output1.String(), "first output stream should be overwritten")
274+
assert.Equal(t, "ERROR\n", output2.String())
275+
}
276+
100277
func TestSimple_WithInput(t *testing.T) {
101278
toTest := Builder().
102279
WithInput(strings.NewReader("TEST\nOUTPUT")).

0 commit comments

Comments
 (0)