Skip to content

Commit 61c3559

Browse files
authored
Refactor RepoRefByType (#32413)
1. clarify the "filepath" could(should) contain "{ref}" 2. remove unclear RepoRefLegacy and RepoRefAny, use RepoRefUnknown to guess 3. by the way, avoid using AppURL
1 parent 4a469c8 commit 61c3559

File tree

7 files changed

+100
-109
lines changed

7 files changed

+100
-109
lines changed

routers/api/v1/repo/file.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ func GetRawFile(ctx *context.APIContext) {
5656
// required: true
5757
// - name: filepath
5858
// in: path
59-
// description: filepath of the file to get
59+
// description: path of the file to get, it should be "{ref}/{filepath}". If there is no ref could be inferred, it will be treated as the default branch
6060
// type: string
6161
// required: true
6262
// - name: ref
6363
// in: query
64-
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
64+
// description: "The name of the commit/branch/tag. Default the repository’s default branch"
6565
// type: string
6666
// required: false
6767
// responses:
@@ -109,12 +109,12 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
109109
// required: true
110110
// - name: filepath
111111
// in: path
112-
// description: filepath of the file to get
112+
// description: path of the file to get, it should be "{ref}/{filepath}". If there is no ref could be inferred, it will be treated as the default branch
113113
// type: string
114114
// required: true
115115
// - name: ref
116116
// in: query
117-
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
117+
// description: "The name of the commit/branch/tag. Default the repository’s default branch"
118118
// type: string
119119
// required: false
120120
// responses:

routers/web/goget.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func goGet(ctx *context.Context) {
6565
insecure = "--insecure "
6666
}
6767

68-
goGetImport := context.ComposeGoGetImport(ownerName, trimmedRepoName)
68+
goGetImport := context.ComposeGoGetImport(ctx, ownerName, trimmedRepoName)
6969

7070
var cloneURL string
7171
if setting.Repository.GoGetCloneURLProtocol == "ssh" {

routers/web/web.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,7 @@ func registerRoutes(m *web.Router) {
13231323
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS)
13241324
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom)
13251325
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed),
1326-
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, true))
1326+
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true}))
13271327
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
13281328
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
13291329
}, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
@@ -1337,7 +1337,7 @@ func registerRoutes(m *web.Router) {
13371337
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS)
13381338
m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom)
13391339
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed),
1340-
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, true))
1340+
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true}))
13411341
m.Get("/releases/attachments/{uuid}", repo.MustBeNotEmpty, repo.GetAttachment)
13421342
m.Get("/releases/download/{vTag}/{fileName}", repo.MustBeNotEmpty, repo.RedirectDownload)
13431343
m.Group("/releases", func() {
@@ -1535,7 +1535,7 @@ func registerRoutes(m *web.Router) {
15351535
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownloadOrLFS)
15361536
m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByIDOrLFS)
15371537
// "/*" route is deprecated, and kept for backward compatibility
1538-
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownloadOrLFS)
1538+
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.SingleDownloadOrLFS)
15391539
}, repo.MustBeNotEmpty)
15401540

15411541
m.Group("/raw", func() {
@@ -1544,7 +1544,7 @@ func registerRoutes(m *web.Router) {
15441544
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownload)
15451545
m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByID)
15461546
// "/*" route is deprecated, and kept for backward compatibility
1547-
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
1547+
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.SingleDownload)
15481548
}, repo.MustBeNotEmpty)
15491549

15501550
m.Group("/render", func() {
@@ -1559,7 +1559,7 @@ func registerRoutes(m *web.Router) {
15591559
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits)
15601560
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits)
15611561
// "/*" route is deprecated, and kept for backward compatibility
1562-
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.RefCommits)
1562+
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.RefCommits)
15631563
}, repo.MustBeNotEmpty)
15641564

15651565
m.Group("/blame", func() {
@@ -1582,7 +1582,7 @@ func registerRoutes(m *web.Router) {
15821582
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
15831583
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home)
15841584
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.Home)
1585-
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home) // "/*" route is deprecated, and kept for backward compatibility
1585+
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.Home) // "/*" route is deprecated, and kept for backward compatibility
15861586
}, repo.SetEditorconfigIfExists)
15871587

