From 48ce135cc9d54d1c5cf876411453414a53183968 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 3 Feb 2020 16:47:04 +0800 Subject: [PATCH] Move PushUpdateAddDeleteTags to repository module from models (#10106) * Move PushUpdateAddDeleteTags to repository module from models * Fix deadlock on sqlite --- models/helper_environment.go | 13 +++ models/release.go | 16 ++-- models/update.go | 158 ++--------------------------------- models/user.go | 13 ++- modules/repofiles/update.go | 2 +- modules/repository/update.go | 134 +++++++++++++++++++++++++++++ routers/repo/repo.go | 2 +- services/release/release.go | 4 +- 8 files changed, 176 insertions(+), 166 deletions(-) create mode 100644 modules/repository/update.go diff --git a/models/helper_environment.go b/models/helper_environment.go index 112df9682..bc9d4c8fc 100644 --- a/models/helper_environment.go +++ b/models/helper_environment.go @@ -10,6 +10,19 @@ import ( "strings" ) +// env keys for git hooks need +const ( + EnvRepoName = "GITEA_REPO_NAME" + EnvRepoUsername = "GITEA_REPO_USER_NAME" + EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" + EnvPusherName = "GITEA_PUSHER_NAME" + EnvPusherEmail = "GITEA_PUSHER_EMAIL" + EnvPusherID = "GITEA_PUSHER_ID" + EnvKeyID = "GITEA_KEY_ID" + EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" + EnvIsInternal = "GITEA_INTERNAL_PUSH" +) + // InternalPushingEnvironment returns an os environment to switch off hooks on push // It is recommended to avoid using this unless you are pushing within a transaction // or if you absolutely are sure that post-receive and pre-receive will do nothing diff --git a/models/release.go b/models/release.go index ebd2b6d38..0f670f374 100644 --- a/models/release.go +++ b/models/release.go @@ -119,9 +119,15 @@ func InsertRelease(rel *Release) error { return err } +// InsertReleasesContext insert releases +func InsertReleasesContext(ctx DBContext, rels []*Release) error { + _, err := ctx.e.Insert(rels) + return err +} + // UpdateRelease updates all columns of a release -func UpdateRelease(rel *Release) error { - _, err := x.ID(rel.ID).AllCols().Update(rel) +func UpdateRelease(ctx DBContext, rel *Release) error { + _, err := ctx.e.ID(rel.ID).AllCols().Update(rel) return err } @@ -212,10 +218,10 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er } // GetReleasesByRepoIDAndNames returns a list of releases of repository according repoID and tagNames. -func GetReleasesByRepoIDAndNames(repoID int64, tagNames []string) (rels []*Release, err error) { - err = x. - Desc("created_unix"). +func GetReleasesByRepoIDAndNames(ctx DBContext, repoID int64, tagNames []string) (rels []*Release, err error) { + err = ctx.e. In("tag_name", tagNames). + Desc("created_unix"). Find(&rels, Release{RepoID: repoID}) return rels, err } diff --git a/models/update.go b/models/update.go index 17ee9ad5f..8e18450db 100644 --- a/models/update.go +++ b/models/update.go @@ -7,42 +7,8 @@ package models import ( "fmt" "strings" - "time" - - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/timeutil" ) -// env keys for git hooks need -const ( - EnvRepoName = "GITEA_REPO_NAME" - EnvRepoUsername = "GITEA_REPO_USER_NAME" - EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" - EnvPusherName = "GITEA_PUSHER_NAME" - EnvPusherEmail = "GITEA_PUSHER_EMAIL" - EnvPusherID = "GITEA_PUSHER_ID" - EnvKeyID = "GITEA_KEY_ID" - EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" - EnvIsInternal = "GITEA_INTERNAL_PUSH" -) - -// PushUpdateAddDeleteTags updates a number of added and delete tags -func PushUpdateAddDeleteTags(repo *Repository, gitRepo *git.Repository, addTags, delTags []string) error { - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return fmt.Errorf("Unable to begin sess in PushUpdateDeleteTags: %v", err) - } - if err := pushUpdateDeleteTags(sess, repo, delTags); err != nil { - return err - } - if err := pushUpdateAddTags(sess, repo, gitRepo, addTags); err != nil { - return err - } - - return sess.Commit() -} - // PushUpdateDeleteTags updates a number of delete tags func PushUpdateDeleteTags(repo *Repository, tags []string) error { sess := x.NewSession() @@ -57,6 +23,11 @@ func PushUpdateDeleteTags(repo *Repository, tags []string) error { return sess.Commit() } +// PushUpdateDeleteTagsContext updates a number of delete tags with context +func PushUpdateDeleteTagsContext(ctx DBContext, repo *Repository, tags []string) error { + return pushUpdateDeleteTags(ctx.e, repo, tags) +} + func pushUpdateDeleteTags(e Engine, repo *Repository, tags []string) error { if len(tags) == 0 { return nil @@ -111,125 +82,6 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error { return nil } -// PushUpdateAddTags updates a number of add tags -func PushUpdateAddTags(repo *Repository, gitRepo *git.Repository, tags []string) error { - sess := x.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return fmt.Errorf("Unable to begin sess in PushUpdateAddTags: %v", err) - } - if err := pushUpdateAddTags(sess, repo, gitRepo, tags); err != nil { - return err - } - - return sess.Commit() -} -func pushUpdateAddTags(e Engine, repo *Repository, gitRepo *git.Repository, tags []string) error { - if len(tags) == 0 { - return nil - } - - lowerTags := make([]string, 0, len(tags)) - for _, tag := range tags { - lowerTags = append(lowerTags, strings.ToLower(tag)) - } - - releases := make([]Release, 0, len(tags)) - if err := e.Where("repo_id = ?", repo.ID). - In("lower_tag_name", lowerTags).Find(&releases); err != nil { - return fmt.Errorf("GetRelease: %v", err) - } - relMap := make(map[string]*Release) - for _, rel := range releases { - relMap[rel.LowerTagName] = &rel - } - - newReleases := make([]*Release, 0, len(lowerTags)-len(relMap)) - - emailToUser := make(map[string]*User) - - for i, lowerTag := range lowerTags { - tag, err := gitRepo.GetTag(tags[i]) - if err != nil { - return fmt.Errorf("GetTag: %v", err) - } - commit, err := tag.Commit() - if err != nil { - return fmt.Errorf("Commit: %v", err) - } - - sig := tag.Tagger - if sig == nil { - sig = commit.Author - } - if sig == nil { - sig = commit.Committer - } - var author *User - var createdAt = time.Unix(1, 0) - - if sig != nil { - var ok bool - author, ok = emailToUser[sig.Email] - if !ok { - author, err = GetUserByEmail(sig.Email) - if err != nil && !IsErrUserNotExist(err) { - return fmt.Errorf("GetUserByEmail: %v", err) - } - } - createdAt = sig.When - } - - commitsCount, err := commit.CommitsCount() - if err != nil { - return fmt.Errorf("CommitsCount: %v", err) - } - - rel, has := relMap[lowerTag] - - if !has { - rel = &Release{ - RepoID: repo.ID, - Title: "", - TagName: tags[i], - LowerTagName: lowerTag, - Target: "", - Sha1: commit.ID.String(), - NumCommits: commitsCount, - Note: "", - IsDraft: false, - IsPrerelease: false, - IsTag: true, - CreatedUnix: timeutil.TimeStamp(createdAt.Unix()), - } - if author != nil { - rel.PublisherID = author.ID - } - - newReleases = append(newReleases, rel) - } else { - rel.Sha1 = commit.ID.String() - rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix()) - rel.NumCommits = commitsCount - rel.IsDraft = false - if rel.IsTag && author != nil { - rel.PublisherID = author.ID - } - if _, err = e.ID(rel.ID).AllCols().Update(rel); err != nil { - return fmt.Errorf("Update: %v", err) - } - } - } - - if len(newReleases) > 0 { - if _, err := e.Insert(newReleases); err != nil { - return fmt.Errorf("Insert: %v", err) - } - } - - return nil -} - // SaveOrUpdateTag must be called for any push actions to add tag func SaveOrUpdateTag(repo *Repository, newRel *Release) error { rel, err := GetRelease(repo.ID, newRel.TagName) diff --git a/models/user.go b/models/user.go index ee66acf1a..fda3bb5ea 100644 --- a/models/user.go +++ b/models/user.go @@ -1452,6 +1452,11 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List { // GetUserByEmail returns the user object by given e-mail if exists. func GetUserByEmail(email string) (*User, error) { + return GetUserByEmailContext(DefaultDBContext(), email) +} + +// GetUserByEmailContext returns the user object by given e-mail if exists with db context +func GetUserByEmailContext(ctx DBContext, email string) (*User, error) { if len(email) == 0 { return nil, ErrUserNotExist{0, email, 0} } @@ -1459,7 +1464,7 @@ func GetUserByEmail(email string) (*User, error) { email = strings.ToLower(email) // First try to find the user by primary email user := &User{Email: email} - has, err := x.Get(user) + has, err := ctx.e.Get(user) if err != nil { return nil, err } @@ -1469,19 +1474,19 @@ func GetUserByEmail(email string) (*User, error) { // Otherwise, check in alternative list for activated email addresses emailAddress := &EmailAddress{Email: email, IsActivated: true} - has, err = x.Get(emailAddress) + has, err = ctx.e.Get(emailAddress) if err != nil { return nil, err } if has { - return GetUserByID(emailAddress.UID) + return getUserByID(ctx.e, emailAddress.UID) } // Finally, if email address is the protected email address: if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) user := &User{LowerName: username} - has, err := x.Get(user) + has, err := ctx.e.Get(user) if err != nil { return nil, err } diff --git a/modules/repofiles/update.go b/modules/repofiles/update.go index c0f669d68..20b83655f 100644 --- a/modules/repofiles/update.go +++ b/modules/repofiles/update.go @@ -732,7 +732,7 @@ func createCommitRepoActions(repo *models.Repository, gitRepo *git.Repository, o Commits: commits, }) } - if err := models.PushUpdateAddDeleteTags(repo, gitRepo, addTags, delTags); err != nil { + if err := repo_module.PushUpdateAddDeleteTags(repo, gitRepo, addTags, delTags); err != nil { return nil, fmt.Errorf("PushUpdateAddDeleteTags: %v", err) } return actions, nil diff --git a/modules/repository/update.go b/modules/repository/update.go new file mode 100644 index 000000000..975f577da --- /dev/null +++ b/modules/repository/update.go @@ -0,0 +1,134 @@ +// Copyright 2020 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 repository + +import ( + "fmt" + "strings" + "time" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/timeutil" +) + +// PushUpdateAddDeleteTags updates a number of added and delete tags +func PushUpdateAddDeleteTags(repo *models.Repository, gitRepo *git.Repository, addTags, delTags []string) error { + return models.WithTx(func(ctx models.DBContext) error { + if err := models.PushUpdateDeleteTagsContext(ctx, repo, delTags); err != nil { + return err + } + return pushUpdateAddTags(ctx, repo, gitRepo, addTags) + }) +} + +// pushUpdateAddTags updates a number of add tags +func pushUpdateAddTags(ctx models.DBContext, repo *models.Repository, gitRepo *git.Repository, tags []string) error { + if len(tags) == 0 { + return nil + } + + lowerTags := make([]string, 0, len(tags)) + for _, tag := range tags { + lowerTags = append(lowerTags, strings.ToLower(tag)) + } + + releases, err := models.GetReleasesByRepoIDAndNames(ctx, repo.ID, lowerTags) + if err != nil { + return fmt.Errorf("GetReleasesByRepoIDAndNames: %v", err) + } + relMap := make(map[string]*models.Release) + for _, rel := range releases { + relMap[rel.LowerTagName] = rel + } + + newReleases := make([]*models.Release, 0, len(lowerTags)-len(relMap)) + + emailToUser := make(map[string]*models.User) + + for i, lowerTag := range lowerTags { + tag, err := gitRepo.GetTag(tags[i]) + if err != nil { + return fmt.Errorf("GetTag: %v", err) + } + commit, err := tag.Commit() + if err != nil { + return fmt.Errorf("Commit: %v", err) + } + + sig := tag.Tagger + if sig == nil { + sig = commit.Author + } + if sig == nil { + sig = commit.Committer + } + var author *models.User + var createdAt = time.Unix(1, 0) + + if sig != nil { + var ok bool + author, ok = emailToUser[sig.Email] + if !ok { + author, err = models.GetUserByEmailContext(ctx, sig.Email) + if err != nil && !models.IsErrUserNotExist(err) { + return fmt.Errorf("GetUserByEmail: %v", err) + } + if author != nil { + emailToUser[sig.Email] = author + } + } + createdAt = sig.When + } + + commitsCount, err := commit.CommitsCount() + if err != nil { + return fmt.Errorf("CommitsCount: %v", err) + } + + rel, has := relMap[lowerTag] + + if !has { + rel = &models.Release{ + RepoID: repo.ID, + Title: "", + TagName: tags[i], + LowerTagName: lowerTag, + Target: "", + Sha1: commit.ID.String(), + NumCommits: commitsCount, + Note: "", + IsDraft: false, + IsPrerelease: false, + IsTag: true, + CreatedUnix: timeutil.TimeStamp(createdAt.Unix()), + } + if author != nil { + rel.PublisherID = author.ID + } + + newReleases = append(newReleases, rel) + } else { + rel.Sha1 = commit.ID.String() + rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix()) + rel.NumCommits = commitsCount + rel.IsDraft = false + if rel.IsTag && author != nil { + rel.PublisherID = author.ID + } + if err = models.UpdateRelease(ctx, rel); err != nil { + return fmt.Errorf("Update: %v", err) + } + } + } + + if len(newReleases) > 0 { + if err = models.InsertReleasesContext(ctx, newReleases); err != nil { + return fmt.Errorf("Insert: %v", err) + } + } + + return nil +} diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 6b6b22f3a..5177add99 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -420,7 +420,7 @@ func RedirectDownload(ctx *context.Context) { ) tagNames := []string{vTag} curRepo := ctx.Repo.Repository - releases, err := models.GetReleasesByRepoIDAndNames(curRepo.ID, tagNames) + releases, err := models.GetReleasesByRepoIDAndNames(models.DefaultDBContext(), curRepo.ID, tagNames) if err != nil { if models.IsErrAttachmentNotExist(err) { ctx.Error(404) diff --git a/services/release/release.go b/services/release/release.go index 0f19db9ee..cc3b98afa 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -102,7 +102,7 @@ func UpdateRelease(doer *models.User, gitRepo *git.Repository, rel *models.Relea } rel.LowerTagName = strings.ToLower(rel.TagName) - if err = models.UpdateRelease(rel); err != nil { + if err = models.UpdateRelease(models.DefaultDBContext(), rel); err != nil { return err } @@ -145,7 +145,7 @@ func DeleteReleaseByID(id int64, doer *models.User, delTag bool) error { rel.Title = "" rel.Note = "" - if err = models.UpdateRelease(rel); err != nil { + if err = models.UpdateRelease(models.DefaultDBContext(), rel); err != nil { return fmt.Errorf("Update: %v", err) } }