@@ -2,6 +2,7 @@ package cmd
22
33import (
44 "bytes"
5+ "context"
56 "fmt"
67 "io"
78 "os"
@@ -19,6 +20,7 @@ type Command struct {
1920 StderrWriter io.Writer
2021 StdoutWriter io.Writer
2122 WorkingDir string
23+ ctx context.Context
2224 executed bool
2325 exitCode int
2426 // stderr and stdout retrieve the output after the command was executed
@@ -57,6 +59,7 @@ func NewCommand(cmd string, options ...func(*Command)) *Command {
5759 Timeout : 30 * time .Minute ,
5860 executed : false ,
5961 Env : []string {},
62+ ctx : context .Background (),
6063 }
6164
6265 c .StdoutWriter = io .MultiWriter (& c .stdout , & c .combined )
@@ -142,6 +145,12 @@ func WithEnvironmentVariables(env EnvVars) func(c *Command) {
142145 }
143146}
144147
148+ func WithContext (ctx context.Context ) func (c * Command ) {
149+ return func (c * Command ) {
150+ c .ctx = ctx
151+ }
152+ }
153+
145154// AddEnv adds an environment variable to the command
146155// If a variable gets passed like ${VAR_NAME} the env variable will be read out by the current shell
147156func (c * Command ) AddEnv (key string , value string ) {
@@ -195,9 +204,10 @@ func (c *Command) Execute() error {
195204 cmd .Dir = c .WorkingDir
196205
197206 // Create timer only if timeout was set > 0
198- var timeoutChan = make (<- chan time.Time , 1 )
199207 if c .Timeout != 0 {
200- timeoutChan = time .After (c .Timeout )
208+ ctx , cancel := context .WithTimeout (c .ctx , c .Timeout )
209+ defer cancel ()
210+ c .ctx = ctx
201211 }
202212
203213 err := cmd .Start ()
@@ -206,35 +216,25 @@ func (c *Command) Execute() error {
206216 }
207217
208218 done := make (chan error , 1 )
209- quit := make (chan bool , 1 )
210- defer close (quit )
211-
212219 go func () {
213220 select {
214- case <- quit :
215- return
216221 case done <- cmd .Wait ():
217222 return
218223 }
219224 }()
220225
221226 select {
222- case err := <- done :
223- if err != nil {
224- c .getExitCode (err )
225- break
226- }
227- c .exitCode = 0
228- case <- timeoutChan :
229- quit <- true
227+ case <- c .ctx .Done ():
230228 if err := cmd .Process .Kill (); err != nil {
231229 return fmt .Errorf ("Timeout occurred and can not kill process with pid %v" , cmd .Process .Pid )
232230 }
233231 return fmt .Errorf ("Command timed out after %v" , c .Timeout )
232+ case err := <- done :
233+ if err != nil {
234+ c .getExitCode (err )
235+ }
234236 }
235-
236237 c .executed = true
237-
238238 return nil
239239}
240240
0 commit comments