15881588
m.Get("/forks", context.RepoRef(), repo.Forks)

services/context/api.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"code.gitea.io/gitea/models/unit"
1515
user_model "code.gitea.io/gitea/models/user"
1616
"code.gitea.io/gitea/modules/cache"
17-
"code.gitea.io/gitea/modules/git"
1817
"code.gitea.io/gitea/modules/gitrepo"
1918
"code.gitea.io/gitea/modules/httpcache"
2019
"code.gitea.io/gitea/modules/log"
@@ -306,24 +305,8 @@ func RepoRefForAPI(next http.Handler) http.Handler {
306305
return
307306
}
308307

309-
if ref := ctx.FormTrim("ref"); len(ref) > 0 {
310-
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
311-
if err != nil {
312-
if git.IsErrNotExist(err) {
313-
ctx.NotFound()
314-
} else {
315-
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
316-
}
317-
return
318-
}
319-
ctx.Repo.Commit = commit
320-
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
321-
ctx.Repo.TreePath = ctx.PathParam("*")
322-
next.ServeHTTP(w, req)
323-
return
324-
}
325-
326-
refName := getRefName(ctx.Base, ctx.Repo, RepoRefAny)
308+
// NOTICE: the "ref" here for internal usage only (e.g. woodpecker)
309+
refName, _ := getRefNameLegacy(ctx.Base, ctx.Repo, ctx.FormTrim("ref"))
327310
var err error
328311

329312
if ctx.Repo.GitRepo.IsBranchExist(refName) {

services/context/repo.go

Lines changed: 73 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"code.gitea.io/gitea/modules/cache"
2626
"code.gitea.io/gitea/modules/git"
2727
"code.gitea.io/gitea/modules/gitrepo"
28+
"code.gitea.io/gitea/modules/httplib"
2829
code_indexer "code.gitea.io/gitea/modules/indexer/code"
2930
"code.gitea.io/gitea/modules/log"
3031
"code.gitea.io/gitea/modules/optional"
@@ -306,11 +307,9 @@ func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) {
306307
}
307308

308309
// ComposeGoGetImport returns go-get-import meta content.
309-
func ComposeGoGetImport(owner, repo string) string {
310-
/// setting.AppUrl is guaranteed to be parse as url
311-
appURL, _ := url.Parse(setting.AppURL)
312-
313-
return path.Join(appURL.Host, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo))
310+
func ComposeGoGetImport(ctx context.Context, owner, repo string) string {
311+
curAppURL, _ := url.Parse(httplib.GuessCurrentAppURL(ctx))
312+
return path.Join(curAppURL.Host, setting.AppSubURL, url.PathEscape(owner), url.PathEscape(repo))
314313
}
315314

316315
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
@@ -332,7 +331,7 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
332331
} else {
333332
cloneURL = repo_model.ComposeHTTPSCloneURL(username, reponame)
334333
}
335-
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(username, reponame), cloneURL)
334+
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(ctx, username, reponame), cloneURL)
336335
htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
337336
ctx.PlainText(http.StatusOK, htmlMeta)
338337
}
@@ -744,7 +743,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
744743
}
745744

