github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/misc/dashboard/builder/http.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  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"log"
    14  	"net/http"
    15  	"net/url"
    16  	"time"
    17  )
    18  
    19  type obj map[string]interface{}
    20  
    21  // dash runs the given method and command on the dashboard.
    22  // If args is non-nil it is encoded as the URL query string.
    23  // If req is non-nil it is JSON-encoded and passed as the body of the HTTP POST.
    24  // If resp is non-nil the server's response is decoded into the value pointed
    25  // to by resp (resp must be a pointer).
    26  func dash(meth, cmd string, args url.Values, req, resp interface{}) error {
    27  	var r *http.Response
    28  	var err error
    29  	if *verbose {
    30  		log.Println("dash", meth, cmd, args, req)
    31  	}
    32  	cmd = "http://" + *dashboard + "/" + cmd
    33  	if len(args) > 0 {
    34  		cmd += "?" + args.Encode()
    35  	}
    36  	switch meth {
    37  	case "GET":
    38  		if req != nil {
    39  			log.Panicf("%s to %s with req", meth, cmd)
    40  		}
    41  		r, err = http.Get(cmd)
    42  	case "POST":
    43  		var body io.Reader
    44  		if req != nil {
    45  			b, err := json.Marshal(req)
    46  			if err != nil {
    47  				return err
    48  			}
    49  			body = bytes.NewBuffer(b)
    50  		}
    51  		r, err = http.Post(cmd, "text/json", body)
    52  	default:
    53  		log.Panicf("%s: invalid method %q", cmd, meth)
    54  		panic("invalid method: " + meth)
    55  	}
    56  	if err != nil {
    57  		return err
    58  	}
    59  	defer r.Body.Close()
    60  	if r.StatusCode != http.StatusOK {
    61  		return fmt.Errorf("bad http response: %v", r.Status)
    62  	}
    63  	body := new(bytes.Buffer)
    64  	if _, err := body.ReadFrom(r.Body); err != nil {
    65  		return err
    66  	}
    67  
    68  	// Read JSON-encoded Response into provided resp
    69  	// and return an error if present.
    70  	var result = struct {
    71  		Response interface{}
    72  		Error    string
    73  	}{
    74  		// Put the provided resp in here as it can be a pointer to
    75  		// some value we should unmarshal into.
    76  		Response: resp,
    77  	}
    78  	if err = json.Unmarshal(body.Bytes(), &result); err != nil {
    79  		log.Printf("json unmarshal %#q: %s\n", body.Bytes(), err)
    80  		return err
    81  	}
    82  	if result.Error != "" {
    83  		return errors.New(result.Error)
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  // todo returns the next hash to build.
    90  func (b *Builder) todo(kind, pkg, goHash string) (rev string, err error) {
    91  	args := url.Values{
    92  		"kind":        {kind},
    93  		"builder":     {b.name},
    94  		"packagePath": {pkg},
    95  		"goHash":      {goHash},
    96  	}
    97  	var resp *struct {
    98  		Kind string
    99  		Data struct {
   100  			Hash string
   101  		}
   102  	}
   103  	if err = dash("GET", "todo", args, nil, &resp); err != nil {
   104  		return "", err
   105  	}
   106  	if resp == nil {
   107  		return "", nil
   108  	}
   109  	if kind != resp.Kind {
   110  		return "", fmt.Errorf("expecting Kind %q, got %q", kind, resp.Kind)
   111  	}
   112  	return resp.Data.Hash, nil
   113  }
   114  
   115  // recordResult sends build results to the dashboard
   116  func (b *Builder) recordResult(ok bool, pkg, hash, goHash, buildLog string, runTime time.Duration) error {
   117  	req := obj{
   118  		"Builder":     b.name,
   119  		"PackagePath": pkg,
   120  		"Hash":        hash,
   121  		"GoHash":      goHash,
   122  		"OK":          ok,
   123  		"Log":         buildLog,
   124  		"RunTime":     runTime,
   125  	}
   126  	args := url.Values{"key": {b.key}, "builder": {b.name}}
   127  	return dash("POST", "result", args, req, nil)
   128  }
   129  
   130  func postCommit(key, pkg string, l *HgLog) error {
   131  	t, err := time.Parse(time.RFC3339, l.Date)
   132  	if err != nil {
   133  		return fmt.Errorf("parsing %q: %v", l.Date, t)
   134  	}
   135  	return dash("POST", "commit", url.Values{"key": {key}}, obj{
   136  		"PackagePath": pkg,
   137  		"Hash":        l.Hash,
   138  		"ParentHash":  l.Parent,
   139  		"Time":        t.Format(time.RFC3339),
   140  		"User":        l.Author,
   141  		"Desc":        l.Desc,
   142  	}, nil)
   143  }
   144  
   145  func dashboardCommit(pkg, hash string) bool {
   146  	err := dash("GET", "commit", url.Values{
   147  		"packagePath": {pkg},
   148  		"hash":        {hash},
   149  	}, nil, nil)
   150  	return err == nil
   151  }
   152  
   153  func dashboardPackages(kind string) []string {
   154  	args := url.Values{"kind": []string{kind}}
   155  	var resp []struct {
   156  		Path string
   157  	}
   158  	if err := dash("GET", "packages", args, nil, &resp); err != nil {
   159  		log.Println("dashboardPackages:", err)
   160  		return nil
   161  	}
   162  	var pkgs []string
   163  	for _, r := range resp {
   164  		pkgs = append(pkgs, r.Path)
   165  	}
   166  	return pkgs
   167  }