blob: 3cc97a85d3e35bda3118fe4122ed06bd82ee4cad [file] [log] [blame]
package repo_manager
import (
"bytes"
"context"
"fmt"
"net/http"
"path"
"strings"
"go.skia.org/infra/autoroll/go/codereview"
"go.skia.org/infra/autoroll/go/strategy"
"go.skia.org/infra/go/gerrit"
"go.skia.org/infra/go/gitiles"
"go.skia.org/infra/go/sklog"
)
/*
Repo manager which rolls Android AFDO profiles into Chromium.
*/
const (
AFDO_COMMIT_MSG_TMPL = `Roll AFDO from %s to %s
This CL may cause a small binary size increase, roughly proportional
to how long it's been since our last AFDO profile roll. For larger
increases (around or exceeding 100KB), please file a bug against
gbiv@chromium.org. Additional context: https://crbug.com/805539
Please note that, despite rolling to chrome/android, this profile is
used for both Linux and Android.
` + COMMIT_MSG_FOOTER_TMPL
)
var (
// "Constants"
AFDO_VERSION_FILE_PATH = path.Join("chrome", "android", "profiles", "newest.txt")
// Use this function to instantiate a RepoManager. This is able to be
// overridden for testing.
NewAFDORepoManager func(context.Context, *AFDORepoManagerConfig, string, gerrit.GerritInterface, string, string, *http.Client, codereview.CodeReview, bool) (RepoManager, error) = newAfdoRepoManager
)
// Shorten the AFDO version.
func afdoShortVersion(long string) string {
return strings.TrimPrefix(strings.TrimSuffix(long, ".afdo.bz2"), "chromeos-chrome-amd64-")
}
// AFDORepoManagerConfig provides configuration for the AFDO RepoManager.
type AFDORepoManagerConfig struct {
NoCheckoutRepoManagerConfig
}
// afdoRepoManager is a RepoManager which rolls Android AFDO profile version
// numbers into Chromium. Unlike other rollers, there is no child repo to sync;
// the version number is obtained from Google Cloud Storage.
type afdoRepoManager struct {
*noCheckoutRepoManager
afdoVersionFile string
authClient *http.Client
versions []string // Protected by infoMtx.
}
// Return an afdoRepoManager instance.
func newAfdoRepoManager(ctx context.Context, c *AFDORepoManagerConfig, workdir string, g gerrit.GerritInterface, serverURL, gitcookiesPath string, client *http.Client, cr codereview.CodeReview, local bool) (RepoManager, error) {
if err := c.Validate(); err != nil {
return nil, err
}
rv := &afdoRepoManager{
afdoVersionFile: AFDO_VERSION_FILE_PATH,
authClient: client,
}
ncrm, err := newNoCheckoutRepoManager(ctx, c.NoCheckoutRepoManagerConfig, workdir, g, serverURL, gitcookiesPath, client, cr, rv.buildCommitMessage, rv.updateHelper, local)
if err != nil {
return nil, err
}
rv.noCheckoutRepoManager = ncrm
return rv, nil
}
// See documentation for noCheckoutRepoManagerBuildCommitMessageFunc.
func (rm *afdoRepoManager) buildCommitMessage(from, to, serverURL, cqExtraTrybots string, emails []string) (string, error) {
commitMsg := fmt.Sprintf(AFDO_COMMIT_MSG_TMPL, afdoShortVersion(from), afdoShortVersion(to), serverURL)
if cqExtraTrybots != "" {
commitMsg += "\n" + fmt.Sprintf(TMPL_CQ_INCLUDE_TRYBOTS, cqExtraTrybots)
}
tbr := "\nTBR="
if len(emails) > 0 {
tbr += strings.Join(emails, ",")
}
commitMsg += tbr
return commitMsg, nil
}
// See documentation for noCheckoutRepoManagerUpdateHelperFunc.
func (rm *afdoRepoManager) updateHelper(ctx context.Context, strat strategy.NextRollStrategy, parentRepo *gitiles.Repo, baseCommit string) (string, string, int, map[string]string, error) {
// Read the version file to determine the last roll rev.
buf := bytes.NewBuffer([]byte{})
if err := parentRepo.ReadFileAtRef(rm.afdoVersionFile, baseCommit, buf); err != nil {
return "", "", 0, nil, err
}
lastRollRev := strings.TrimSpace(buf.String())
// Get the next roll rev, and the list of versions in between the last
// and next rolls.
nextRollRev, err := strat.GetNextRollRev(ctx, nil)
if err != nil {
return "", "", 0, nil, err
}
if nextRollRev == "" {
nextRollRev = lastRollRev
}
versions := strat.(*strategy.AFDOStrategy).GetVersions()
lastIdx := -1
nextIdx := -1
for idx, v := range versions {
if v == lastRollRev {
lastIdx = idx
}
if v == nextRollRev {
nextIdx = idx
}
}
if lastIdx == -1 {
sklog.Errorf("Last roll rev %q not found in available versions. Not-rolled count will be wrong.", lastRollRev)
}
if nextIdx == -1 {
sklog.Errorf("Next roll rev %q not found in available versions. Not-rolled count will be wrong.", nextRollRev)
}
// This seems backwards, but the versions are in descending order.
commitsNotRolled := lastIdx - nextIdx
rm.infoMtx.Lock()
defer rm.infoMtx.Unlock()
rm.versions = versions
return lastRollRev, nextRollRev, commitsNotRolled, map[string]string{AFDO_VERSION_FILE_PATH: nextRollRev}, nil
}
// See documentation for RepoManager interface.
func (rm *afdoRepoManager) FullChildHash(ctx context.Context, ver string) (string, error) {
rm.infoMtx.RLock()
defer rm.infoMtx.RUnlock()
for _, v := range rm.versions {
if strings.Contains(v, ver) {
return v, nil
}
}
return "", fmt.Errorf("Unable to find version: %s", ver)
}
// See documentation for RepoManager interface.
func (rm *afdoRepoManager) RolledPast(ctx context.Context, ver string) (bool, error) {
verIsNewer, err := strategy.AFDOVersionGreater(ver, rm.LastRollRev())
if err != nil {
return false, err
}
return !verIsNewer, nil
}
// See documentation for RepoManager interface.
func (r *afdoRepoManager) CreateNextRollStrategy(ctx context.Context, s string) (strategy.NextRollStrategy, error) {
return strategy.GetNextRollStrategy(ctx, s, r.childBranch, DEFAULT_REMOTE, "", []string{}, r.childRepo, r.authClient)
}
// See documentation for RepoManager interface.
func (r *afdoRepoManager) DefaultStrategy() string {
return strategy.ROLL_STRATEGY_AFDO
}
// See documentation for RepoManager interface.
func (r *afdoRepoManager) ValidStrategies() []string {
return []string{
strategy.ROLL_STRATEGY_AFDO,
}
}