From d0bbfd835f1641018f79afc99664230f271cd7bb Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 13 Mar 2019 01:39:20 +0800 Subject: [PATCH] =?UTF-8?q?update=20git=20vendor=20to=20fix=20wrong=20rele?= =?UTF-8?q?ase=20commit=20id=20and=20add=20migrations=20=EF=BC=88#6224?= =?UTF-8?q?=EF=BC=89=20(#6300)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gopkg.lock | 5 +-- models/repo_branch.go | 9 +++-- routers/repo/view.go | 2 +- vendor/code.gitea.io/git/cache.go | 11 +++++ vendor/code.gitea.io/git/commit.go | 53 +++++++++++++++++++++++++ vendor/code.gitea.io/git/commit_info.go | 20 +++++++--- vendor/code.gitea.io/git/repo_commit.go | 31 +++++++++++++-- vendor/code.gitea.io/git/repo_tag.go | 20 +++------- vendor/code.gitea.io/git/submodule.go | 16 ++++++-- vendor/code.gitea.io/git/tree.go | 22 +++++++--- 10 files changed, 149 insertions(+), 40 deletions(-) create mode 100644 vendor/code.gitea.io/git/cache.go diff --git a/Gopkg.lock b/Gopkg.lock index c3b6f2e62..0f952a463 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -3,11 +3,11 @@ [[projects]] branch = "master" - digest = "1:ab875622908a804a327a95a1701002b150806a3c5406df51ec231eac16d3a1ca" + digest = "1:e1fa64238b0a2dbf1edf98c4af8d1b8cb65179e286d7f28006b50fa9f508ee9d" name = "code.gitea.io/git" packages = ["."] pruneopts = "NUT" - revision = "389d3c803e12a30dffcbb54a15c2242521bc4333" + revision = "74d7c14dd4a3ed9c5def0dc3c1aeede399ddc5c5" [[projects]] branch = "master" @@ -1173,7 +1173,6 @@ "github.com/keybase/go-crypto/openpgp", "github.com/keybase/go-crypto/openpgp/armor", "github.com/keybase/go-crypto/openpgp/packet", - "github.com/klauspost/compress/gzip", "github.com/lafriks/xormstore", "github.com/lib/pq", "github.com/lunny/dingtalk_webhook", diff --git a/models/repo_branch.go b/models/repo_branch.go index cd12742ba..b2297d913 100644 --- a/models/repo_branch.go +++ b/models/repo_branch.go @@ -70,10 +70,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 @@ -87,6 +83,11 @@ func (repo *Repository) CheckBranchName(name string) error { return ErrBranchNameConflict{branch.Name} } } + + if _, err := gitRepo.GetTag(name); err == nil { + return ErrTagAlreadyExists{name} + } + return nil } diff --git a/routers/repo/view.go b/routers/repo/view.go index 78a305aa2..c63217556 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -50,7 +50,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 diff --git a/vendor/code.gitea.io/git/cache.go b/vendor/code.gitea.io/git/cache.go new file mode 100644 index 000000000..dbbbafae4 --- /dev/null +++ b/vendor/code.gitea.io/git/cache.go @@ -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 +} diff --git a/vendor/code.gitea.io/git/commit.go b/vendor/code.gitea.io/git/commit.go index 5e8c91d30..36b8d5456 100644 --- a/vendor/code.gitea.io/git/commit.go +++ b/vendor/code.gitea.io/git/commit.go @@ -1,4 +1,5 @@ // Copyright 2015 The Gogs Authors. All rights reserved. +// Copyright 2018 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. @@ -9,6 +10,7 @@ import ( "bytes" "container/list" "fmt" + "io" "net/http" "strconv" "strings" @@ -16,6 +18,7 @@ import ( // Commit represents a git commit. type Commit struct { + Branch string // Branch this commit belongs to Tree ID SHA1 // The ID of this commit object Author *Signature @@ -279,6 +282,56 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) { return nil, nil } +// CommitFileStatus represents status of files in a commit. +type CommitFileStatus struct { + Added []string + Removed []string + Modified []string +} + +// NewCommitFileStatus creates a CommitFileStatus +func NewCommitFileStatus() *CommitFileStatus { + return &CommitFileStatus{ + []string{}, []string{}, []string{}, + } +} + +// GetCommitFileStatus returns file status of commit in given repository. +func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) { + stdout, w := io.Pipe() + done := make(chan struct{}) + fileStatus := NewCommitFileStatus() + go func() { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + if len(fields) < 2 { + continue + } + + switch fields[0][0] { + case 'A': + fileStatus.Added = append(fileStatus.Added, fields[1]) + case 'D': + fileStatus.Removed = append(fileStatus.Removed, fields[1]) + case 'M': + fileStatus.Modified = append(fileStatus.Modified, fields[1]) + } + } + done <- struct{}{} + }() + + stderr := new(bytes.Buffer) + err := NewCommand("show", "--name-status", "--pretty=format:''", commitID).RunInDirPipeline(repoPath, w, stderr) + w.Close() // Close writer to exit parsing goroutine + if err != nil { + return nil, concatenateError(err, stderr.String()) + } + + <-done + return fileStatus, nil +} + // GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository. func GetFullCommitID(repoPath, shortID string) (string, error) { if len(shortID) >= 40 { diff --git a/vendor/code.gitea.io/git/commit_info.go b/vendor/code.gitea.io/git/commit_info.go index 6b42b57c9..971082be1 100644 --- a/vendor/code.gitea.io/git/commit_info.go +++ b/vendor/code.gitea.io/git/commit_info.go @@ -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) diff --git a/vendor/code.gitea.io/git/repo_commit.go b/vendor/code.gitea.io/git/repo_commit.go index d5cab8f87..2d9f5bdbf 100644 --- a/vendor/code.gitea.io/git/repo_commit.go +++ b/vendor/code.gitea.io/git/repo_commit.go @@ -10,7 +10,7 @@ import ( "strconv" "strings" - "github.com/mcuadros/go-version" + version "github.com/mcuadros/go-version" ) // GetRefCommitID returns the last commit ID string of given reference (branch or tag). @@ -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 @@ -94,7 +101,11 @@ l: sig, err := newGPGSignatureFromCommitline(data, (nextline+1)+sigindex, true) if err == nil && sig != nil { // remove signature from commit message - cm = cm[:sigindex-1] + if sigindex == 0 { + cm = "" + } else { + cm = cm[:sigindex-1] + } commit.Signature = sig } } @@ -130,6 +141,14 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) { commit.repo = repo commit.ID = id + data, err = NewCommand("name-rev", id.String()).RunInDirBytes(repo.Path) + if err != nil { + return nil, err + } + + // name-rev commitID ouput will be "COMMIT_ID master" or "COMMIT_ID master~12" + commit.Branch = strings.Split(strings.Split(string(data), " ")[1], "~")[0] + repo.commitCache.Set(id.String(), commit) return commit, nil } @@ -138,10 +157,14 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) { func (repo *Repository) GetCommit(commitID string) (*Commit, error) { if len(commitID) != 40 { var err error - commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path) + actualCommitID, err := NewCommand("rev-parse", commitID).RunInDir(repo.Path) if err != nil { + if strings.Contains(err.Error(), "unknown revision or path") { + return nil, ErrNotExist{commitID, ""} + } return nil, err } + commitID = actualCommitID } id, err := NewIDFromString(commitID) if err != nil { diff --git a/vendor/code.gitea.io/git/repo_tag.go b/vendor/code.gitea.io/git/repo_tag.go index 11f1f3da7..84825d7dc 100644 --- a/vendor/code.gitea.io/git/repo_tag.go +++ b/vendor/code.gitea.io/git/repo_tag.go @@ -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 } @@ -103,26 +103,18 @@ func (repo *Repository) GetTagInfos() ([]*Tag, error) { } tagNames := strings.Split(stdout, "\n") - var tags []*Tag + var tags = make([]*Tag, 0, len(tagNames)) for _, tagName := range tagNames { tagName = strings.TrimSpace(tagName) if len(tagName) == 0 { continue } - commitID, err := NewCommand("rev-parse", tagName).RunInDir(repo.Path) + + tag, err := repo.GetTag(tagName) if err != nil { return nil, err } - commit, err := repo.GetCommit(commitID) - if err != nil { - return nil, err - } - tags = append(tags, &Tag{ - Name: tagName, - Message: commit.Message(), - Object: commit.ID, - Tagger: commit.Author, - }) + tags = append(tags, tag) } sortTagsByTime(tags) return tags, nil diff --git a/vendor/code.gitea.io/git/submodule.go b/vendor/code.gitea.io/git/submodule.go index a0fe7b4a5..294df3986 100644 --- a/vendor/code.gitea.io/git/submodule.go +++ b/vendor/code.gitea.io/git/submodule.go @@ -29,13 +29,12 @@ func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile { } } -// RefURL guesses and returns reference URL. -func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string { - if sf.refURL == "" { +func getRefURL(refURL, urlPrefix, parentPath string) string { + if refURL == "" { return "" } - url := strings.TrimSuffix(sf.refURL, ".git") + url := strings.TrimSuffix(refURL, ".git") // git://xxx/user/repo if strings.HasPrefix(url, "git://") { @@ -67,12 +66,21 @@ func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string { if strings.Contains(urlPrefix, url[i+1:j]) { return urlPrefix + url[j+1:] } + if strings.HasPrefix(url, "ssh://") || strings.HasPrefix(url, "git+ssh://") { + k := strings.Index(url[j+1:], "/") + return "http://" + url[i+1:j] + "/" + url[j+1:][k+1:] + } return "http://" + url[i+1:j] + "/" + url[j+1:] } return url } +// RefURL guesses and returns reference URL. +func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string { + return getRefURL(sf.refURL, urlPrefix, parentPath) +} + // RefID returns reference ID. func (sf *SubModuleFile) RefID() string { return sf.refID diff --git a/vendor/code.gitea.io/git/tree.go b/vendor/code.gitea.io/git/tree.go index b67bf5584..b65fe1940 100644 --- a/vendor/code.gitea.io/git/tree.go +++ b/vendor/code.gitea.io/git/tree.go @@ -18,6 +18,9 @@ type Tree struct { entries Entries entriesParsed bool + + entriesRecursive Entries + entriesRecursiveParsed bool } // NewTree create a new tree according the repository and commit id @@ -67,20 +70,29 @@ func (t *Tree) ListEntries() (Entries, error) { if err != nil { return nil, err } + t.entries, err = parseTreeEntries(stdout, t) + if err == nil { + t.entriesParsed = true + } + return t.entries, err } // ListEntriesRecursive returns all entries of current tree recursively including all subtrees func (t *Tree) ListEntriesRecursive() (Entries, error) { - if t.entriesParsed { - return t.entries, nil + if t.entriesRecursiveParsed { + return t.entriesRecursive, nil } stdout, err := NewCommand("ls-tree", "-t", "-r", t.ID.String()).RunInDirBytes(t.repo.Path) - if err != nil { return nil, err } - t.entries, err = parseTreeEntries(stdout, t) - return t.entries, err + + t.entriesRecursive, err = parseTreeEntries(stdout, t) + if err == nil { + t.entriesRecursiveParsed = true + } + + return t.entriesRecursive, err }