* 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 | |||
} | |||