blob: a4aabd284200be6bc2646d39d0df74ea90b1b517 [file] [log] [blame]
// 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
}