OLD | NEW |
(Empty) | |
| 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.Ki
nd) |
| 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, runT
ime 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 } |
OLD | NEW |