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 |