github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/misc/dashboard/builder/exec.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "log" 12 "os" 13 "os/exec" 14 "time" 15 ) 16 17 // run is a simple wrapper for exec.Run/Close 18 func run(timeout time.Duration, envv []string, dir string, argv ...string) error { 19 if *verbose { 20 log.Println("run", argv) 21 } 22 cmd := exec.Command(argv[0], argv[1:]...) 23 cmd.Dir = dir 24 cmd.Env = envv 25 cmd.Stderr = os.Stderr 26 if err := cmd.Start(); err != nil { 27 return err 28 } 29 return waitWithTimeout(timeout, cmd) 30 } 31 32 // runLog runs a process and returns the combined stdout/stderr. It returns 33 // process combined stdout and stderr output, exit status and error. The 34 // error returned is nil, if process is started successfully, even if exit 35 // status is not successful. 36 func runLog(timeout time.Duration, envv []string, dir string, argv ...string) (string, bool, error) { 37 var b bytes.Buffer 38 ok, err := runOutput(timeout, envv, &b, dir, argv...) 39 return b.String(), ok, err 40 } 41 42 // runOutput runs a process and directs any output to the supplied writer. 43 // It returns exit status and error. The error returned is nil, if process 44 // is started successfully, even if exit status is not successful. 45 func runOutput(timeout time.Duration, envv []string, out io.Writer, dir string, argv ...string) (bool, error) { 46 if *verbose { 47 log.Println("runOutput", argv) 48 } 49 50 cmd := exec.Command(argv[0], argv[1:]...) 51 cmd.Dir = dir 52 cmd.Env = envv 53 cmd.Stdout = out 54 cmd.Stderr = out 55 56 startErr := cmd.Start() 57 if startErr != nil { 58 return false, startErr 59 } 60 if err := waitWithTimeout(timeout, cmd); err != nil { 61 return false, err 62 } 63 return true, nil 64 } 65 66 func waitWithTimeout(timeout time.Duration, cmd *exec.Cmd) error { 67 errc := make(chan error, 1) 68 go func() { 69 errc <- cmd.Wait() 70 }() 71 var err error 72 select { 73 case <-time.After(timeout): 74 cmd.Process.Kill() 75 err = fmt.Errorf("timed out after %v", timeout) 76 case err = <-errc: 77 } 78 return err 79 }