mirror of
https://github.com/gogs/gogs.git
synced 2025-12-20 15:20:01 +01:00
release: improve page load performance
Previously, we load all releases of a repository which could hurt performance when the repository has a lot of releases. Now we're able to only load releases in current page view we need to show by matching with 'tag_name'.
This commit is contained in:
2
gogs.go
2
gogs.go
@@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VER = "0.10.12.0309"
|
const APP_VER = "0.10.12.0310"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
setting.AppVer = APP_VER
|
setting.AppVer = APP_VER
|
||||||
|
|||||||
@@ -51,6 +51,26 @@ func (r *Release) AfterSet(colName string, _ xorm.Cell) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Release) loadAttributes(e Engine) (err error) {
|
||||||
|
if r.Publisher == nil {
|
||||||
|
r.Publisher, err = getUserByID(e, r.PublisherID)
|
||||||
|
if err != nil {
|
||||||
|
if IsErrUserNotExist(err) {
|
||||||
|
r.PublisherID = -1
|
||||||
|
r.Publisher = NewGhostUser()
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("getUserByID.(Publisher) [%d]: %v", r.PublisherID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Release) LoadAttributes() error {
|
||||||
|
return r.loadAttributes(x)
|
||||||
|
}
|
||||||
|
|
||||||
// IsReleaseExist returns true if release with given tag name already exists.
|
// IsReleaseExist returns true if release with given tag name already exists.
|
||||||
func IsReleaseExist(repoID int64, tagName string) (bool, error) {
|
func IsReleaseExist(repoID int64, tagName string) (bool, error) {
|
||||||
if len(tagName) == 0 {
|
if len(tagName) == 0 {
|
||||||
@@ -60,31 +80,31 @@ func IsReleaseExist(repoID int64, tagName string) (bool, error) {
|
|||||||
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
|
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTag(gitRepo *git.Repository, rel *Release) error {
|
func createTag(gitRepo *git.Repository, r *Release) error {
|
||||||
// Only actual create when publish.
|
// Only actual create when publish.
|
||||||
if !rel.IsDraft {
|
if !r.IsDraft {
|
||||||
if !gitRepo.IsTagExist(rel.TagName) {
|
if !gitRepo.IsTagExist(r.TagName) {
|
||||||
commit, err := gitRepo.GetBranchCommit(rel.Target)
|
commit, err := gitRepo.GetBranchCommit(r.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetBranchCommit: %v", err)
|
return fmt.Errorf("GetBranchCommit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim '--' prefix to prevent command line argument vulnerability.
|
// Trim '--' prefix to prevent command line argument vulnerability.
|
||||||
rel.TagName = strings.TrimPrefix(rel.TagName, "--")
|
r.TagName = strings.TrimPrefix(r.TagName, "--")
|
||||||
if err = gitRepo.CreateTag(rel.TagName, commit.ID.String()); err != nil {
|
if err = gitRepo.CreateTag(r.TagName, commit.ID.String()); err != nil {
|
||||||
if strings.Contains(err.Error(), "is not a valid tag name") {
|
if strings.Contains(err.Error(), "is not a valid tag name") {
|
||||||
return ErrInvalidTagName{rel.TagName}
|
return ErrInvalidTagName{r.TagName}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
commit, err := gitRepo.GetTagCommit(rel.TagName)
|
commit, err := gitRepo.GetTagCommit(r.TagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetTagCommit: %v", err)
|
return fmt.Errorf("GetTagCommit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rel.Sha1 = commit.ID.String()
|
r.Sha1 = commit.ID.String()
|
||||||
rel.NumCommits, err = commit.CommitsCount()
|
r.NumCommits, err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("CommitsCount: %v", err)
|
return fmt.Errorf("CommitsCount: %v", err)
|
||||||
}
|
}
|
||||||
@@ -94,19 +114,19 @@ func createTag(gitRepo *git.Repository, rel *Release) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateRelease creates a new release of repository.
|
// CreateRelease creates a new release of repository.
|
||||||
func CreateRelease(gitRepo *git.Repository, rel *Release) error {
|
func CreateRelease(gitRepo *git.Repository, r *Release) error {
|
||||||
isExist, err := IsReleaseExist(rel.RepoID, rel.TagName)
|
isExist, err := IsReleaseExist(r.RepoID, r.TagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if isExist {
|
} else if isExist {
|
||||||
return ErrReleaseAlreadyExist{rel.TagName}
|
return ErrReleaseAlreadyExist{r.TagName}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = createTag(gitRepo, rel); err != nil {
|
if err = createTag(gitRepo, r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rel.LowerTagName = strings.ToLower(rel.TagName)
|
r.LowerTagName = strings.ToLower(r.TagName)
|
||||||
_, err = x.InsertOne(rel)
|
_, err = x.InsertOne(r)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,53 +139,68 @@ func GetRelease(repoID int64, tagName string) (*Release, error) {
|
|||||||
return nil, ErrReleaseNotExist{0, tagName}
|
return nil, ErrReleaseNotExist{0, tagName}
|
||||||
}
|
}
|
||||||
|
|
||||||
rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}
|
r := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}
|
||||||
_, err = x.Get(rel)
|
if _, err = x.Get(r); err != nil {
|
||||||
return rel, err
|
return nil, fmt.Errorf("Get: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, r.LoadAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReleaseByID returns release with given ID.
|
// GetReleaseByID returns release with given ID.
|
||||||
func GetReleaseByID(id int64) (*Release, error) {
|
func GetReleaseByID(id int64) (*Release, error) {
|
||||||
rel := new(Release)
|
r := new(Release)
|
||||||
has, err := x.Id(id).Get(rel)
|
has, err := x.Id(id).Get(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, ErrReleaseNotExist{id, ""}
|
return nil, ErrReleaseNotExist{id, ""}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rel, nil
|
return r, r.LoadAttributes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReleasesByRepoID returns a list of releases of repository.
|
// GetPublishedReleasesByRepoID returns a list of published releases of repository.
|
||||||
func GetReleasesByRepoID(repoID int64) (rels []*Release, err error) {
|
// If matches is not empty, only published releases in matches will be returned.
|
||||||
err = x.Desc("created_unix").Find(&rels, Release{RepoID: repoID})
|
// In any case, drafts won't be returned by this function.
|
||||||
return rels, err
|
func GetPublishedReleasesByRepoID(repoID int64, matches ...string) ([]*Release, error) {
|
||||||
|
sess := x.Where("repo_id = ?", repoID).And("is_draft = ?", false).Desc("created_unix")
|
||||||
|
if len(matches) > 0 {
|
||||||
|
sess.In("tag_name", matches)
|
||||||
|
}
|
||||||
|
releases := make([]*Release, 0, 5)
|
||||||
|
return releases, sess.Find(&releases, new(Release))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDraftReleasesByRepoID returns all draft releases of repository.
|
||||||
|
func GetDraftReleasesByRepoID(repoID int64) ([]*Release, error) {
|
||||||
|
releases := make([]*Release, 0)
|
||||||
|
return releases, x.Where("repo_id = ?", repoID).And("is_draft = ?", true).Find(&releases)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReleaseSorter struct {
|
type ReleaseSorter struct {
|
||||||
rels []*Release
|
releases []*Release
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *ReleaseSorter) Len() int {
|
func (rs *ReleaseSorter) Len() int {
|
||||||
return len(rs.rels)
|
return len(rs.releases)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *ReleaseSorter) Less(i, j int) bool {
|
func (rs *ReleaseSorter) Less(i, j int) bool {
|
||||||
diffNum := rs.rels[i].NumCommits - rs.rels[j].NumCommits
|
diffNum := rs.releases[i].NumCommits - rs.releases[j].NumCommits
|
||||||
if diffNum != 0 {
|
if diffNum != 0 {
|
||||||
return diffNum > 0
|
return diffNum > 0
|
||||||
}
|
}
|
||||||
return rs.rels[i].Created.After(rs.rels[j].Created)
|
return rs.releases[i].Created.After(rs.releases[j].Created)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rs *ReleaseSorter) Swap(i, j int) {
|
func (rs *ReleaseSorter) Swap(i, j int) {
|
||||||
rs.rels[i], rs.rels[j] = rs.rels[j], rs.rels[i]
|
rs.releases[i], rs.releases[j] = rs.releases[j], rs.releases[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SortReleases sorts releases by number of commits and created time.
|
// SortReleases sorts releases by number of commits and created time.
|
||||||
func SortReleases(rels []*Release) {
|
func SortReleases(rels []*Release) {
|
||||||
sorter := &ReleaseSorter{rels: rels}
|
sorter := &ReleaseSorter{releases: rels}
|
||||||
sort.Sort(sorter)
|
sort.Sort(sorter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,36 +59,27 @@ func Releases(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: should only get releases match tags result and drafts.
|
releases, err := models.GetPublishedReleasesByRepoID(ctx.Repo.Repository.ID, tagsResult.Tags...)
|
||||||
releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(500, "GetReleasesByRepoID", err)
|
ctx.Handle(500, "GetPublishedReleasesByRepoID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temproray cache commits count of used branches to speed up.
|
// Temproray cache commits count of used branches to speed up.
|
||||||
countCache := make(map[string]int64)
|
countCache := make(map[string]int64)
|
||||||
|
|
||||||
drafts := make([]*models.Release, 0, 1)
|
results := make([]*models.Release, len(tagsResult.Tags))
|
||||||
tags := make([]*models.Release, len(tagsResult.Tags))
|
|
||||||
for i, rawTag := range tagsResult.Tags {
|
for i, rawTag := range tagsResult.Tags {
|
||||||
for j, r := range releases {
|
for j, r := range releases {
|
||||||
if r == nil ||
|
if r == nil || r.TagName != rawTag {
|
||||||
(r.IsDraft && !ctx.Repo.IsOwner()) ||
|
|
||||||
(!r.IsDraft && r.TagName != rawTag) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
releases[j] = nil // Mark as used.
|
releases[j] = nil // Mark as used.
|
||||||
|
|
||||||
r.Publisher, err = models.GetUserByID(r.PublisherID)
|
if err = r.LoadAttributes(); err != nil {
|
||||||
if err != nil {
|
ctx.Handle(500, "LoadAttributes", err)
|
||||||
if models.IsErrUserNotExist(err) {
|
|
||||||
r.Publisher = models.NewGhostUser()
|
|
||||||
} else {
|
|
||||||
ctx.Handle(500, "GetUserByID", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
|
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
|
||||||
ctx.Handle(500, "calReleaseNumCommitsBehind", err)
|
ctx.Handle(500, "calReleaseNumCommitsBehind", err)
|
||||||
@@ -96,49 +87,68 @@ func Releases(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.Note = markdown.RenderString(r.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
|
r.Note = markdown.RenderString(r.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
|
||||||
if r.TagName == rawTag {
|
results[i] = r
|
||||||
tags[i] = r
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.IsDraft {
|
// No published release matches this tag
|
||||||
drafts = append(drafts, r)
|
if results[i] == nil {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if tags[i] == nil {
|
|
||||||
commit, err := ctx.Repo.GitRepo.GetTagCommit(rawTag)
|
commit, err := ctx.Repo.GitRepo.GetTagCommit(rawTag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(500, "GetTagCommit", err)
|
ctx.Handle(500, "GetTagCommit", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags[i] = &models.Release{
|
results[i] = &models.Release{
|
||||||
Title: rawTag,
|
Title: rawTag,
|
||||||
TagName: rawTag,
|
TagName: rawTag,
|
||||||
Sha1: commit.ID.String(),
|
Sha1: commit.ID.String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
tags[i].NumCommits, err = commit.CommitsCount()
|
results[i].NumCommits, err = commit.CommitsCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(500, "CommitsCount", err)
|
ctx.Handle(500, "CommitsCount", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tags[i].NumCommitsBehind = ctx.Repo.CommitsCount - tags[i].NumCommits
|
results[i].NumCommitsBehind = ctx.Repo.CommitsCount - results[i].NumCommits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
models.SortReleases(results)
|
||||||
|
|
||||||
|
// Only show drafts if user is viewing the latest page
|
||||||
|
var drafts []*models.Release
|
||||||
|
if tagsResult.HasLatest {
|
||||||
|
drafts, err = models.GetDraftReleasesByRepoID(ctx.Repo.Repository.ID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetDraftReleasesByRepoID", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range drafts {
|
||||||
|
if err = r.LoadAttributes(); err != nil {
|
||||||
|
ctx.Handle(500, "LoadAttributes", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
|
||||||
|
ctx.Handle(500, "calReleaseNumCommitsBehind", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Note = markdown.RenderString(r.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(drafts) > 0 {
|
||||||
|
results = append(drafts, results...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
models.SortReleases(tags)
|
ctx.Data["Releases"] = results
|
||||||
if len(drafts) > 0 && tagsResult.HasLatest {
|
|
||||||
tags = append(drafts, tags...)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Releases"] = tags
|
|
||||||
ctx.Data["HasPrevious"] = !tagsResult.HasLatest
|
ctx.Data["HasPrevious"] = !tagsResult.HasLatest
|
||||||
ctx.Data["ReachEnd"] = tagsResult.ReachEnd
|
ctx.Data["ReachEnd"] = tagsResult.ReachEnd
|
||||||
ctx.Data["PreviousAfter"] = tagsResult.PreviousAfter
|
ctx.Data["PreviousAfter"] = tagsResult.PreviousAfter
|
||||||
if len(tags) > 0 {
|
if len(results) > 0 {
|
||||||
ctx.Data["NextAfter"] = tags[len(tags)-1].TagName
|
ctx.Data["NextAfter"] = results[len(results)-1].TagName
|
||||||
}
|
}
|
||||||
ctx.HTML(200, RELEASES)
|
ctx.HTML(200, RELEASES)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.10.12.0309
|
0.10.12.0310
|
||||||
2
vendor/github.com/gogits/git-module/git.go
generated
vendored
2
vendor/github.com/gogits/git-module/git.go
generated
vendored
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const _VERSION = "0.4.12"
|
const _VERSION = "0.4.13"
|
||||||
|
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return _VERSION
|
return _VERSION
|
||||||
|
|||||||
2
vendor/github.com/gogits/git-module/repo_tag.go
generated
vendored
2
vendor/github.com/gogits/git-module/repo_tag.go
generated
vendored
@@ -171,7 +171,7 @@ func (repo *Repository) GetTagsAfter(after string, limit int) (*TagsResult, erro
|
|||||||
}
|
}
|
||||||
if allTags[i] == after {
|
if allTags[i] == after {
|
||||||
hasMatch = true
|
hasMatch = true
|
||||||
if limit > 0 && i-limit > 0 {
|
if limit > 0 && i-limit >= 0 {
|
||||||
previousAfter = allTags[i-limit]
|
previousAfter = allTags[i-limit]
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|||||||
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@@ -159,10 +159,10 @@
|
|||||||
"revisionTime": "2016-08-10T03:50:02Z"
|
"revisionTime": "2016-08-10T03:50:02Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "RnWB5UDcTpSGepvWnwic1SyRZrc=",
|
"checksumSHA1": "sygMoTVpNmOTbsnZbgLR904p5GE=",
|
||||||
"path": "github.com/gogits/git-module",
|
"path": "github.com/gogits/git-module",
|
||||||
"revision": "1b9552bab7499e5cbd96f6b550aaa0038faf6b67",
|
"revision": "2c083b82191752340c76271876671e18130ad662",
|
||||||
"revisionTime": "2017-02-19T18:16:29Z"
|
"revisionTime": "2017-03-10T19:06:55Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "Rvj0LCHGhFQyIM7MzBPt1iRP89c=",
|
"checksumSHA1": "Rvj0LCHGhFQyIM7MzBPt1iRP89c=",
|
||||||
|
|||||||
Reference in New Issue
Block a user