* update git vendor to fix wrong release commit id and add migrations * fix count * fix migration release * fix teststags/v1.9.0-dev
| @@ -3,11 +3,11 @@ | |||
| [[projects]] | |||
| branch = "master" | |||
| digest = "1:0a001725d6e1b35faccf15cbc4f782b67a0d77f4bbf56e51a4b244f92e7c60ca" | |||
| digest = "1:0f0ada42a7b1bd64794bf8fea917c2cd626d6b0539173e3704cd764b93eb5312" | |||
| name = "code.gitea.io/git" | |||
| packages = ["."] | |||
| pruneopts = "NUT" | |||
| revision = "0aea7f12d36ed49bcac560b61301cff88e478e5c" | |||
| revision = "8983773ac6fef49203e7ee8cdbfde3e118bc3421" | |||
| [[projects]] | |||
| branch = "master" | |||
| @@ -217,6 +217,8 @@ var migrations = []Migration{ | |||
| NewMigration("add is locked to issues", addIsLockedToIssues), | |||
| // v81 -> v82 | |||
| NewMigration("update U2F counter type", changeU2FCounterType), | |||
| // v82 -> v83 | |||
| NewMigration("hot fix for wrong release sha1 on release table", fixReleaseSha1OnReleaseTable), | |||
| } | |||
| // Migrate database to current version | |||
| @@ -0,0 +1,87 @@ | |||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package migrations | |||
| import ( | |||
| "code.gitea.io/git" | |||
| "code.gitea.io/gitea/models" | |||
| "github.com/go-xorm/xorm" | |||
| ) | |||
| func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error { | |||
| type Release struct { | |||
| ID int64 | |||
| RepoID int64 | |||
| Sha1 string | |||
| TagName string | |||
| } | |||
| // Update release sha1 | |||
| const batchSize = 100 | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| var ( | |||
| err error | |||
| count int | |||
| gitRepoCache = make(map[int64]*git.Repository) | |||
| repoCache = make(map[int64]*models.Repository) | |||
| ) | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| for start := 0; ; start += batchSize { | |||
| releases := make([]*Release, 0, batchSize) | |||
| if err = sess.Limit(batchSize, start).Asc("id").Where("is_tag=?", false).Find(&releases); err != nil { | |||
| return err | |||
| } | |||
| if len(releases) == 0 { | |||
| break | |||
| } | |||
| for _, release := range releases { | |||
| gitRepo, ok := gitRepoCache[release.RepoID] | |||
| if !ok { | |||
| repo, ok := repoCache[release.RepoID] | |||
| if !ok { | |||
| repo, err = models.GetRepositoryByID(release.RepoID) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| repoCache[release.RepoID] = repo | |||
| } | |||
| gitRepo, err = git.OpenRepository(repo.RepoPath()) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| gitRepoCache[release.RepoID] = gitRepo | |||
| } | |||
| release.Sha1, err = gitRepo.GetTagCommitID(release.TagName) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| if _, err = sess.ID(release.ID).Cols("sha1").Update(release); err != nil { | |||
| return err | |||
| } | |||
| count++ | |||
| if count >= 1000 { | |||
| if err = sess.Commit(); err != nil { | |||
| return err | |||
| } | |||
| if err = sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| count = 0 | |||
| } | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| @@ -110,10 +110,6 @@ func (repo *Repository) CheckBranchName(name string) error { | |||
| return err | |||
| } | |||
| if _, err := gitRepo.GetTag(name); err == nil { | |||
| return ErrTagAlreadyExists{name} | |||
| } | |||
| branches, err := repo.GetBranches() | |||
| if err != nil { | |||
| return err | |||
| @@ -127,6 +123,11 @@ func (repo *Repository) CheckBranchName(name string) error { | |||
| return ErrBranchNameConflict{branch.Name} | |||
| } | |||
| } | |||
| if _, err := gitRepo.GetTag(name); err == nil { | |||
| return ErrTagAlreadyExists{name} | |||
| } | |||
| return nil | |||
| } | |||
| @@ -49,7 +49,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { | |||
| } | |||
| entries.CustomSort(base.NaturalSortLess) | |||
| ctx.Data["Files"], err = entries.GetCommitsInfo(ctx.Repo.Commit, ctx.Repo.TreePath) | |||
| ctx.Data["Files"], err = entries.GetCommitsInfo(ctx.Repo.Commit, ctx.Repo.TreePath, nil) | |||
| if err != nil { | |||
| ctx.ServerError("GetCommitsInfo", err) | |||
| return | |||
| @@ -0,0 +1,11 @@ | |||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package git | |||
| // LastCommitCache cache | |||
| type LastCommitCache interface { | |||
| Get(repoPath, ref, entryPath string) (*Commit, error) | |||
| Put(repoPath, ref, entryPath string, commit *Commit) error | |||
| } | |||
| @@ -72,13 +72,20 @@ func (state *getCommitsInfoState) getTargetedEntryPath() string { | |||
| } | |||
| // repeatedly perform targeted searches for unpopulated entries | |||
| func targetedSearch(state *getCommitsInfoState, done chan error) { | |||
| func targetedSearch(state *getCommitsInfoState, done chan error, cache LastCommitCache) { | |||
| for { | |||
| entryPath := state.getTargetedEntryPath() | |||
| if len(entryPath) == 0 { | |||
| done <- nil | |||
| return | |||
| } | |||
| if cache != nil { | |||
| commit, err := cache.Get(state.headCommit.repo.Path, state.headCommit.ID.String(), entryPath) | |||
| if err == nil && commit != nil { | |||
| state.update(entryPath, commit) | |||
| continue | |||
| } | |||
| } | |||
| command := NewCommand("rev-list", "-1", state.headCommit.ID.String(), "--", entryPath) | |||
| output, err := command.RunInDir(state.headCommit.repo.Path) | |||
| if err != nil { | |||
| @@ -96,6 +103,9 @@ func targetedSearch(state *getCommitsInfoState, done chan error) { | |||
| return | |||
| } | |||
| state.update(entryPath, commit) | |||
| if cache != nil { | |||
| cache.Put(state.headCommit.repo.Path, state.headCommit.ID.String(), entryPath, commit) | |||
| } | |||
| } | |||
| } | |||
| @@ -118,9 +128,9 @@ func initGetCommitInfoState(entries Entries, headCommit *Commit, treePath string | |||
| } | |||
| // GetCommitsInfo gets information of all commits that are corresponding to these entries | |||
| func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) { | |||
| func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCommitCache) ([][]interface{}, error) { | |||
| state := initGetCommitInfoState(tes, commit, treePath) | |||
| if err := getCommitsInfo(state); err != nil { | |||
| if err := getCommitsInfo(state, cache); err != nil { | |||
| return nil, err | |||
| } | |||
| if len(state.commits) < len(state.entryPaths) { | |||
| @@ -188,7 +198,7 @@ func (state *getCommitsInfoState) update(entryPath string, commit *Commit) bool | |||
| const getCommitsInfoPretty = "--pretty=format:%H %ct %s" | |||
| func getCommitsInfo(state *getCommitsInfoState) error { | |||
| func getCommitsInfo(state *getCommitsInfoState, cache LastCommitCache) error { | |||
| ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) | |||
| defer cancel() | |||
| @@ -215,7 +225,7 @@ func getCommitsInfo(state *getCommitsInfoState) error { | |||
| numThreads := runtime.NumCPU() | |||
| done := make(chan error, numThreads) | |||
| for i := 0; i < numThreads; i++ { | |||
| go targetedSearch(state, done) | |||
| go targetedSearch(state, done, cache) | |||
| } | |||
| scanner := bufio.NewScanner(readCloser) | |||
| @@ -32,7 +32,14 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) { | |||
| // GetTagCommitID returns last commit ID string of given tag. | |||
| func (repo *Repository) GetTagCommitID(name string) (string, error) { | |||
| return repo.GetRefCommitID(TagPrefix + name) | |||
| stdout, err := NewCommand("rev-list", "-n", "1", name).RunInDir(repo.Path) | |||
| if err != nil { | |||
| if strings.Contains(err.Error(), "unknown revision or path") { | |||
| return "", ErrNotExist{name, ""} | |||
| } | |||
| return "", err | |||
| } | |||
| return strings.TrimSpace(stdout), nil | |||
| } | |||
| // parseCommitData parses commit information from the (uncompressed) raw | |||
| @@ -76,12 +76,12 @@ func (repo *Repository) getTag(id SHA1) (*Tag, error) { | |||
| // GetTag returns a Git tag by given name. | |||
| func (repo *Repository) GetTag(name string) (*Tag, error) { | |||
| stdout, err := NewCommand("show-ref", "--tags", name).RunInDir(repo.Path) | |||
| idStr, err := repo.GetTagCommitID(name) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| id, err := NewIDFromString(strings.Split(stdout, " ")[0]) | |||
| id, err := NewIDFromString(idStr) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||