]> Cypherpunks repositories - gostls13.git/commitdiff
misc/dashboard/builder: record build result on dashboard
authorDave Cheney <dave@cheney.net>
Thu, 14 Feb 2013 23:44:29 +0000 (10:44 +1100)
committerDave Cheney <dave@cheney.net>
Thu, 14 Feb 2013 23:44:29 +0000 (10:44 +1100)
This is part one of two changes intended to make it easier to debug builder failures.

runOutput allows us to control the io.Writer passed to a subcommand. The intention is to add additional debugging information before and after the build which will then be capture and sent to the dashboard.

In this proposal, the only additional information is the build status. See http://build.golang.org/log/e7b5bf435b4de1913fc61781b3295fb3f03aeb6e

R=adg
CC=golang-dev
https://golang.org/cl/7303090

misc/dashboard/builder/exec.go
misc/dashboard/builder/main.go

index bf5c28d47d70350227d7e8b00338e66049664fce..a4aabd284200be6bc2646d39d0df74ea90b1b517 100644 (file)
@@ -29,42 +29,38 @@ func run(timeout time.Duration, envv []string, dir string, argv ...string) error
        return waitWithTimeout(timeout, cmd)
 }
 
-// runLog runs a process and returns the combined stdout/stderr,
-// as well as writing it to logfile (if specified). 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, logfile, dir string, argv ...string) (string, int, error) {
-       if *verbose {
-               log.Println("runLog", argv)
-       }
+// 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
+}
 
-       b := new(bytes.Buffer)
-       var w io.Writer = b
-       if logfile != "" {
-               f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
-               if err != nil {
-                       return "", 0, err
-               }
-               defer f.Close()
-               w = io.MultiWriter(f, b)
+// 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 = w
-       cmd.Stderr = w
+       cmd.Stdout = out
+       cmd.Stderr = out
 
        startErr := cmd.Start()
        if startErr != nil {
-               return "", 1, startErr
+               return false, startErr
        }
-       exitStatus := 0
        if err := waitWithTimeout(timeout, cmd); err != nil {
-               exitStatus = 1 // TODO(bradfitz): this is fake. no callers care, so just return a bool instead.
+               return false, err
        }
-       return b.String(), exitStatus, nil
+       return true, nil
 }
 
 func waitWithTimeout(timeout time.Duration, cmd *exec.Cmd) error {
index 4b237ba81a63d77794cae3c95735e75b2a885ed9..b1f5571b0f148d1e8bc91cbbc0764cbb4aec02e7 100644 (file)
@@ -9,6 +9,7 @@ import (
        "encoding/xml"
        "flag"
        "fmt"
+       "io"
        "io/ioutil"
        "log"
        "os"
@@ -272,21 +273,36 @@ func (b *Builder) buildHash(hash string) error {
        srcDir := filepath.Join(workpath, "go", "src")
 
        // build
+       var buildlog bytes.Buffer
        logfile := filepath.Join(workpath, "build.log")
+       f, err := os.Create(logfile)
+       if err != nil {
+               return err
+       }
+       defer f.Close()
+       w := io.MultiWriter(f, &buildlog)
+
        cmd := *buildCmd
        if !filepath.IsAbs(cmd) {
                cmd = filepath.Join(srcDir, cmd)
        }
        startTime := time.Now()
-       buildLog, status, err := runLog(*buildTimeout, b.envv(), logfile, srcDir, cmd)
+       ok, err := runOutput(*buildTimeout, b.envv(), w, srcDir, cmd)
        runTime := time.Now().Sub(startTime)
-       if err != nil {
-               return fmt.Errorf("%s: %s", *buildCmd, err)
+       errf := func() string {
+               if err != nil {
+                       return fmt.Sprintf("error: %v", err)
+               }
+               if !ok {
+                       return "failed"
+               }
+               return "success"
        }
+       fmt.Fprintf(w, "Build complete, duration %v. Result: %v\n", runTime, errf())
 
-       if status != 0 {
+       if err != nil || !ok {
                // record failure
-               return b.recordResult(false, "", hash, "", buildLog, runTime)
+               return b.recordResult(false, "", hash, "", buildlog.String(), runTime)
        }
 
        // record success
@@ -372,9 +388,9 @@ func (b *Builder) buildSubrepo(goRoot, goPath, pkg, hash string) (string, error)
        }
 
        // fetch package and dependencies
-       log, status, err := runLog(*cmdTimeout, env, "", goPath, goTool, "get", "-d", pkg+"/...")
-       if err == nil && status != 0 {
-               err = fmt.Errorf("go exited with status %d", status)
+       log, ok, err := runLog(*cmdTimeout, env, goPath, goTool, "get", "-d", pkg+"/...")
+       if err == nil && !ok {
+               err = fmt.Errorf("go exited with status 1")
        }
        if err != nil {
                return log, err
@@ -387,9 +403,9 @@ func (b *Builder) buildSubrepo(goRoot, goPath, pkg, hash string) (string, error)
        }
 
        // test the package
-       log, status, err = runLog(*buildTimeout, env, "", goPath, goTool, "test", "-short", pkg+"/...")
-       if err == nil && status != 0 {
-               err = fmt.Errorf("go exited with status %d", status)
+       log, ok, err = runLog(*buildTimeout, env, goPath, goTool, "test", "-short", pkg+"/...")
+       if err == nil && !ok {
+               err = fmt.Errorf("go exited with status 1")
        }
        return log, err
 }
@@ -571,7 +587,7 @@ func commitPoll(key, pkg string) {
        const N = 50 // how many revisions to grab
 
        lockGoroot()
-       data, _, err := runLog(*cmdTimeout, nil, "", pkgRoot, hgCmd("log",
+       data, _, err := runLog(*cmdTimeout, nil, pkgRoot, hgCmd("log",
                "--encoding=utf-8",
                "--limit="+strconv.Itoa(N),
                "--template="+xmlLogTemplate)...,
@@ -663,7 +679,7 @@ func fullHash(root, rev string) (string, error) {
        if root == goroot {
                gorootMu.Lock()
        }
-       s, _, err := runLog(*cmdTimeout, nil, "", root,
+       s, _, err := runLog(*cmdTimeout, nil, root,
                hgCmd("log",
                        "--encoding=utf-8",
                        "--rev="+rev,