Index: milo/buildsource/buildbot/builder.go |
diff --git a/milo/buildsource/buildbot/builder.go b/milo/buildsource/buildbot/builder.go |
index dc3790656f9d70b6c63cf9685fa4fc929d00f016..644b3ccbb66bfdcb06cd526e4e47c92932dc903f 100644 |
--- a/milo/buildsource/buildbot/builder.go |
+++ b/milo/buildsource/buildbot/builder.go |
@@ -17,7 +17,6 @@ package buildbot |
import ( |
"crypto/sha1" |
"encoding/base64" |
- "errors" |
"fmt" |
"sort" |
"strings" |
@@ -27,8 +26,10 @@ import ( |
"github.com/luci/gae/service/memcache" |
"github.com/luci/luci-go/common/clock" |
+ "github.com/luci/luci-go/common/errors" |
"github.com/luci/luci-go/common/logging" |
"github.com/luci/luci-go/milo/api/resp" |
+ "github.com/luci/luci-go/milo/common" |
"golang.org/x/net/context" |
) |
@@ -95,8 +96,8 @@ func getBuildSummary(b *buildbotBuild) *resp.BuildSummary { |
// getBuilds fetches all of the recent builds from the . Note that |
// getBuilds() does not perform ACL checks. |
func getBuilds( |
- c context.Context, masterName, builderName string, finished bool, limit int, cursor *datastore.Cursor) ( |
- []*resp.BuildSummary, *datastore.Cursor, error) { |
+ c context.Context, masterName, builderName string, finished bool, limit int, cursor datastore.Cursor) ( |
+ []*resp.BuildSummary, datastore.Cursor, error) { |
// TODO(hinoka): Builder specific structs. |
result := []*resp.BuildSummary{} |
@@ -106,7 +107,7 @@ func getBuilds( |
q = q.Eq("builder", builderName) |
q = q.Order("-number") |
if cursor != nil { |
- q = q.Start(*cursor) |
+ q = q.Start(cursor) |
} |
buildbots, nextCursor, err := runBuildsQuery(c, q, int32(limit)) |
if err != nil { |
@@ -122,7 +123,7 @@ func getBuilds( |
// datastore cursor by creating a mapping of nextCursor -> thisCursor |
// in memcache. maybeSetGetCursor stores the future mapping, then returns prevCursor |
// in the mapping for thisCursor -> prevCursor, if available. |
-func maybeSetGetCursor(c context.Context, thisCursor, nextCursor *datastore.Cursor, limit int) (*datastore.Cursor, bool) { |
+func maybeSetGetCursor(c context.Context, thisCursor, nextCursor datastore.Cursor, limit int) (datastore.Cursor, bool) { |
key := func(c datastore.Cursor) string { |
// Memcache key limit is 250 bytes, hash our cursor to get under this limit. |
blob := sha1.Sum([]byte(c.String())) |
@@ -130,12 +131,12 @@ func maybeSetGetCursor(c context.Context, thisCursor, nextCursor *datastore.Curs |
} |
// Set the next cursor to this cursor mapping, if available. |
if nextCursor != nil { |
- item := memcache.NewItem(c, key(*nextCursor)) |
+ item := memcache.NewItem(c, key(nextCursor)) |
if thisCursor == nil { |
// Make sure we know it exists, just empty |
item.SetValue([]byte{}) |
} else { |
- item.SetValue([]byte((*thisCursor).String())) |
+ item.SetValue([]byte(thisCursor.String())) |
} |
item.SetExpiration(24 * time.Hour) |
memcache.Set(c, item) |
@@ -144,33 +145,17 @@ func maybeSetGetCursor(c context.Context, thisCursor, nextCursor *datastore.Curs |
if thisCursor == nil { |
return nil, false |
} |
- if item, err := memcache.GetKey(c, key(*thisCursor)); err == nil { |
+ if item, err := memcache.GetKey(c, key(thisCursor)); err == nil { |
if len(item.Value()) == 0 { |
return nil, true |
} |
if prevCursor, err := datastore.DecodeCursor(c, string(item.Value())); err == nil { |
- return &prevCursor, true |
+ return prevCursor, true |
} |
} |
return nil, false |
} |
-var errMasterNotFound = errors.New( |
- "Either the request resource was not found or you have insufficient permissions") |
-var errNotAuth = errors.New("You are not authenticated, try logging in") |
- |
-type errBuilderNotFound struct { |
- master string |
- builder string |
- available []string |
-} |
- |
-func (e errBuilderNotFound) Error() string { |
- avail := strings.Join(e.available, "\n") |
- return fmt.Sprintf("Cannot find builder %q in master %q.\nAvailable builders: \n%s", |
- e.builder, e.master, avail) |
-} |
- |
func summarizeSlavePool( |
baseURL string, slaves []string, slaveMap map[string]*buildbotSlave) *resp.MachinePool { |
@@ -204,23 +189,13 @@ func summarizeSlavePool( |
return mp |
} |
-// builderImpl is the implementation for getting a milo builder page from buildbot. |
+// GetBuilder is the implementation for getting a milo builder page from |
+// buildbot. |
+// |
// This gets: |
-// * Current Builds from querying the master json from the datastore. |
-// * Recent Builds from a cron job that backfills the recent builds. |
-func builderImpl( |
- c context.Context, masterName, builderName string, limit int, cursor string) ( |
- *resp.Builder, error) { |
- |
- var thisCursor *datastore.Cursor |
- if cursor != "" { |
- tmpCur, err := datastore.DecodeCursor(c, cursor) |
- if err != nil { |
- return nil, fmt.Errorf("bad cursor: %s", err) |
- } |
- thisCursor = &tmpCur |
- } |
- |
+// * Current Builds from querying the master json from the datastore. |
+// * Recent Builds from a cron job that backfills the recent builds. |
+func GetBuilder(c context.Context, masterName, builderName string, limit int, cursor datastore.Cursor) (*resp.Builder, error) { |
result := &resp.Builder{ |
Name: builderName, |
} |
@@ -244,7 +219,13 @@ func builderImpl( |
keys = append(keys, k) |
} |
sort.Strings(keys) |
- return nil, errBuilderNotFound{masterName, builderName, keys} |
+ // TODO(iannucci): add error-info-helper tags to give the error page enough |
+ // information to render link-to-master and link-to-builder. |
+ builders := strings.Join(keys, "\n") |
+ return nil, errors.Reason( |
+ "Cannot find builder %q in master %q.\nAvailable builders: \n%s", |
+ builderName, masterName, builders, |
+ ).Tag(common.CodeNotFound).Err() |
} |
// Extract pending builds out of the master json. |
result.PendingBuilds = make([]*resp.BuildSummary, len(p.PendingBuildStates)) |
@@ -273,20 +254,20 @@ func builderImpl( |
result.MachinePool = summarizeSlavePool(baseURL+master.Name, p.Slaves, master.Slaves) |
// This is CPU bound anyways, so there's no need to do this in parallel. |
- finishedBuilds, nextCursor, err := getBuilds(c, masterName, builderName, true, limit, thisCursor) |
+ finishedBuilds, nextCursor, err := getBuilds(c, masterName, builderName, true, limit, cursor) |
if err != nil { |
return nil, err |
} |
- if prevCursor, ok := maybeSetGetCursor(c, thisCursor, nextCursor, limit); ok { |
+ if prevCursor, ok := maybeSetGetCursor(c, cursor, nextCursor, limit); ok { |
if prevCursor == nil { |
// Magic string to signal display prev without cursor |
result.PrevCursor = "EMPTY" |
} else { |
- result.PrevCursor = (*prevCursor).String() |
+ result.PrevCursor = prevCursor.String() |
} |
} |
if nextCursor != nil { |
- result.NextCursor = (*nextCursor).String() |
+ result.NextCursor = nextCursor.String() |
} |
// Cursor is not needed for current builds. |
currentBuilds, _, err := getBuilds(c, masterName, builderName, false, 0, nil) |