func ListBuilds()

in util/gcs/read.go [202:277]


func ListBuilds(parent context.Context, lister Lister, gcsPath Path, after *Path) ([]Build, error) {
	ctx, cancel := context.WithCancel(parent)
	defer cancel()
	var offset string
	if after != nil {
		offset = after.Object()
	}
	offsetBaseName := hackOffset(&offset)
	if !strings.HasSuffix(offset, "/") {
		offset += "/"
	}
	it := lister.Objects(ctx, gcsPath, "/", offset)
	var all []Build
	for {
		objAttrs, err := it.Next()
		if errors.Is(err, iterator.Done) {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("list objects: %w", err)
		}

		// if this is a link under directory/, resolve the build value
		// This is used for PR type jobs which we store in a PR specific prefix.
		// The directory prefix contains a link header to the result
		// under the PR specific prefix.
		if link := readLink(objAttrs); link != "" {
			// links created by bootstrap.py have a space
			link = strings.TrimSpace(link)
			u, err := url.Parse(link)
			if err != nil {
				return nil, fmt.Errorf("parse %s link: %v", objAttrs.Name, err)
			}
			if !strings.HasSuffix(u.Path, "/") {
				u.Path += "/"
			}
			var linkPath Path
			if err := linkPath.SetURL(u); err != nil {
				return nil, fmt.Errorf("bad %s link path %s: %w", objAttrs.Name, u, err)
			}
			all = append(all, Build{
				Path:     linkPath,
				baseName: path.Base(objAttrs.Name),
			})
			continue
		}

		if objAttrs.Prefix == "" {
			continue // not a symlink to a directory
		}

		loc := "gs://" + gcsPath.Bucket() + "/" + objAttrs.Prefix
		gcsPath, err := NewPath(loc)
		if err != nil {
			return nil, fmt.Errorf("bad path %q: %w", loc, err)
		}

		all = append(all, Build{
			Path:     *gcsPath,
			baseName: path.Base(objAttrs.Prefix),
		})
	}

	Sort(all)

	if offsetBaseName != "" {
		// GCS will return 200 2000 30 for a prefix of 100
		// testgrid expects this as 2000 200 (dropping 30)
		for i, b := range all {
			if sortorder.NaturalLess(b.baseName, offsetBaseName) || b.baseName == offsetBaseName {
				return all[:i], nil // b <= offsetBaseName, so skip this one
			}
		}
	}
	return all, nil
}