@@ -83,8 +83,8 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) error {
83
83
}
84
84
85
85
copyCtx , copyCancel := context .WithTimeout (ctx , time .Duration (copyTimeout ))
86
+ defer copyCancel ()
86
87
matched , err := copyContext (copyCtx , copyOutput , conn , r .cfg .ExpectOutput )
87
- copyCancel ()
88
88
if r .cfg .ExpectTimeout {
89
89
if err == nil {
90
90
return xerrors .Errorf ("expected timeout, but the command exited successfully" )
@@ -107,11 +107,27 @@ func copyContext(ctx context.Context, dst io.Writer, src io.Reader, expectOutput
107
107
copyErr = make (chan error )
108
108
matched = expectOutput == ""
109
109
)
110
+
111
+ // Guard goroutine for loop body to ensure reading `matched` is safe on
112
+ // context cancellation and that `dst` won't be written to after we
113
+ // return from this function.
114
+ processing := make (chan struct {}, 1 )
115
+ processing <- struct {}{}
116
+
110
117
go func () {
118
+ defer close (processing )
111
119
defer close (copyErr )
112
120
113
121
scanner := bufio .NewScanner (src )
114
122
for scanner .Scan () {
123
+ select {
124
+ case <- processing :
125
+ default :
126
+ }
127
+ if ctx .Err () != nil {
128
+ return
129
+ }
130
+
115
131
if expectOutput != "" && strings .Contains (scanner .Text (), expectOutput ) {
116
132
matched = true
117
133
}
@@ -121,6 +137,7 @@ func copyContext(ctx context.Context, dst io.Writer, src io.Reader, expectOutput
121
137
copyErr <- xerrors .Errorf ("write to logs: %w" , err )
122
138
return
123
139
}
140
+ processing <- struct {}{}
124
141
}
125
142
if scanner .Err () != nil {
126
143
copyErr <- xerrors .Errorf ("read from reconnecting PTY: %w" , scanner .Err ())
@@ -130,6 +147,10 @@ func copyContext(ctx context.Context, dst io.Writer, src io.Reader, expectOutput
130
147
131
148
select {
132
149
case <- ctx .Done ():
150
+ select {
151
+ case <- processing :
152
+ case <- copyErr :
153
+ }
133
154
return matched , ctx .Err ()
134
155
case err := <- copyErr :
135
156
return matched , err
0 commit comments