func readResult()

in pkg/updater/read.go [420:540]


func readResult(parent context.Context, client gcs.Downloader, build gcs.Build, stop time.Time) (*gcsResult, error) {
	ctx, cancel := context.WithCancel(parent) // Allows aborting after first error
	defer cancel()
	result := gcsResult{
		job:   build.Job(),
		build: build.Build(),
	}
	ec := make(chan error) // Receives errors from anyone

	var lock sync.Mutex
	addMalformed := func(s ...string) {
		lock.Lock()
		defer lock.Unlock()
		result.malformed = append(result.malformed, s...)
	}

	var work int

	// Download podinfo.json
	work++
	go func() {
		pi, err := build.PodInfo(ctx, client)
		switch {
		case errors.Is(err, io.EOF):
			addMalformed("podinfo.json")
			err = nil
		case err != nil:
			err = fmt.Errorf("podinfo: %w", err)
		case pi != nil:
			result.podInfo = *pi
		}
		select {
		case <-ctx.Done():
		case ec <- err:
		}
	}()

	// Download started.json
	work++
	go func() {
		s, err := build.Started(ctx, client)
		switch {
		case errors.Is(err, io.EOF):
			addMalformed("started.json")
			err = nil
		case err != nil:
			err = fmt.Errorf("started: %w", err)
		case time.Unix(s.Timestamp, 0).Before(stop):
			err = &ancientError{fmt.Sprintf("build too old; started %v before %v)", s.Timestamp, stop.Unix())}
			if s.Timestamp == 0 {
				err = &noStartError{}
			}
		default:
			result.started = *s
		}
		select {
		case <-ctx.Done():
		case ec <- err:
		}
	}()

	// Download finished.json
	work++
	go func() {
		f, err := build.Finished(ctx, client)
		switch {
		case errors.Is(err, io.EOF):
			addMalformed("finished.json")
			err = nil
		case err != nil:
			err = fmt.Errorf("finished: %w", err)
		default:
			result.finished = *f
		}
		select {
		case <-ctx.Done():
		case ec <- err:
		}
	}()

	// Download suites
	work++
	go func() {
		suites, err := readSuites(ctx, client, build)
		if err != nil {
			err = fmt.Errorf("suites: %w", err)
		}
		var problems []string
		for _, s := range suites {
			if s.Err != nil {
				p := strings.TrimPrefix(s.Path, build.Path.String())
				problems = append(problems, fmt.Sprintf("%s: %s", p, s.Err))
			} else {
				result.suites = append(result.suites, s)
			}
		}
		if len(problems) > 0 {
			addMalformed(problems...)
		}

		select {
		case <-ctx.Done():
		case ec <- err:
		}
	}()

	for ; work > 0; work-- {
		select {
		case <-ctx.Done():
			return nil, fmt.Errorf("timeout: %w", ctx.Err())
		case err := <-ec:
			if err != nil {
				return nil, err
			}
		}
	}
	sort.Slice(result.malformed, func(i, j int) bool {
		return result.malformed[i] < result.malformed[j]
	})
	return &result, nil
}