1
0
mirror of https://github.com/golang/go synced 2024-11-07 07:36:14 -07:00
go/dashboard/builder/exec.go
Chris Manghane 1d214a6a09 go.tools/dashboard: implement dashboard using vcs package.
To make the dashboard more flexible with different VCS, the Repo now depends on the VCS package for running commands.

* Exported Repo.Master
* Modified RemoteRepo to return a repo and an error
* Reimplemented all Repo methods using vcs package
* Removed hgCmd
* Removed repoURL
* Removed scheme from hgUrl since vcs.RepoRootForImportPath decides the scheme.
* Changed waitWithTimeout into timeout
* Added waitForFuncWithTimeout to wrap vcs commands with a timeout.

R=adg
CC=golang-dev
https://golang.org/cl/13201043
2013-08-27 21:52:18 -07:00

105 lines
2.5 KiB
Go

// 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(d 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 timeout(d, func() error {
if err := cmd.Wait(); err != nil {
if _, ok := err.(TimeoutErr); ok {
cmd.Process.Kill()
}
return err
}
return nil
})
}
// 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(d 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 := timeout(d, func() error {
if err := cmd.Wait(); err != nil {
if _, ok := err.(TimeoutErr); ok {
cmd.Process.Kill()
}
return err
}
return nil
}); err != nil {
return false, err
}
return true, nil
}
// timeout runs f and returns its error value, or if the function does not
// complete before the provided duration it returns a timeout error.
func timeout(d time.Duration, f func() error) error {
errc := make(chan error)
go func() {
errc <- f()
}()
t := time.NewTimer(d)
defer t.Stop()
select {
case <-t.C:
return fmt.Errorf("timed out after %v", d)
case err := <-errc:
return err
}
}
type TimeoutErr time.Duration
func (e TimeoutErr) Error() string {
return fmt.Sprintf("timed out after %v", time.Duration(e))
}