From fedd244060d8d21b1dae6ed10dd45b7a8560588a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 13 Jan 2025 00:26:58 -0800 Subject: [PATCH 1/2] 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)}} From 2de6bbef77a026f20e50868310c98cfb8dc33fee Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 13 Jan 2025 17:51:58 +0800 Subject: [PATCH 2/2] fix --- modules/git/ref.go | 24 ++++------- routers/web/repo/find.go | 8 ++-- routers/web/repo/treelist.go | 7 ++- routers/web/web.go | 3 +- services/context/repo.go | 83 ++++++++++++++---------------------- templates/repo/home.tmpl | 3 +- 6 files changed, 54 insertions(+), 74 deletions(-) diff --git a/modules/git/ref.go b/modules/git/ref.go index 0ac6094e3da53..a6e53ced8317c 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -5,9 +5,9 @@ package git import ( "regexp" + "slices" "strings" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" ) @@ -85,20 +85,6 @@ 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) } @@ -235,3 +221,11 @@ func (ref RefName) RefWebLinkPath() string { } return string(refType) + "/" + util.PathEscapeSegments(ref.ShortName()) } + +func RefNameFromUserInput(ref string, allowedTypes ...RefType) RefName { + refName := RefName(ref) + if !slices.Contains(allowedTypes, refName.RefType()) { + return "" + } + return refName +} diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go index 530d75ff1b151..2a505971b8975 100644 --- a/routers/web/repo/find.go +++ b/routers/web/repo/find.go @@ -5,7 +5,9 @@ package repo import ( "net/http" + "net/url" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" @@ -18,8 +20,8 @@ const ( // FindFiles render the page to find repository files 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) + - "?ref_type=" + ctx.FormTrim("ref_type") + "&ref_name=" + ctx.FormTrim("ref_name") + ref := git.RefNameFromUserInput(ctx.FormTrim("ref"), git.RefTypeBranch, git.RefTypeTag, git.RefTypeCommit) + ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + ref.RefWebLinkPath() + "/" + util.PathEscapeSegments(path) + ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path) + "?ref=" + url.QueryEscape(ctx.FormTrim("ref")) ctx.HTML(http.StatusOK, tplFindFiles) } diff --git a/routers/web/repo/treelist.go b/routers/web/repo/treelist.go index d11af4669f90c..6c3e0d83751fa 100644 --- a/routers/web/repo/treelist.go +++ b/routers/web/repo/treelist.go @@ -15,7 +15,12 @@ import ( // TreeList get all files' entries of a repository func TreeList(ctx *context.Context) { - tree, err := ctx.Repo.Commit.SubTree("/") + _, commit, err := ctx.Repo.GetRefCommit(ctx.FormString("ref"), git.RefTypeBranch, git.RefTypeTag, git.RefTypeCommit) + if err != nil { + ctx.ServerError("GetRefCommit", err) + return + } + tree, err := commit.SubTree("/") if err != nil { ctx.ServerError("Repo.Commit.SubTree", err) return diff --git a/routers/web/web.go b/routers/web/web.go index 30a0c74f7a5f5..687664e81aeb7 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1158,8 +1158,7 @@ func registerRoutes(m *web.Router) { m.Group("/{username}/{reponame}", func() { m.Get("/find/*", repo.FindFiles) m.Get("/find", repo.FindFiles) - m.Get("/tree-list/*", context.RepoRefByQueries(), repo.TreeList) - m.Get("/tree-list", context.RepoRefByQueries(), repo.TreeList) + m.Get("/tree-list", 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). diff --git a/services/context/repo.go b/services/context/repo.go index 21aeca5111db4..e05580b922431 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -91,6 +91,22 @@ func (r *Repository) GetObjectFormat() git.ObjectFormat { return git.ObjectFormatFromName(r.Repository.ObjectFormatName) } +func (r *Repository) GetRefCommit(ref string, allowedTypes ...git.RefType) (git.RefName, *git.Commit, error) { + refName := git.RefNameFromUserInput(ref, allowedTypes...) + if refName == "" { + return "", nil, errors.New("invalid ref") + } + commitID, err := r.GitRepo.GetRefCommitID(refName.String()) + if err != nil { + return "", nil, err + } + commit, err := r.GitRepo.GetCommit(commitID) + if err != nil { + return "", nil, err + } + return refName, commit, nil +} + // RepoMustNotBeArchived checks if a repo is archived func RepoMustNotBeArchived() func(ctx *Context) { return func(ctx *Context) { @@ -780,6 +796,20 @@ type RepoRefByTypeOptions struct { IgnoreNotExistErr bool } +func repoRefFullName(typ git.RefType, shortName string) git.RefName { + switch typ { + case git.RefTypeBranch: + return git.RefNameFromBranch(shortName) + case git.RefTypeTag: + return git.RefNameFromTag(shortName) + case git.RefTypeCommit: + 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 git.RefType, opts ...RepoRefByTypeOptions) func(*Context) { @@ -842,7 +872,7 @@ func RepoRefByType(detectRefType git.RefType, opts ...RepoRefByTypeOptions) func } else { refShortName = getRefName(ctx.Base, ctx.Repo, reqPath, refType) } - ctx.Repo.RefFullName = git.RefNameFromTypeAndShortName(refType, refShortName) + ctx.Repo.RefFullName = repoRefFullName(refType, refShortName) isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool) if isRenamedBranch && has { renamedBranchName := ctx.Data["RenamedBranchName"].(string) @@ -939,57 +969,6 @@ func RepoRefByType(detectRefType git.RefType, 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 a0c181a7d79d7..0a49687093ae1 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -62,7 +62,8 @@ {{if $isTreePathRoot}} - {{ctx.Locale.Tr "repo.find_file.go_to_file"}} + {{/* FIXME: it should still use RefTypeNameSubURL, otherwise the link is ugly */}} + {{ctx.Locale.Tr "repo.find_file.go_to_file"}} {{end}} {{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}