blob: e6171ca7a47a05077ce5fed39157e1bf170a91be [file] [log] [blame]
package incremental
import (
"context"
"fmt"
"reflect"
"sync"
"go.skia.org/infra/go/git"
"go.skia.org/infra/go/git/repograph"
"go.skia.org/infra/go/metrics2"
"go.skia.org/infra/go/vcsinfo"
"go.skia.org/infra/task_scheduler/go/window"
)
// commitsCache is a struct used for tracking newly-landed commits.
type commitsCache struct {
mtx sync.Mutex
// map[repo URL][branch name]*git.Branch
oldBranchHeads map[string]map[string]*git.Branch
repos repograph.Map
}
// newCommitsCache returns a commitsCache instance.
func newCommitsCache(repos repograph.Map) *commitsCache {
return &commitsCache{
repos: repos,
}
}
// Return any new commits for each repo, or the last N if reset is true. Branch
// heads will be provided for a given repo only if there are new commits for
// that repo, or if reset is true. The returned commits may be in any order and
// are not sorted by timestamp.
func (c *commitsCache) Update(ctx context.Context, w *window.Window, reset bool, n int) (map[string][]*git.Branch, map[string][]*vcsinfo.LongCommit, error) {
defer metrics2.FuncTimer().Stop()
c.mtx.Lock()
defer c.mtx.Unlock()
newCommitsAllRepos, _, err := c.repos.UpdateAndReturnCommitDiffs(ctx)
if err != nil {
return nil, nil, fmt.Errorf("Failed to update commitsCache; failed to update repos: %s", err)
}
updatedBranchHeads := make(map[string]map[string]*git.Branch, len(c.repos))
rvCommits := make(map[string][]*vcsinfo.LongCommit, len(c.repos))
rvBranchHeads := make(map[string][]*git.Branch, len(c.repos))
for repoUrl, repo := range c.repos {
// Update the branch heads for this repo.
bh := repo.BranchHeads()
bhMap := make(map[string]*git.Branch, len(bh))
for _, h := range bh {
bhMap[h.Name] = h
}
updatedBranchHeads[repoUrl] = bhMap
newCommits := newCommitsAllRepos[repoUrl]
// If reset is specified, we don't care about changes; we return
// all commits in range.
if reset {
var err error
newCommits, err = repo.GetLastNCommits(n)
if err != nil {
return nil, nil, fmt.Errorf("Failed to update commitsCache; failed to obtain commits from %s: %s", repoUrl, err)
}
}
// Add any new commits to the return value. The branch heads get
// updated if there are any new commits OR if the branch heads
// have changed (eg. in the case of a reset or empty merge).
if len(newCommits) > 0 {
// Only add new commits which are in the window.
filtered := make([]*vcsinfo.LongCommit, 0, len(newCommits))
for _, c := range newCommits {
if w.TestTime(repoUrl, c.Timestamp) {
filtered = append(filtered, c)
}
}
rvCommits[repoUrl] = filtered
rvBranchHeads[repoUrl] = bh
} else if !reflect.DeepEqual(c.oldBranchHeads[repoUrl], bhMap) {
rvBranchHeads[repoUrl] = bh
}
}
c.oldBranchHeads = updatedBranchHeads
return rvBranchHeads, rvCommits, nil
}