Skip to content

Commit

Permalink
Merge branch 'lunny/refactor_reftype' of github.com:lunny/gitea into …
Browse files Browse the repository at this point in the history
…lunny/refactor_reftype
  • Loading branch information
lunny committed Jan 13, 2025
2 parents 98d7e04 + 2de6bbe commit a7ceb12
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 73 deletions.
9 changes: 9 additions & 0 deletions modules/git/ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package git

import (
"regexp"
"slices"
"strings"

"code.gitea.io/gitea/modules/util"
Expand Down Expand Up @@ -220,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
}
7 changes: 5 additions & 2 deletions routers/web/repo/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -18,7 +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 := 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)
}
7 changes: 6 additions & 1 deletion routers/web/repo/treelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
68 changes: 33 additions & 35 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1156,11 +1157,8 @@ 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", 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).
Expand Down Expand Up @@ -1313,9 +1311,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)
Expand All @@ -1334,7 +1332,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)
Expand All @@ -1348,7 +1346,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() {
Expand Down Expand Up @@ -1521,42 +1519,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)
Expand All @@ -1568,20 +1566,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

Expand Down
73 changes: 39 additions & 34 deletions services/context/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -677,24 +693,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 {
Expand All @@ -710,29 +715,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
Expand Down Expand Up @@ -762,9 +767,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
Expand All @@ -782,7 +787,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 ""
}
Expand All @@ -791,13 +796,13 @@ type RepoRefByTypeOptions struct {
IgnoreNotExistErr bool
}

func repoRefFullName(shortName string, typ RepoRefType) git.RefName {
func repoRefFullName(typ git.RefType, shortName string) git.RefName {
switch typ {
case RepoRefBranch:
case git.RefTypeBranch:
return git.RefNameFromBranch(shortName)
case RepoRefTag:
case git.RefTypeTag:
return git.RefNameFromTag(shortName)
case RepoRefCommit:
case git.RefTypeCommit:
return git.RefNameFromCommit(shortName)
default:
setting.PanicInDevOrTesting("Unknown RepoRefType: %v", typ)
Expand All @@ -807,7 +812,7 @@ func repoRefFullName(shortName string, typ RepoRefType) git.RefName {

// 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
Expand Down Expand Up @@ -861,13 +866,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 = repoRefFullName(refType, refShortName)
isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
if isRenamedBranch && has {
renamedBranchName := ctx.Data["RenamedBranchName"].(string)
Expand All @@ -877,7 +882,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)
Expand All @@ -888,7 +893,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
Expand Down
3 changes: 2 additions & 1 deletion templates/repo/home.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@

<!-- Show go to file if on home page -->
{{if $isTreePathRoot}}
<a href="{{.Repository.Link}}/find/{{.RefTypeNameSubURL}}" class="ui compact basic button">{{ctx.Locale.Tr "repo.find_file.go_to_file"}}</a>
{{/* FIXME: it should still use RefTypeNameSubURL, otherwise the link is ugly */}}
<a href="{{.Repository.Link}}/find/{{.TreePath}}?ref={{.RefFullName}}" class="ui compact basic button">{{ctx.Locale.Tr "repo.find_file.go_to_file"}}</a>
{{end}}

{{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}
Expand Down

0 comments on commit a7ceb12

Please sign in to comment.