Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package buildbot | 5 package buildbot |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "encoding/json" | 8 "encoding/json" |
| 9 "errors" | 9 "errors" |
| 10 "fmt" | 10 "fmt" |
| 11 "io/ioutil" | 11 "io/ioutil" |
| 12 "math" | |
| 12 "path/filepath" | 13 "path/filepath" |
| 13 "regexp" | 14 "regexp" |
| 14 "sort" | 15 "sort" |
| 15 "strings" | 16 "strings" |
| 16 "time" | 17 "time" |
| 17 | 18 |
| 18 "golang.org/x/net/context" | 19 "golang.org/x/net/context" |
| 19 | 20 |
| 20 "github.com/luci/gae/service/datastore" | 21 "github.com/luci/gae/service/datastore" |
| 21 "github.com/luci/luci-go/common/data/stringset" | 22 "github.com/luci/luci-go/common/data/stringset" |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 306 } | 307 } |
| 307 | 308 |
| 308 // Figure out the times. | 309 // Figure out the times. |
| 309 bc.Started, bc.Finished, bc.Duration = parseTimes(endingTime, st ep.Times) | 310 bc.Started, bc.Finished, bc.Duration = parseTimes(endingTime, st ep.Times) |
| 310 | 311 |
| 311 result = append(result, bc) | 312 result = append(result, bc) |
| 312 } | 313 } |
| 313 return | 314 return |
| 314 } | 315 } |
| 315 | 316 |
| 316 // parseProp returns a representation of v based off k, and a boolean to | 317 // parseProp returns a representation of v based off k, and a boolean to |
|
nodir
2017/04/11 07:13:19
there is no k
nodir
2017/04/11 07:13:19
high level: i think JSON encoding should be in a t
hinoka
2017/04/13 21:01:59
This was done this was because previously rietveld
| |
| 317 // specify whether or not to hide it altogether. | 318 // specify whether or not to hide it altogether. |
|
nodir
2017/04/11 07:13:19
after I read this, i thought the function returns
hinoka
2017/04/13 21:01:59
Removed block.
| |
| 318 func parseProp(prop map[string]Prop, k string, v interface{}) (string, bool) { | 319 func parseProp(v interface{}) (string, bool) { |
| 319 » switch k { | 320 » if vs, ok := v.(string); ok && vs == "" { |
| 320 » case "requestedAt": | 321 » » return "", false // Value is empty, don't show it. |
|
nodir
2017/04/11 07:13:19
why we are hiding empty strings? They are legit va
hinoka
2017/04/13 21:01:59
They why is because it seems kind of useless to di
nodir
2017/04/13 21:08:20
Yeah, I think they should be there. Imagine someon
| |
| 321 » » if vf, ok := v.(float64); ok { | 322 » } |
| 322 » » » return time.Unix(int64(vf), 0).UTC().Format(time.RFC3339 ), true | 323 » if v == nil { |
| 324 » » return "", false | |
| 325 » } | |
| 326 » // if v is a whole number, force it into an int. json.Marshal() would t urn | |
| 327 » // it into what looks like a float instead. We want this to remain and | |
| 328 » // int instead of a number. | |
| 329 » if vf, ok := v.(float64); ok { | |
| 330 » » if math.Floor(vf) == vf { | |
| 331 » » » return fmt.Sprintf("%d", int64(vf)), true | |
| 323 } | 332 } |
| 324 » case "buildbucket": | 333 » } |
| 325 » » var b map[string]interface{} | 334 » // return the json representation of the value. |
| 326 » » json.Unmarshal([]byte(v.(string)), &b) | 335 » b, err := json.Marshal(v) |
| 327 » » if b["build"] == nil { | 336 » if err == nil { |
| 328 » » » return "", false | 337 » » return string(b), true |
| 329 » » } | |
| 330 » » build := b["build"].(map[string]interface{}) | |
| 331 » » id := build["id"] | |
| 332 » » if id == nil { | |
| 333 » » » return "", false | |
| 334 » » } | |
| 335 » » return fmt.Sprintf("https://cr-buildbucket.appspot.com/b/%s", id .(string)), true | |
| 336 » case "issue": | |
| 337 » » if rv, ok := prop["rietveld"]; ok { | |
| 338 » » » rietveld := rv.Value.(string) | |
| 339 » » » // Issue could be a float, int, or string. | |
| 340 » » » switch v := v.(type) { | |
| 341 » » » case float64: | |
| 342 » » » » return fmt.Sprintf("%s/%d", rietveld, int(v)), t rue | |
| 343 » » » default: // Probably int or string | |
| 344 » » » » return fmt.Sprintf("%s/%v", rietveld, v), true | |
| 345 » » » } | |
| 346 » » } | |
| 347 » » return fmt.Sprintf("%d", int(v.(float64))), true | |
| 348 » case "rietveld": | |
| 349 » » return "", false | |
| 350 » default: | |
| 351 » » if vs, ok := v.(string); ok && vs == "" { | |
| 352 » » » return "", false // Value is empty, don't show it. | |
| 353 » » } | |
| 354 » » if v == nil { | |
| 355 » » » return "", false | |
| 356 » » } | |
| 357 } | 338 } |
| 358 return fmt.Sprintf("%v", v), true | 339 return fmt.Sprintf("%v", v), true |
| 359 } | 340 } |
| 360 | 341 |
| 361 // Prop is a struct used to store a value and group so that we can make a map | 342 // Prop is a struct used to store a value and group so that we can make a map |
| 362 // of key:Prop to pass into parseProp() for the purpose of cross referencing | 343 // of key:Prop to pass into parseProp() for the purpose of cross referencing |
| 363 // one prop while working on another. | 344 // one prop while working on another. |
| 364 type Prop struct { | 345 type Prop struct { |
| 365 Value interface{} | 346 Value interface{} |
| 366 Group string | 347 Group string |
| 367 } | 348 } |
| 368 | 349 |
| 369 // properties extracts all properties from buildbot builds and groups them into | 350 // properties extracts all properties from buildbot builds and groups them into |
| 370 // property groups. | 351 // property groups. |
| 371 func properties(b *buildbotBuild) (result []*resp.PropertyGroup) { | 352 func properties(b *buildbotBuild) (result []*resp.PropertyGroup) { |
| 372 groups := map[string]*resp.PropertyGroup{} | 353 groups := map[string]*resp.PropertyGroup{} |
| 373 allProps := map[string]Prop{} | 354 allProps := map[string]Prop{} |
| 374 for _, prop := range b.Properties { | 355 for _, prop := range b.Properties { |
| 375 allProps[prop.Name] = Prop{ | 356 allProps[prop.Name] = Prop{ |
| 376 Value: prop.Value, | 357 Value: prop.Value, |
| 377 Group: prop.Source, | 358 Group: prop.Source, |
| 378 } | 359 } |
| 379 } | 360 } |
| 380 for key, prop := range allProps { | 361 for key, prop := range allProps { |
| 381 value := prop.Value | 362 value := prop.Value |
| 382 groupName := prop.Group | 363 groupName := prop.Group |
| 383 if _, ok := groups[groupName]; !ok { | 364 if _, ok := groups[groupName]; !ok { |
| 384 groups[groupName] = &resp.PropertyGroup{GroupName: group Name} | 365 groups[groupName] = &resp.PropertyGroup{GroupName: group Name} |
| 385 } | 366 } |
| 386 » » vs, ok := parseProp(allProps, key, value) | 367 » » vs, ok := parseProp(value) |
| 387 if !ok { | 368 if !ok { |
| 388 continue | 369 continue |
| 389 } | 370 } |
| 390 groups[groupName].Property = append(groups[groupName].Property, &resp.Property{ | 371 groups[groupName].Property = append(groups[groupName].Property, &resp.Property{ |
| 391 Key: key, | 372 Key: key, |
| 392 Value: vs, | 373 Value: vs, |
|
nodir
2017/04/11 07:13:20
i think this should be an interface{} and JSON-enc
hinoka
2017/04/13 21:01:59
I'll do that in a different CL. That would underm
| |
| 393 }) | 374 }) |
| 394 } | 375 } |
| 395 // Insert the groups into a list in alphabetical order. | 376 // Insert the groups into a list in alphabetical order. |
| 396 // You have to make a separate sorting data structure because Go doesn't like | 377 // You have to make a separate sorting data structure because Go doesn't like |
| 397 // sorting things for you. | 378 // sorting things for you. |
| 398 groupNames := []string{} | 379 groupNames := []string{} |
| 399 for n := range groups { | 380 for n := range groups { |
| 400 groupNames = append(groupNames, n) | 381 groupNames = append(groupNames, n) |
| 401 } | 382 } |
| 402 sort.Strings(groupNames) | 383 sort.Strings(groupNames) |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 659 var newAliases map[string][]*buildbotLinkAlias | 640 var newAliases map[string][]*buildbotLinkAlias |
| 660 if l := remainingAliases.Len(); l > 0 { | 641 if l := remainingAliases.Len(); l > 0 { |
| 661 newAliases = make(map[string][]*buildbotLinkAlias, l) | 642 newAliases = make(map[string][]*buildbotLinkAlias, l) |
| 662 remainingAliases.Iter(func(v string) bool { | 643 remainingAliases.Iter(func(v string) bool { |
| 663 newAliases[v] = s.Aliases[v] | 644 newAliases[v] = s.Aliases[v] |
| 664 return true | 645 return true |
| 665 }) | 646 }) |
| 666 } | 647 } |
| 667 s.Aliases = newAliases | 648 s.Aliases = newAliases |
| 668 } | 649 } |
| OLD | NEW |