746745
if ctx.FormString("go-get") == "1" {
747-
ctx.Data["GoGetImport"] = ComposeGoGetImport(owner.Name, repo.Name)
746+
ctx.Data["GoGetImport"] = ComposeGoGetImport(ctx, owner.Name, repo.Name)
748747
fullURLPrefix := repo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
749748
ctx.Data["GoDocDirectory"] = fullURLPrefix + "{/dir}"
750749
ctx.Data["GoDocFile"] = fullURLPrefix + "{/dir}/{file}#L{line}"
@@ -756,19 +755,11 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
756755
type RepoRefType int
757756

758757
const (
759-
// RepoRefLegacy unknown type, make educated guess and redirect.
760-
// for backward compatibility with previous URL scheme
761-
RepoRefLegacy RepoRefType = iota
762-
// RepoRefAny is for usage where educated guess is needed
763-
// but redirect can not be made
764-
RepoRefAny
765-
// RepoRefBranch branch
758+
// RepoRefUnknown is for legacy support, makes the code to "guess" the ref type
759+
RepoRefUnknown RepoRefType = iota
766760
RepoRefBranch
767-
// RepoRefTag tag
768761
RepoRefTag
769-
// RepoRefCommit commit
770762
RepoRefCommit
771-
// RepoRefBlob blob
772763
RepoRefBlob
773764
)
774765

@@ -781,22 +772,6 @@ func RepoRef() func(*Context) context.CancelFunc {
781772
return RepoRefByType(RepoRefBranch)
782773
}
783774

784-
// RefTypeIncludesBranches returns true if ref type can be a branch
785-
func (rt RepoRefType) RefTypeIncludesBranches() bool {
786-
if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefBranch {
787-
return true
788-
}
789-
return false
790-
}
791-
792-
// RefTypeIncludesTags returns true if ref type can be a tag
793-
func (rt RepoRefType) RefTypeIncludesTags() bool {
794-
if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefTag {
795-
return true
796-
}
797-
return false
798-
}
799-
800775
func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string {
801776
refName := ""
802777
parts := strings.Split(path, "/")
@@ -810,28 +785,50 @@ func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool
810785
return ""
811786
}
812787

788+
func isStringLikelyCommitID(objFmt git.ObjectFormat, s string, minLength ...int) bool {
789+
minLen := util.OptionalArg(minLength, objFmt.FullLength())
790+
if len(s) < minLen || len(s) > objFmt.FullLength() {
791+
return false
792+
}
793+
for _, c := range s {
794+
isHex := (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
795+
if !isHex {
796+
return false
797+
}
798+
}
799+
return true
800+
}
801+
802+
func getRefNameLegacy(ctx *Base, repo *Repository, optionalExtraRef ...string) (string, RepoRefType) {
803+
extraRef := util.OptionalArg(optionalExtraRef)
804+
reqPath := ctx.PathParam("*")
805+
reqPath = path.Join(extraRef, reqPath)
806+
807+
if refName := getRefName(ctx, repo, RepoRefBranch); refName != "" {
808+
return refName, RepoRefBranch
809+
}
810+
if refName := getRefName(ctx, repo, RepoRefTag); refName != "" {
811+
return refName, RepoRefTag
812+
}
813+
814+
// For legacy support only full commit sha
815+
parts := strings.Split(reqPath, "/")
816+
if isStringLikelyCommitID(git.ObjectFormatFromName(repo.Repository.ObjectFormatName), parts[0]) {
817+
// FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
818+
repo.TreePath = strings.Join(parts[1:], "/")
819+
return parts[0], RepoRefCommit
820+
}
821+
822+
if refName := getRefName(ctx, repo, RepoRefBlob); len(refName) > 0 {
823+
return refName, RepoRefBlob
824+
}
825+
repo.TreePath = reqPath
826+
return repo.Repository.DefaultBranch, RepoRefBranch
827+
}
828+
813829
func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
814830
path := ctx.PathParam("*")
815831
switch pathType {
816-
case RepoRefLegacy, RepoRefAny:
817-
if refName := getRefName(ctx, repo, RepoRefBranch); len(refName) > 0 {
818-
return refName
819-
}
820-
if refName := getRefName(ctx, repo, RepoRefTag); len(refName) > 0 {
821-
return refName
822-
}
823-
// For legacy and API support only full commit sha
824-
parts := strings.Split(path, "/")
825-
826-
if len(parts) > 0 && len(parts[0]) == git.ObjectFormatFromName(repo.Repository.ObjectFormatName).FullLength() {
827-
repo.TreePath = strings.Join(parts[1:], "/")
828-
return parts[0]
829-
}
830-
if refName := getRefName(ctx, repo, RepoRefBlob); len(refName) > 0 {
831-
return refName
832-
}
833-
repo.TreePath = path
834-
return repo.Repository.DefaultBranch
835832
case RepoRefBranch:
836833
ref := getRefNameFromPath(repo, path, repo.GitRepo.IsBranchExist)
837834
if len(ref) == 0 {
@@ -866,13 +863,13 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
866863
return getRefNameFromPath(repo, path, repo.GitRepo.IsTagExist)
867864
case RepoRefCommit:
868865
parts := strings.Split(path, "/")
869-
870-
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= repo.GetObjectFormat().FullLength() {
866+
if isStringLikelyCommitID(repo.GetObjectFormat(), parts[0], 7) {
867+
// FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
871868
repo.TreePath = strings.Join(parts[1:], "/")
872869
return parts[0]
873870
}
874871

875-
if len(parts) > 0 && parts[0] == headRefName {
872+
if parts[0] == headRefName {
876873
// HEAD ref points to last default branch commit
877874
commit, err := repo.GitRepo.GetBranchCommit(repo.Repository.DefaultBranch)
878875
if err != nil {
@@ -888,15 +885,21 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string {
888885
}
889886
return path
890887
default:
891-
log.Error("Unrecognized path type: %v", path)
888+
panic(fmt.Sprintf("Unrecognized path type: %v", pathType))
892889
}
893890
return ""
894891
}
895892

893+
type RepoRefByTypeOptions struct {
894+
IgnoreNotExistErr bool
895+
}
896+
896897
// RepoRefByType handles repository reference name for a specific type
897898
// of repository reference
898-
func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context) context.CancelFunc {
899+
func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func(*Context) context.CancelFunc {
900+
opt := util.OptionalArg(opts)
899901
return func(ctx *Context) (cancel context.CancelFunc) {
902+
refType := detectRefType
900903
// Empty repository does not have reference information.
901904
if ctx.Repo.Repository.IsEmpty {
902905
// assume the user is viewing the (non-existent) default branch
@@ -956,7 +959,12 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
956959
}
957960
ctx.Repo.IsViewBranch = true
958961
} else {
959-
refName = getRefName(ctx.Base, ctx.Repo, refType)
962+
guessLegacyPath := refType == RepoRefUnknown
963+
if guessLegacyPath {
964+
refName, refType = getRefNameLegacy(ctx.Base, ctx.Repo)
965+
} else {
966+
refName = getRefName(ctx.Base, ctx.Repo, refType)
967+
}
960968
ctx.Repo.RefName = refName
961969
isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
962970
if isRenamedBranch && has {
@@ -967,7 +975,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
967975
return cancel
968976
}
969977

970-
if refType.RefTypeIncludesBranches() && ctx.Repo.GitRepo.IsBranchExist(refName) {
978+
if refType == RepoRefBranch && ctx.Repo.GitRepo.IsBranchExist(refName) {
971979
ctx.Repo.IsViewBranch = true
972980
ctx.Repo.BranchName = refName
973981

@@ -977,7 +985,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
977985
return cancel
978986
}
979987
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
980-
} else if refType.RefTypeIncludesTags() && ctx.Repo.GitRepo.IsTagExist(refName) {
988+
} else if refType == RepoRefTag && ctx.Repo.GitRepo.IsTagExist(refName) {
981989
ctx.Repo.IsViewTag = true
982990
ctx.Repo.TagName = refName
983991

@@ -991,7 +999,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
991999
return cancel
9921000
}
9931001
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
994-
} else if len(refName) >= 7 && len(refName) <= ctx.Repo.GetObjectFormat().FullLength() {
1002+
} else if isStringLikelyCommitID(ctx.Repo.GetObjectFormat(), refName, 7) {
9951003
ctx.Repo.IsViewCommit = true
9961004
ctx.Repo.CommitID = refName
9971005

@@ -1002,18 +1010,18 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
10021010
}
10031011
// If short commit ID add canonical link header
10041012
if len(refName) < ctx.Repo.GetObjectFormat().FullLength() {
1005-
ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
1006-
util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
1013+
canonicalURL := util.URLJoin(httplib.GuessCurrentAppURL(ctx), strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))
1014+
ctx.RespHeader().Set("Link", fmt.Sprintf(`<%s>; rel="canonical"`, canonicalURL))
10071015
}
10081016
} else {
1009-
if len(ignoreNotExistErr) > 0 && ignoreNotExistErr[0] {
1017+
if opt.IgnoreNotExistErr {
10101018
return cancel
10111019
}
10121020
ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
10131021
return cancel
10141022
}
10151023

1016-
if refType == RepoRefLegacy {
1024+
if guessLegacyPath {
10171025
// redirect from old URL scheme to new URL scheme
10181026
prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.PathParam("*"))), strings.ToLower(ctx.Repo.RepoLink))
10191027
redirect := path.Join(

0 commit comments

Comments
 (0)