From e2cc85374f7ad3976861483786f6fe552ca02f10 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 13 Jan 2025 00:26:58 -0800 Subject: [PATCH] refactor ref type --- modules/git/ref.go | 15 ++++++ routers/web/repo/find.go | 3 +- routers/web/web.go | 69 ++++++++++++------------ services/context/repo.go | 114 ++++++++++++++++++++++++--------------- templates/repo/home.tmpl | 2 +- 5 files changed, 122 insertions(+), 81 deletions(-) diff --git a/modules/git/ref.go b/modules/git/ref.go index f20a175e422a8..0ac6094e3da53 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -7,6 +7,7 @@ import ( "regexp" "strings" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -84,6 +85,20 @@ func RefNameFromCommit(shortName string) RefName { return RefName(shortName) } +func RefNameFromTypeAndShortName(tp RefType, shortName string) RefName { + switch tp { + case RefTypeBranch: + return RefNameFromBranch(shortName) + case RefTypeTag: + return RefNameFromTag(shortName) + case RefTypeCommit: + return RefNameFromCommit(shortName) + default: + setting.PanicInDevOrTesting("Unknown RefType: %v", tp) + return "" + } +} + func (ref RefName) String() string { return string(ref) } diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go index 3a3a7610e772b..530d75ff1b151 100644 --- a/routers/web/repo/find.go +++ b/routers/web/repo/find.go @@ -19,6 +19,7 @@ const ( func FindFiles(ctx *context.Context) { path := ctx.PathParam("*") ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + util.PathEscapeSegments(path) - ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) + ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) + + "?ref_type=" + ctx.FormTrim("ref_type") + "&ref_name=" + ctx.FormTrim("ref_name") ctx.HTML(http.StatusOK, tplFindFiles) } diff --git a/routers/web/web.go b/routers/web/web.go index 2f7ee8ade76fa..30a0c74f7a5f5 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/metrics" "code.gitea.io/gitea/modules/public" @@ -1156,11 +1157,9 @@ func registerRoutes(m *web.Router) { m.Group("/{username}/{reponame}", func() { m.Get("/find/*", repo.FindFiles) - m.Group("/tree-list", func() { - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.TreeList) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.TreeList) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.TreeList) - }) + m.Get("/find", repo.FindFiles) + m.Get("/tree-list/*", context.RepoRefByQueries(), repo.TreeList) + m.Get("/tree-list", context.RepoRefByQueries(), repo.TreeList) m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff) m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists). Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff). @@ -1313,9 +1312,9 @@ func registerRoutes(m *web.Router) { m.Group("/branches", func() { m.Group("/_new", func() { - m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch) - m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch) - m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch) + m.Post("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.CreateBranch) + m.Post("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.CreateBranch) + m.Post("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.CreateBranch) }, web.Bind(forms.NewBranchForm{})) m.Post("/delete", repo.DeleteBranchPost) m.Post("/restore", repo.RestoreBranchPost) @@ -1334,7 +1333,7 @@ func registerRoutes(m *web.Router) { m.Get(".rss", feedEnabled, repo.TagsListFeedRSS) m.Get(".atom", feedEnabled, repo.TagsListFeedAtom) }, ctxDataSet("EnableFeed", setting.Other.EnableFeed), - repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true})) + repo.MustBeNotEmpty, context.RepoRefByType(git.RefTypeTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true})) m.Post("/tags/delete", repo.DeleteTag, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef()) }, optSignIn, context.RepoAssignment, reqRepoCodeReader) @@ -1348,7 +1347,7 @@ func registerRoutes(m *web.Router) { m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS) m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom) }, ctxDataSet("EnableFeed", setting.Other.EnableFeed), - repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true})) + repo.MustBeNotEmpty, context.RepoRefByType(git.RefTypeTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true})) m.Get("/releases/attachments/{uuid}", repo.MustBeNotEmpty, repo.GetAttachment) m.Get("/releases/download/{vTag}/{fileName}", repo.MustBeNotEmpty, repo.RedirectDownload) m.Group("/releases", func() { @@ -1521,42 +1520,42 @@ func registerRoutes(m *web.Router) { }, repo.MustBeNotEmpty, context.RepoRef()) m.Group("/media", func() { - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownloadOrLFS) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownloadOrLFS) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownloadOrLFS) + m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.SingleDownloadOrLFS) + m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.SingleDownloadOrLFS) + m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.SingleDownloadOrLFS) m.Get("/blob/{sha}", repo.DownloadByIDOrLFS) // "/*" route is deprecated, and kept for backward compatibility - m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.SingleDownloadOrLFS) + m.Get("/*", context.RepoRefByType(""), repo.SingleDownloadOrLFS) }, repo.MustBeNotEmpty) m.Group("/raw", func() { - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownload) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownload) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownload) + m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.SingleDownload) + m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.SingleDownload) + m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.SingleDownload) m.Get("/blob/{sha}", repo.DownloadByID) // "/*" route is deprecated, and kept for backward compatibility - m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.SingleDownload) + m.Get("/*", context.RepoRefByType(""), repo.SingleDownload) }, repo.MustBeNotEmpty) m.Group("/render", func() { - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile) + m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RenderFile) + m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.RenderFile) + m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.RenderFile) m.Get("/blob/{sha}", repo.RenderFile) }, repo.MustBeNotEmpty) m.Group("/commits", func() { - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits) + m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RefCommits) + m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.RefCommits) + m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.RefCommits) // "/*" route is deprecated, and kept for backward compatibility - m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.RefCommits) + m.Get("/*", context.RepoRefByType(""), repo.RefCommits) }, repo.MustBeNotEmpty) m.Group("/blame", func() { - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefBlame) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefBlame) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefBlame) + m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RefBlame) + m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.RefBlame) + m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.RefBlame) }, repo.MustBeNotEmpty) m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) @@ -1568,20 +1567,20 @@ func registerRoutes(m *web.Router) { m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick) }, repo.MustBeNotEmpty, context.RepoRef()) - m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) - m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed) + m.Get("/rss/branch/*", context.RepoRefByType(git.RefTypeBranch), feedEnabled, feed.RenderBranchFeed) + m.Get("/atom/branch/*", context.RepoRefByType(git.RefTypeBranch), feedEnabled, feed.RenderBranchFeed) m.Group("/src", func() { m.Get("", func(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink) }) // there is no "{owner}/{repo}/src" page, so redirect to "{owner}/{repo}" to avoid 404 - m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home) - m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home) - m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.Home) - m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.Home) // "/*" route is deprecated, and kept for backward compatibility + m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.Home) + m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.Home) + m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.Home) + m.Get("/*", context.RepoRefByType(""), repo.Home) // "/*" route is deprecated, and kept for backward compatibility }, repo.SetEditorconfigIfExists) m.Get("/forks", context.RepoRef(), repo.Forks) m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff) - m.Post("/lastcommit/*", context.RepoRefByType(context.RepoRefCommit), repo.LastCommit) + m.Post("/lastcommit/*", context.RepoRefByType(git.RefTypeCommit), repo.LastCommit) }, optSignIn, context.RepoAssignment, reqRepoCodeReader) // end "/{username}/{reponame}": repo code diff --git a/services/context/repo.go b/services/context/repo.go index cd5ac7c6c9ba1..21aeca5111db4 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -677,24 +677,13 @@ func RepoAssignment(ctx *Context) { } } -// RepoRefType type of repo reference -type RepoRefType int - -const ( - // RepoRefUnknown is for legacy support, makes the code to "guess" the ref type - RepoRefUnknown RepoRefType = iota - RepoRefBranch - RepoRefTag - RepoRefCommit -) - const headRefName = "HEAD" // RepoRef handles repository reference names when the ref name is not // explicitly given func RepoRef() func(*Context) { // since no ref name is explicitly specified, ok to just use branch - return RepoRefByType(RepoRefBranch) + return RepoRefByType(git.RefTypeBranch) } func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string { @@ -710,29 +699,29 @@ func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool return "" } -func getRefNameLegacy(ctx *Base, repo *Repository, reqPath, extraRef string) (string, RepoRefType) { +func getRefNameLegacy(ctx *Base, repo *Repository, reqPath, extraRef string) (string, git.RefType) { reqRefPath := path.Join(extraRef, reqPath) reqRefPathParts := strings.Split(reqRefPath, "/") - if refName := getRefName(ctx, repo, reqRefPath, RepoRefBranch); refName != "" { - return refName, RepoRefBranch + if refName := getRefName(ctx, repo, reqRefPath, git.RefTypeBranch); refName != "" { + return refName, git.RefTypeBranch } - if refName := getRefName(ctx, repo, reqRefPath, RepoRefTag); refName != "" { - return refName, RepoRefTag + if refName := getRefName(ctx, repo, reqRefPath, git.RefTypeTag); refName != "" { + return refName, git.RefTypeTag } if git.IsStringLikelyCommitID(git.ObjectFormatFromName(repo.Repository.ObjectFormatName), reqRefPathParts[0]) { // FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists repo.TreePath = strings.Join(reqRefPathParts[1:], "/") - return reqRefPathParts[0], RepoRefCommit + return reqRefPathParts[0], git.RefTypeCommit } // FIXME: the old code falls back to default branch if "ref" doesn't exist, there could be an edge case: // "README?ref=no-such" would read the README file from the default branch, but the user might expect a 404 repo.TreePath = reqPath - return repo.Repository.DefaultBranch, RepoRefBranch + return repo.Repository.DefaultBranch, git.RefTypeBranch } -func getRefName(ctx *Base, repo *Repository, path string, pathType RepoRefType) string { - switch pathType { - case RepoRefBranch: +func getRefName(ctx *Base, repo *Repository, path string, refType git.RefType) string { + switch refType { + case git.RefTypeBranch: ref := getRefNameFromPath(repo, path, repo.GitRepo.IsBranchExist) if len(ref) == 0 { // check if ref is HEAD @@ -762,9 +751,9 @@ func getRefName(ctx *Base, repo *Repository, path string, pathType RepoRefType) } return ref - case RepoRefTag: + case git.RefTypeTag: return getRefNameFromPath(repo, path, repo.GitRepo.IsTagExist) - case RepoRefCommit: + case git.RefTypeCommit: parts := strings.Split(path, "/") if git.IsStringLikelyCommitID(repo.GetObjectFormat(), parts[0], 7) { // FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists @@ -782,7 +771,7 @@ func getRefName(ctx *Base, repo *Repository, path string, pathType RepoRefType) return commit.ID.String() } default: - panic(fmt.Sprintf("Unrecognized path type: %v", pathType)) + panic(fmt.Sprintf("Unrecognized ref type: %v", refType)) } return "" } @@ -791,23 +780,9 @@ type RepoRefByTypeOptions struct { IgnoreNotExistErr bool } -func repoRefFullName(shortName string, typ RepoRefType) git.RefName { - switch typ { - case RepoRefBranch: - return git.RefNameFromBranch(shortName) - case RepoRefTag: - return git.RefNameFromTag(shortName) - case RepoRefCommit: - return git.RefNameFromCommit(shortName) - default: - setting.PanicInDevOrTesting("Unknown RepoRefType: %v", typ) - return git.RefNameFromBranch("main") // just a dummy result, it shouldn't happen - } -} - // RepoRefByType handles repository reference name for a specific type // of repository reference -func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func(*Context) { +func RepoRefByType(detectRefType git.RefType, opts ...RepoRefByTypeOptions) func(*Context) { opt := util.OptionalArg(opts) return func(ctx *Context) { var err error @@ -861,13 +836,13 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func } ctx.Repo.IsViewBranch = true } else { // there is a path in request - guessLegacyPath := refType == RepoRefUnknown + guessLegacyPath := refType == "" if guessLegacyPath { refShortName, refType = getRefNameLegacy(ctx.Base, ctx.Repo, reqPath, "") } else { refShortName = getRefName(ctx.Base, ctx.Repo, reqPath, refType) } - ctx.Repo.RefFullName = repoRefFullName(refShortName, refType) + ctx.Repo.RefFullName = git.RefNameFromTypeAndShortName(refType, refShortName) isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool) if isRenamedBranch && has { renamedBranchName := ctx.Data["RenamedBranchName"].(string) @@ -877,7 +852,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func return } - if refType == RepoRefBranch && ctx.Repo.GitRepo.IsBranchExist(refShortName) { + if refType == git.RefTypeBranch && ctx.Repo.GitRepo.IsBranchExist(refShortName) { ctx.Repo.IsViewBranch = true ctx.Repo.BranchName = refShortName ctx.Repo.RefFullName = git.RefNameFromBranch(refShortName) @@ -888,7 +863,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if refType == RepoRefTag && ctx.Repo.GitRepo.IsTagExist(refShortName) { + } else if refType == git.RefTypeTag && ctx.Repo.GitRepo.IsTagExist(refShortName) { ctx.Repo.IsViewTag = true ctx.Repo.RefFullName = git.RefNameFromTag(refShortName) ctx.Repo.TagName = refShortName @@ -964,6 +939,57 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func } } +func RepoRefByQueries() func(ctx *Context) { + return func(ctx *Context) { + if ctx.Repo.Repository.IsEmpty { + // assume the user is viewing the (non-existent) default branch + ctx.Repo.IsViewBranch = true + ctx.Repo.BranchName = ctx.Repo.Repository.DefaultBranch + ctx.Repo.RefFullName = git.RefNameFromBranch(ctx.Repo.BranchName) + return + } + + var err error + if ctx.Repo.GitRepo == nil { + ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx.Repo.Repository) + if err != nil { + ctx.ServerError(fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err) + return + } + } + + ctx.Repo.RefFullName = git.RefNameFromTypeAndShortName(git.RefType(ctx.FormTrim("ref_type")), ctx.FormTrim("ref_name")) + if ctx.Repo.RefFullName == "" { + ctx.Error(http.StatusBadRequest, "invalid ref type or name") + return + } + + switch ctx.Repo.RefFullName.RefType() { + case git.RefTypeBranch: + ctx.Repo.IsViewBranch = true + ctx.Repo.BranchName = ctx.Repo.RefFullName.ShortName() + case git.RefTypeTag: + ctx.Repo.IsViewTag = true + ctx.Repo.TagName = ctx.Repo.RefFullName.ShortName() + case git.RefTypeCommit: + ctx.Repo.IsViewCommit = true + ctx.Repo.CommitID = ctx.Repo.RefFullName.ShortName() + } + + ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(ctx.Repo.RefFullName.String()) + if err != nil { + if git.IsErrNotExist(err) { + ctx.NotFound("GetCommit", err) + } else { + ctx.ServerError("GetCommit", err) + } + return + } + ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() + ctx.Repo.TreePath = ctx.PathParam("*") + } +} + // GitHookService checks if repository Git hooks service has been enabled. func GitHookService() func(ctx *Context) { return func(ctx *Context) { diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 86ad1629085a1..a0c181a7d79d7 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -62,7 +62,7 @@ {{if $isTreePathRoot}} - {{ctx.Locale.Tr "repo.find_file.go_to_file"}} + {{ctx.Locale.Tr "repo.find_file.go_to_file"}} {{end}} {{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}