Skip to content

Commit c29599b

Browse files
committed
Improve cmd
1 parent e23d428 commit c29599b

File tree

2 files changed

+26
-42
lines changed

2 files changed

+26
-42
lines changed

dep/cmd/cmd.go

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"bufio"
5+
"context"
56
"errors"
67
"fmt"
78
"net/http"
@@ -32,7 +33,7 @@ const (
3233

3334
type Cmd struct {
3435
opts []Opt
35-
ready func(*exec.Cmd) error
36+
ready func(context.Context, *exec.Cmd) error
3637
stop func(*exec.Cmd) error
3738
cmd *exec.Cmd
3839
readyTimeout time.Duration
@@ -43,7 +44,7 @@ type Opt func(*Cmd) error
4344
func New(opts ...Opt) *Cmd {
4445
return &Cmd{
4546
opts: opts,
46-
ready: func(*exec.Cmd) error { return nil },
47+
ready: func(context.Context, *exec.Cmd) error { return nil },
4748
stop: StopWithSignal(os.Interrupt),
4849
readyTimeout: 30 * time.Second,
4950
}
@@ -64,10 +65,13 @@ func (c *Cmd) Start() error {
6465
}
6566

6667
func (c *Cmd) Ready() error {
68+
ctx, cancel := context.WithTimeout(context.Background(), c.readyTimeout)
69+
defer cancel()
70+
6771
errCh := make(chan error, 1)
6872
go func() {
6973
defer close(errCh)
70-
errCh <- c.ready(c.cmd)
74+
errCh <- c.ready(ctx, c.cmd)
7175
}()
7276

7377
select {
@@ -93,13 +97,15 @@ func (c *Cmd) wrapErr(wErr, err error) error {
9397
func WithCommand(name string, args ...string) Opt {
9498
return func(c *Cmd) error {
9599
c.cmd = exec.Command(name, args...)
100+
c.cmd.Stdout = os.Stdout
101+
c.cmd.Stderr = os.Stderr
96102
return nil
97103
}
98104
}
99105

100106
// WithReadyFn allows user to provide custom readiness function.
101107
// Given fn should block until the command is ready.
102-
func WithReadyFn(fn func(*exec.Cmd) error) Opt {
108+
func WithReadyFn(fn func(context.Context, *exec.Cmd) error) Opt {
103109
return func(c *Cmd) error {
104110
c.ready = fn
105111
return nil
@@ -109,19 +115,20 @@ func WithReadyFn(fn func(*exec.Cmd) error) Opt {
109115
// WithReadyHTTP sets the ready function to wait for url to return 200 OK.
110116
func WithReadyHTTP(url string) Opt {
111117
return func(c *Cmd) error {
112-
c.ready = func(cmd *exec.Cmd) error {
118+
c.ready = func(ctx context.Context, cmd *exec.Cmd) error {
113119
client := &http.Client{
114-
Timeout: 10 * time.Second,
120+
Timeout: 1 * time.Second,
115121
}
116122
for {
123+
if ctx.Err() != nil {
124+
return ctx.Err()
125+
}
117126
resp, err := client.Get(url)
118-
if err != nil {
127+
if err != nil || resp.StatusCode != http.StatusOK {
128+
time.Sleep(time.Millisecond * 100)
119129
continue
120130
}
121-
if resp.StatusCode == http.StatusOK {
122-
return nil
123-
}
124-
time.Sleep(100 * time.Millisecond)
131+
return nil
125132
}
126133
}
127134
return nil
@@ -201,7 +208,7 @@ func WithReadyTimeout(d time.Duration) Opt {
201208
// This is useful for commands that exit on their own and don't need to be stopped manually.
202209
func WithWaitExit() Opt {
203210
return func(c *Cmd) error {
204-
c.ready = func(cmd *exec.Cmd) error { return cmd.Wait() }
211+
c.ready = func(_ context.Context, cmd *exec.Cmd) error { return cmd.Wait() }
205212
c.stop = func(*exec.Cmd) error { return nil }
206213
return nil
207214
}
@@ -215,17 +222,6 @@ func WithExecCmd(cmd *exec.Cmd) Opt {
215222
}
216223
}
217224

218-
// WithPreCmd runs the given command as part of the setup.
219-
// This can be used to prepare the actual main command.
220-
func WithPreCmd(cmd *exec.Cmd) Opt {
221-
return func(c *Cmd) error {
222-
if err := cmd.Run(); err != nil {
223-
return fmt.Errorf("%w: %w", ErrPreCmdFailed, err)
224-
}
225-
return nil
226-
}
227-
}
228-
229225
// WithGoCode builds the given Go projects and sets the main package as the command.
230226
// By default the the output binary is instrumented to collect coverage data
231227
// Working directory for build command is set to modulePath which means that the mainPkg should be relative to it.
@@ -304,7 +300,7 @@ func StopWithSignal(s os.Signal) func(*exec.Cmd) error {
304300
}
305301

306302
// MatchLine waits for the command to output a line that matches the given regular expression.
307-
func MatchingLine(exp string, cmd *exec.Cmd) (func(*exec.Cmd) error, error) {
303+
func MatchingLine(exp string, cmd *exec.Cmd) (func(context.Context, *exec.Cmd) error, error) {
308304
if cmd == nil {
309305
return nil, ErrNilCmdRegexp
310306
}
@@ -320,7 +316,7 @@ func MatchingLine(exp string, cmd *exec.Cmd) (func(*exec.Cmd) error, error) {
320316
return nil, fmt.Errorf("%w: %w", ErrOutputPipe, err)
321317
}
322318

323-
return func(cmd *exec.Cmd) error {
319+
return func(ctx context.Context, cmd *exec.Cmd) error {
324320
scanner := bufio.NewScanner(stdout)
325321
for scanner.Scan() {
326322
if re.Match(scanner.Bytes()) {
@@ -331,6 +327,9 @@ func MatchingLine(exp string, cmd *exec.Cmd) (func(*exec.Cmd) error, error) {
331327
}()
332328
return nil
333329
}
330+
if ctx.Err() != nil {
331+
return ctx.Err()
332+
}
334333
}
335334
return errors.Join(ErrNoMatchingLine, scanner.Err())
336335
}, nil

dep/cmd/cmd_test.go

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd_test
22

33
import (
4+
"context"
45
"net/http"
56
"net/http/httptest"
67
"os"
@@ -83,14 +84,6 @@ func TestCmd(t *testing.T) {
8384
),
8485
err: cmd.ErrNilCmdRegexp,
8586
},
86-
{
87-
name: "WithBuildCmd_error",
88-
cmd: cmd.New(
89-
cmd.WithPreCmd(exec.Command("go", "build", "non/existing/path/main.go")),
90-
cmd.WithCommand("non/existing/path/main"),
91-
),
92-
err: cmd.ErrPreCmdFailed,
93-
},
9487
{
9588
name: "WithEnv",
9689
cmd: cmd.New(
@@ -116,14 +109,6 @@ func TestCmd(t *testing.T) {
116109
cmd.WithWaitExit(),
117110
),
118111
},
119-
{
120-
name: "WithBuildCmd",
121-
cmd: cmd.New(
122-
cmd.WithPreCmd(exec.Command("go", "build", "-o", waitBin, waitPkg+"/main.go")),
123-
cmd.WithCommand(waitBin),
124-
cmd.WithWaitMatchingLine("Waiting for signal"),
125-
),
126-
},
127112
{
128113
name: "DefaultReady",
129114
cmd: cmd.New(
@@ -202,7 +187,7 @@ func TestCmd_WithGoCode_Coverage(t *testing.T) {
202187
require.Len(t, files, 2)
203188
}
204189

205-
func blockForever(*exec.Cmd) error {
190+
func blockForever(context.Context, *exec.Cmd) error {
206191
select {}
207192
}
208193

0 commit comments

Comments
 (0)