| OLD | NEW |
| 1 package main | 1 package main |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "encoding/json" | 4 "encoding/json" |
| 5 "fmt" | 5 "fmt" |
| 6 "html/template" | 6 "html/template" |
| 7 "net/http" | 7 "net/http" |
| 8 "net/url" | 8 "net/url" |
| 9 "path/filepath" | 9 "path/filepath" |
| 10 "regexp" | 10 "regexp" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 MAX_PAGE_SIZE = 100 | 40 MAX_PAGE_SIZE = 100 |
| 41 ) | 41 ) |
| 42 | 42 |
| 43 var ( | 43 var ( |
| 44 templates *template.Template | 44 templates *template.Template |
| 45 ) | 45 ) |
| 46 | 46 |
| 47 func loadTemplates() { | 47 func loadTemplates() { |
| 48 templates = template.Must(template.New("").Delims("{%", "%}").ParseFiles
( | 48 templates = template.Must(template.New("").Delims("{%", "%}").ParseFiles
( |
| 49 filepath.Join(*resourcesDir, "templates/byblame.html"), | 49 filepath.Join(*resourcesDir, "templates/byblame.html"), |
| 50 filepath.Join(*resourcesDir, "templates/cluster.html"), |
| 50 filepath.Join(*resourcesDir, "templates/index.html"), | 51 filepath.Join(*resourcesDir, "templates/index.html"), |
| 51 filepath.Join(*resourcesDir, "templates/ignores.html"), | 52 filepath.Join(*resourcesDir, "templates/ignores.html"), |
| 52 filepath.Join(*resourcesDir, "templates/compare.html"), | 53 filepath.Join(*resourcesDir, "templates/compare.html"), |
| 53 filepath.Join(*resourcesDir, "templates/single.html"), | 54 filepath.Join(*resourcesDir, "templates/single.html"), |
| 54 filepath.Join(*resourcesDir, "templates/diff.html"), | 55 filepath.Join(*resourcesDir, "templates/diff.html"), |
| 55 filepath.Join(*resourcesDir, "templates/help.html"), | 56 filepath.Join(*resourcesDir, "templates/help.html"), |
| 56 filepath.Join(*resourcesDir, "templates/triagelog.html"), | 57 filepath.Join(*resourcesDir, "templates/triagelog.html"), |
| 57 filepath.Join(*resourcesDir, "templates/search.html"), | 58 filepath.Join(*resourcesDir, "templates/search.html"), |
| 58 filepath.Join(*resourcesDir, "templates/search2.html"), | 59 filepath.Join(*resourcesDir, "templates/search2.html"), |
| 59 // Sub templates used by other templates. | 60 // Sub templates used by other templates. |
| (...skipping 1153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 Pos: r.FormValue("pos") == "true", | 1214 Pos: r.FormValue("pos") == "true", |
| 1214 Neg: r.FormValue("neg") == "true", | 1215 Neg: r.FormValue("neg") == "true", |
| 1215 Unt: r.FormValue("unt") == "true", | 1216 Unt: r.FormValue("unt") == "true", |
| 1216 Head: r.FormValue("head") == "true", | 1217 Head: r.FormValue("head") == "true", |
| 1217 IncludeIgnores: r.FormValue("include") == "true", | 1218 IncludeIgnores: r.FormValue("include") == "true", |
| 1218 Query: r.FormValue("query"), | 1219 Query: r.FormValue("query"), |
| 1219 Limit: Limit, | 1220 Limit: Limit, |
| 1220 } | 1221 } |
| 1221 } | 1222 } |
| 1222 | 1223 |
| 1224 // Node represents a single node in a d3 diagram. Used in D3. |
| 1225 type Node struct { |
| 1226 Name string `json:"name"` |
| 1227 Status string `json:"status"` |
| 1228 } |
| 1229 |
| 1230 // Link represents a link between d3 nodes, used in D3. |
| 1231 type Link struct { |
| 1232 Source int `json:"source"` |
| 1233 Target int `json:"target"` |
| 1234 Value float32 `json:"value"` |
| 1235 } |
| 1236 |
| 1237 // D3 represents the data structure to pass to a d3 force layout object. |
| 1238 type D3 struct { |
| 1239 Nodes []Node `json:"nodes"` |
| 1240 Links []Link `json:"links"` |
| 1241 |
| 1242 // map [digest] paramset |
| 1243 Paramsets map[string]map[string][]string `json:"paramsets"` |
| 1244 } |
| 1245 |
| 1246 // nxnJSONHandler calculates the NxN diffs of all the digests that match |
| 1247 // the incoming query and returns the data in a format appropriate for |
| 1248 // handling in d3. |
| 1249 func nxnJSONHandler(w http.ResponseWriter, r *http.Request) { |
| 1250 w.Header().Set("Content-Type", "application/json") |
| 1251 test := r.FormValue("test") |
| 1252 |
| 1253 e, err := storages.ExpectationsStore.Get() |
| 1254 if err != nil { |
| 1255 util.ReportError(w, r, err, "Failed to get expectations.") |
| 1256 } |
| 1257 |
| 1258 var t *tally.Tally |
| 1259 var ok bool |
| 1260 if t, ok = tallies.ByTest()[test]; !ok { |
| 1261 util.ReportError(w, r, fmt.Errorf("Not a valid test name: %s", t
est), "Not a valid test name.") |
| 1262 } |
| 1263 |
| 1264 digests := []string{} |
| 1265 for digest, _ := range *t { |
| 1266 digests = append(digests, digest) |
| 1267 } |
| 1268 |
| 1269 digestIndex := map[string]int{} |
| 1270 for i, d := range digests { |
| 1271 digestIndex[d] = i |
| 1272 } |
| 1273 |
| 1274 d3 := D3{ |
| 1275 Nodes: []Node{}, |
| 1276 Links: []Link{}, |
| 1277 Paramsets: map[string]map[string][]string{}, |
| 1278 } |
| 1279 for i, d := range digests { |
| 1280 d3.Nodes = append(d3.Nodes, Node{ |
| 1281 Name: d, |
| 1282 Status: e.Classification(test, d).String(), |
| 1283 }) |
| 1284 remaining := digests[i:len(digests)] |
| 1285 diffs, err := storages.DiffStore.Get(d, remaining) |
| 1286 if err != nil { |
| 1287 glog.Errorf("Failed to calculate differences: %s", err) |
| 1288 continue |
| 1289 } |
| 1290 for otherDigest, diff := range diffs { |
| 1291 d3.Links = append(d3.Links, Link{ |
| 1292 Source: digestIndex[d], |
| 1293 Target: digestIndex[otherDigest], |
| 1294 Value: diff.PixelDiffPercent, |
| 1295 }) |
| 1296 } |
| 1297 d3.Paramsets[d] = paramsetSum.Get(test, d, false) |
| 1298 } |
| 1299 |
| 1300 sendJsonResponse(w, d3) |
| 1301 } |
| 1302 |
| 1223 // sendJsonResponse serializes resp to JSON. If an error occurs | 1303 // sendJsonResponse serializes resp to JSON. If an error occurs |
| 1224 // a text based error code is send to the client. | 1304 // a text based error code is send to the client. |
| 1225 func sendJsonResponse(w http.ResponseWriter, resp interface{}) { | 1305 func sendJsonResponse(w http.ResponseWriter, resp interface{}) { |
| 1226 w.Header().Set("Content-Type", "application/json") | 1306 w.Header().Set("Content-Type", "application/json") |
| 1227 if err := json.NewEncoder(w).Encode(resp); err != nil { | 1307 if err := json.NewEncoder(w).Encode(resp); err != nil { |
| 1228 glog.Errorf("Failed to write or encode result: %s", err) | 1308 glog.Errorf("Failed to write or encode result: %s", err) |
| 1229 } | 1309 } |
| 1230 } | 1310 } |
| 1231 | 1311 |
| 1232 // makeResourceHandler creates a static file handler that sets a caching policy. | 1312 // makeResourceHandler creates a static file handler that sets a caching policy. |
| 1233 func makeResourceHandler() func(http.ResponseWriter, *http.Request) { | 1313 func makeResourceHandler() func(http.ResponseWriter, *http.Request) { |
| 1234 fileServer := http.FileServer(http.Dir(*resourcesDir)) | 1314 fileServer := http.FileServer(http.Dir(*resourcesDir)) |
| 1235 return func(w http.ResponseWriter, r *http.Request) { | 1315 return func(w http.ResponseWriter, r *http.Request) { |
| 1236 w.Header().Add("Cache-Control", string(300)) | 1316 w.Header().Add("Cache-Control", string(300)) |
| 1237 fileServer.ServeHTTP(w, r) | 1317 fileServer.ServeHTTP(w, r) |
| 1238 } | 1318 } |
| 1239 } | 1319 } |
| 1240 | 1320 |
| 1241 // Init figures out where the resources are and then loads the templates. | 1321 // Init figures out where the resources are and then loads the templates. |
| 1242 func Init() { | 1322 func Init() { |
| 1243 if *resourcesDir == "" { | 1323 if *resourcesDir == "" { |
| 1244 _, filename, _, _ := runtime.Caller(0) | 1324 _, filename, _, _ := runtime.Caller(0) |
| 1245 *resourcesDir = filepath.Join(filepath.Dir(filename), "../..") | 1325 *resourcesDir = filepath.Join(filepath.Dir(filename), "../..") |
| 1246 } | 1326 } |
| 1247 loadTemplates() | 1327 loadTemplates() |
| 1248 } | 1328 } |
| OLD | NEW |