| Index: dashboard/builder/exec.go |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/dashboard/builder/exec.go |
| @@ -0,0 +1,79 @@ |
| +// Copyright 2011 The Go Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style |
| +// license that can be found in the LICENSE file. |
| + |
| +package main |
| + |
| +import ( |
| + "bytes" |
| + "fmt" |
| + "io" |
| + "log" |
| + "os" |
| + "os/exec" |
| + "time" |
| +) |
| + |
| +// run is a simple wrapper for exec.Run/Close |
| +func run(timeout time.Duration, envv []string, dir string, argv ...string) error { |
| + if *verbose { |
| + log.Println("run", argv) |
| + } |
| + cmd := exec.Command(argv[0], argv[1:]...) |
| + cmd.Dir = dir |
| + cmd.Env = envv |
| + cmd.Stderr = os.Stderr |
| + if err := cmd.Start(); err != nil { |
| + return err |
| + } |
| + return waitWithTimeout(timeout, cmd) |
| +} |
| + |
| +// runLog runs a process and returns the combined stdout/stderr. It returns |
| +// process combined stdout and stderr output, exit status and error. The |
| +// error returned is nil, if process is started successfully, even if exit |
| +// status is not successful. |
| +func runLog(timeout time.Duration, envv []string, dir string, argv ...string) (string, bool, error) { |
| + var b bytes.Buffer |
| + ok, err := runOutput(timeout, envv, &b, dir, argv...) |
| + return b.String(), ok, err |
| +} |
| + |
| +// runOutput runs a process and directs any output to the supplied writer. |
| +// It returns exit status and error. The error returned is nil, if process |
| +// is started successfully, even if exit status is not successful. |
| +func runOutput(timeout time.Duration, envv []string, out io.Writer, dir string, argv ...string) (bool, error) { |
| + if *verbose { |
| + log.Println("runOutput", argv) |
| + } |
| + |
| + cmd := exec.Command(argv[0], argv[1:]...) |
| + cmd.Dir = dir |
| + cmd.Env = envv |
| + cmd.Stdout = out |
| + cmd.Stderr = out |
| + |
| + startErr := cmd.Start() |
| + if startErr != nil { |
| + return false, startErr |
| + } |
| + if err := waitWithTimeout(timeout, cmd); err != nil { |
| + return false, err |
| + } |
| + return true, nil |
| +} |
| + |
| +func waitWithTimeout(timeout time.Duration, cmd *exec.Cmd) error { |
| + errc := make(chan error, 1) |
| + go func() { |
| + errc <- cmd.Wait() |
| + }() |
| + var err error |
| + select { |
| + case <-time.After(timeout): |
| + cmd.Process.Kill() |
| + err = fmt.Errorf("timed out after %v", timeout) |
| + case err = <-errc: |
| + } |
| + return err |
| +} |