diff options
author | zeripath <art27@cantab.net> | 2021-10-08 14:08:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-08 15:08:22 +0200 |
commit | 001dbf100de40f19c7ade5b8f013fbcccbe09ec3 (patch) | |
tree | 0b1a57f8efbb2e941fe4c344005a70ec76ad57d1 /routers/web | |
parent | 88fa9f3fb168bc6c9c2bdc6341b83bc048b38846 (diff) | |
download | gitea-001dbf100de40f19c7ade5b8f013fbcccbe09ec3.tar.gz gitea-001dbf100de40f19c7ade5b8f013fbcccbe09ec3.zip |
Defer Last Commit Info (#16467)
One of the biggest reasons for slow repository browsing is that we wait
until last commit information has been generated for all files in the
repository.
This PR proposes deferring this generation to a new POST endpoint that
does the look up outside of the main page request.
Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'routers/web')
-rw-r--r-- | routers/web/repo/view.go | 205 | ||||
-rw-r--r-- | routers/web/web.go | 3 |
2 files changed, 156 insertions, 52 deletions
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index c0a35bcb4f..0777a10e7b 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -7,6 +7,7 @@ package repo import ( "bytes" + gocontext "context" "encoding/base64" "fmt" gotemplate "html/template" @@ -16,6 +17,7 @@ import ( "path" "strconv" "strings" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" @@ -34,11 +36,12 @@ import ( ) const ( - tplRepoEMPTY base.TplName = "repo/empty" - tplRepoHome base.TplName = "repo/home" - tplWatchers base.TplName = "repo/watchers" - tplForks base.TplName = "repo/forks" - tplMigrating base.TplName = "repo/migrate/migrating" + tplRepoEMPTY base.TplName = "repo/empty" + tplRepoHome base.TplName = "repo/home" + tplRepoViewList base.TplName = "repo/view_list" + tplWatchers base.TplName = "repo/watchers" + tplForks base.TplName = "repo/forks" + tplMigrating base.TplName = "repo/migrate/migrating" ) type namedBlob struct { @@ -128,28 +131,8 @@ func getReadmeFileFromPath(commit *git.Commit, treePath string) (*namedBlob, err } func renderDirectory(ctx *context.Context, treeLink string) { - tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) - if err != nil { - ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) - return - } - - entries, err := tree.ListEntries() - if err != nil { - ctx.ServerError("ListEntries", err) - return - } - entries.CustomSort(base.NaturalSortLess) - - var c *git.LastCommitCache - if setting.CacheService.LastCommit.Enabled && ctx.Repo.CommitsCount >= setting.CacheService.LastCommit.CommitsCount { - c = git.NewLastCommitCache(ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache()) - } - - var latestCommit *git.Commit - ctx.Data["Files"], latestCommit, err = entries.GetCommitsInfo(ctx, ctx.Repo.Commit, ctx.Repo.TreePath, c) - if err != nil { - ctx.ServerError("GetCommitsInfo", err) + entries := renderDirectoryFiles(ctx, 1*time.Second) + if ctx.Written() { return } @@ -186,6 +169,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { isSymlink := entry.IsLink() target := entry if isSymlink { + var err error target, err = entry.FollowLinks() if err != nil && !git.IsErrBadLink(err) { ctx.ServerError("FollowLinks", err) @@ -207,6 +191,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { name := entry.Name() isSymlink := entry.IsLink() if isSymlink { + var err error entry, err = entry.FollowLinks() if err != nil && !git.IsErrBadLink(err) { ctx.ServerError("FollowLinks", err) @@ -237,6 +222,7 @@ func renderDirectory(ctx *context.Context, treeLink string) { if entry == nil { continue } + var err error readmeFile, err = getReadmeFileFromPath(ctx.Repo.Commit, entry.GetSubJumpablePathName()) if err != nil { ctx.ServerError("getReadmeFileFromPath", err) @@ -365,34 +351,12 @@ func renderDirectory(ctx *context.Context, treeLink string) { } } - // Show latest commit info of repository in table header, - // or of directory if not in root directory. - ctx.Data["LatestCommit"] = latestCommit - verification := models.ParseCommitWithSignature(latestCommit) - - if err := models.CalculateTrustStatus(verification, ctx.Repo.Repository, nil); err != nil { - ctx.ServerError("CalculateTrustStatus", err) - return - } - ctx.Data["LatestCommitVerification"] = verification - - ctx.Data["LatestCommitUser"] = models.ValidateCommitWithEmail(latestCommit) - - statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, ctx.Repo.Commit.ID.String(), db.ListOptions{}) - if err != nil { - log.Error("GetLatestCommitStatus: %v", err) - } - - ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(statuses) - ctx.Data["LatestCommitStatuses"] = statuses - // Check permission to add or upload new file. if ctx.Repo.CanWrite(models.UnitTypeCode) && ctx.Repo.IsViewBranch { ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived } - ctx.Data["SSHDomain"] = setting.SSH.Domain } func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink string) { @@ -614,8 +578,7 @@ func safeURL(address string) string { return u.String() } -// Home render repository home page -func Home(ctx *context.Context) { +func checkHomeCodeViewable(ctx *context.Context) { if len(ctx.Repo.Units) > 0 { if ctx.Repo.Repository.IsBeingCreated() { task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) @@ -648,7 +611,6 @@ func Home(ctx *context.Context) { var firstUnit *models.Unit for _, repoUnit := range ctx.Repo.Units { if repoUnit.Type == models.UnitTypeCode { - renderCode(ctx) return } @@ -667,6 +629,145 @@ func Home(ctx *context.Context) { ctx.NotFound("Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo"))) } +// Home render repository home page +func Home(ctx *context.Context) { + checkHomeCodeViewable(ctx) + if ctx.Written() { + return + } + + renderCode(ctx) +} + +// LastCommit returns lastCommit data for the provided branch/tag/commit and directory (in url) and filenames in body +func LastCommit(ctx *context.Context) { + checkHomeCodeViewable(ctx) + if ctx.Written() { + return + } + + renderDirectoryFiles(ctx, 0) + if ctx.Written() { + return + } + + var treeNames []string + paths := make([]string, 0, 5) + if len(ctx.Repo.TreePath) > 0 { + treeNames = strings.Split(ctx.Repo.TreePath, "/") + for i := range treeNames { + paths = append(paths, strings.Join(treeNames[:i+1], "/")) + } + + ctx.Data["HasParentPath"] = true + if len(paths)-2 >= 0 { + ctx.Data["ParentPath"] = "/" + paths[len(paths)-2] + } + } + branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL() + ctx.Data["BranchLink"] = branchLink + + ctx.HTML(http.StatusOK, tplRepoViewList) +} + +func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entries { + tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + if err != nil { + ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) + return nil + } + + ctx.Data["LastCommitLoaderURL"] = ctx.Repo.RepoLink + "/lastcommit/" + ctx.Repo.CommitID + "/" + ctx.Repo.TreePath + + // Get current entry user currently looking at. + entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) + if err != nil { + ctx.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) + return nil + } + + if !entry.IsDir() { + ctx.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) + return nil + } + + allEntries, err := tree.ListEntries() + if err != nil { + ctx.ServerError("ListEntries", err) + return nil + } + allEntries.CustomSort(base.NaturalSortLess) + + commitInfoCtx := gocontext.Context(ctx) + if timeout > 0 { + var cancel gocontext.CancelFunc + commitInfoCtx, cancel = gocontext.WithTimeout(ctx, timeout) + defer cancel() + } + + var c *git.LastCommitCache + if setting.CacheService.LastCommit.Enabled && ctx.Repo.CommitsCount >= setting.CacheService.LastCommit.CommitsCount { + c = git.NewLastCommitCache(ctx.Repo.Repository.FullName(), ctx.Repo.GitRepo, setting.LastCommitCacheTTLSeconds, cache.GetCache()) + } + + selected := map[string]bool{} + for _, pth := range ctx.FormStrings("f[]") { + selected[pth] = true + } + + entries := allEntries + if len(selected) > 0 { + entries = make(git.Entries, 0, len(selected)) + for _, entry := range allEntries { + if selected[entry.Name()] { + entries = append(entries, entry) + } + } + } + + var latestCommit *git.Commit + ctx.Data["Files"], latestCommit, err = entries.GetCommitsInfo(commitInfoCtx, ctx.Repo.Commit, ctx.Repo.TreePath, c) + if err != nil { + ctx.ServerError("GetCommitsInfo", err) + return nil + } + + // Show latest commit info of repository in table header, + // or of directory if not in root directory. + ctx.Data["LatestCommit"] = latestCommit + if latestCommit != nil { + + verification := models.ParseCommitWithSignature(latestCommit) + + if err := models.CalculateTrustStatus(verification, ctx.Repo.Repository, nil); err != nil { + ctx.ServerError("CalculateTrustStatus", err) + return nil + } + ctx.Data["LatestCommitVerification"] = verification + ctx.Data["LatestCommitUser"] = models.ValidateCommitWithEmail(latestCommit) + } + + statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, ctx.Repo.Commit.ID.String(), db.ListOptions{}) + if err != nil { + log.Error("GetLatestCommitStatus: %v", err) + } + + ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(statuses) + ctx.Data["LatestCommitStatuses"] = statuses + + branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL() + treeLink := branchLink + + if len(ctx.Repo.TreePath) > 0 { + treeLink += "/" + ctx.Repo.TreePath + } + + ctx.Data["TreeLink"] = treeLink + ctx.Data["SSHDomain"] = setting.SSH.Domain + + return allEntries +} + func renderLanguageStats(ctx *context.Context) { langs, err := ctx.Repo.Repository.GetTopLanguageStats(5) if err != nil { diff --git a/routers/web/web.go b/routers/web/web.go index e12552f4d4..01d90d206f 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -995,6 +995,9 @@ func RegisterRoutes(m *web.Route) { m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff) }, ignSignIn, context.RepoAssignment, context.UnitTypes()) + + m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit) + m.Group("/{username}/{reponame}", func() { m.Get("/stars", repo.Stars) m.Get("/watchers", repo.Watchers) |