Skip to content

Commit f26eb1c

Browse files
6543AbdulrhmnGhanem
authored andcommitted
RepoAssignment ensure to close before overwrite (go-gitea#19449)
* check if GitRepo already open and close if * only run RepoAssignment once * refactor context helper for api to open GitRepo
1 parent 0cadca1 commit f26eb1c

File tree

11 files changed

+121
-96
lines changed

11 files changed

+121
-96
lines changed

modules/context/api.go

+40-41
Original file line numberDiff line numberDiff line change
@@ -285,36 +285,6 @@ func APIContexter() func(http.Handler) http.Handler {
285285
}
286286
}
287287

288-
// ReferencesGitRepo injects the GitRepo into the Context
289-
func ReferencesGitRepo(allowEmpty bool) func(ctx *APIContext) (cancel context.CancelFunc) {
290-
return func(ctx *APIContext) (cancel context.CancelFunc) {
291-
// Empty repository does not have reference information.
292-
if !allowEmpty && ctx.Repo.Repository.IsEmpty {
293-
return
294-
}
295-
296-
// For API calls.
297-
if ctx.Repo.GitRepo == nil {
298-
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
299-
gitRepo, err := git.OpenRepository(ctx, repoPath)
300-
if err != nil {
301-
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
302-
return
303-
}
304-
ctx.Repo.GitRepo = gitRepo
305-
// We opened it, we should close it
306-
return func() {
307-
// If it's been set to nil then assume someone else has closed it.
308-
if ctx.Repo.GitRepo != nil {
309-
ctx.Repo.GitRepo.Close()
310-
}
311-
}
312-
}
313-
314-
return
315-
}
316-
}
317-
318288
// NotFound handles 404s for APIContext
319289
// String will replace message, errors will be added to a slice
320290
func (ctx *APIContext) NotFound(objs ...interface{}) {
@@ -340,33 +310,62 @@ func (ctx *APIContext) NotFound(objs ...interface{}) {
340310
})
341311
}
342312

343-
// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
344-
func RepoRefForAPI(next http.Handler) http.Handler {
345-
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
346-
ctx := GetAPIContext(req)
313+
// ReferencesGitRepo injects the GitRepo into the Context
314+
// you can optional skip the IsEmpty check
315+
func ReferencesGitRepo(allowEmpty ...bool) func(ctx *APIContext) (cancel context.CancelFunc) {
316+
return func(ctx *APIContext) (cancel context.CancelFunc) {
347317
// Empty repository does not have reference information.
348-
if ctx.Repo.Repository.IsEmpty {
318+
if ctx.Repo.Repository.IsEmpty && !(len(allowEmpty) != 0 && allowEmpty[0]) {
349319
return
350320
}
351321

352-
var err error
353-
322+
// For API calls.
354323
if ctx.Repo.GitRepo == nil {
355324
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
356-
ctx.Repo.GitRepo, err = git.OpenRepository(ctx, repoPath)
325+
gitRepo, err := git.OpenRepository(ctx, repoPath)
357326
if err != nil {
358-
ctx.InternalServerError(err)
327+
ctx.Error(http.StatusInternalServerError, "RepoRef Invalid repo "+repoPath, err)
359328
return
360329
}
330+
ctx.Repo.GitRepo = gitRepo
361331
// We opened it, we should close it
362-
defer func() {
332+
return func() {
363333
// If it's been set to nil then assume someone else has closed it.
364334
if ctx.Repo.GitRepo != nil {
365335
ctx.Repo.GitRepo.Close()
366336
}
367-
}()
337+
}
338+
}
339+
340+
return
341+
}
342+
}
343+
344+
// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
345+
func RepoRefForAPI(next http.Handler) http.Handler {
346+
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
347+
ctx := GetAPIContext(req)
348+
349+
if ctx.Repo.GitRepo == nil {
350+
ctx.InternalServerError(fmt.Errorf("no open git repo"))
351+
return
352+
}
353+
354+
if ref := ctx.FormTrim("ref"); len(ref) > 0 {
355+
commit, err := ctx.Repo.GitRepo.GetCommit(ref)
356+
if err != nil {
357+
if git.IsErrNotExist(err) {
358+
ctx.NotFound()
359+
} else {
360+
ctx.Error(http.StatusInternalServerError, "GetBlobByPath", err)
361+
}
362+
return
363+
}
364+
ctx.Repo.Commit = commit
365+
return
368366
}
369367

368+
var err error
370369
refName := getRefName(ctx.Context, RepoRefAny)
371370

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

modules/context/repo.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,21 @@ func (r *Repository) FileExists(path, branch string) (bool, error) {
221221

222222
// GetEditorconfig returns the .editorconfig definition if found in the
223223
// HEAD of the default repo branch.
224-
func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
224+
func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (*editorconfig.Editorconfig, error) {
225225
if r.GitRepo == nil {
226226
return nil, nil
227227
}
228-
commit, err := r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
229-
if err != nil {
230-
return nil, err
228+
var (
229+
err error
230+
commit *git.Commit
231+
)
232+
if len(optCommit) != 0 {
233+
commit = optCommit[0]
234+
} else {
235+
commit, err = r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
236+
if err != nil {
237+
return nil, err
238+
}
231239
}
232240
treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
233241
if err != nil {
@@ -407,6 +415,12 @@ func RepoIDAssignment() func(ctx *Context) {
407415

408416
// RepoAssignment returns a middleware to handle repository assignment
409417
func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
418+
if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
419+
log.Trace("RepoAssignment was exec already, skipping second call ...")
420+
return
421+
}
422+
ctx.Data["repoAssignmentExecuted"] = true
423+
410424
var (
411425
owner *user_model.User
412426
err error
@@ -602,6 +616,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
602616
ctx.ServerError("RepoAssignment Invalid repo "+repo_model.RepoPath(userName, repoName), err)
603617
return
604618
}
619+
if ctx.Repo.GitRepo != nil {
620+
ctx.Repo.GitRepo.Close()
621+
}
605622
ctx.Repo.GitRepo = gitRepo
606623

607624
// We opened it, we should close it

routers/api/v1/api.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ func Routes() *web.Route {
799799
m.Combo("").Get(repo.GetHook).
800800
Patch(bind(api.EditHookOption{}), repo.EditHook).
801801
Delete(repo.DeleteHook)
802-
m.Post("/tests", context.RepoRefForAPI, repo.TestHook)
802+
m.Post("/tests", context.ReferencesGitRepo(), context.RepoRefForAPI, repo.TestHook)
803803
})
804804
}, reqToken(), reqAdmin(), reqWebhooksEnabled())
805805
m.Get("/collaborators/{collaborator}", reqAnyRepoReader(), repo.IsCollaborator)
@@ -817,16 +817,16 @@ func Routes() *web.Route {
817817
Put(reqAdmin(), repo.AddTeam).
818818
Delete(reqAdmin(), repo.DeleteTeam)
819819
}, reqToken())
820-
m.Get("/raw/*", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
820+
m.Get("/raw/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
821821
m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive)
822822
m.Combo("/forks").Get(repo.ListForks).
823823
Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
824824
m.Group("/branches", func() {
825-
m.Get("", context.ReferencesGitRepo(false), repo.ListBranches)
826-
m.Get("/*", context.ReferencesGitRepo(false), repo.GetBranch)
827-
m.Delete("/*", reqRepoWriter(unit.TypeCode), context.ReferencesGitRepo(false), repo.DeleteBranch)
828-
m.Post("", reqRepoWriter(unit.TypeCode), context.ReferencesGitRepo(false), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
829-
}, reqRepoReader(unit.TypeCode))
825+
m.Get("", repo.ListBranches)
826+
m.Get("/*", repo.GetBranch)
827+
m.Delete("/*", reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
828+
m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
829+
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
830830
m.Group("/branch_protections", func() {
831831
m.Get("", repo.ListBranchProtections)
832832
m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection)
@@ -945,10 +945,10 @@ func Routes() *web.Route {
945945
})
946946
m.Group("/releases", func() {
947947
m.Combo("").Get(repo.ListReleases).
948-
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(false), bind(api.CreateReleaseOption{}), repo.CreateRelease)
948+
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
949949
m.Group("/{id}", func() {
950950
m.Combo("").Get(repo.GetRelease).
951-
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(false), bind(api.EditReleaseOption{}), repo.EditRelease).
951+
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
952952
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
953953
m.Group("/assets", func() {
954954
m.Combo("").Get(repo.ListReleaseAttachments).
@@ -965,7 +965,7 @@ func Routes() *web.Route {
965965
})
966966
}, reqRepoReader(unit.TypeReleases))
967967
m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
968-
m.Get("/editorconfig/{filename}", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
968+
m.Get("/editorconfig/{filename}", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
969969
m.Group("/pulls", func() {
970970
m.Combo("").Get(repo.ListPullRequests).
971971
Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
@@ -996,30 +996,30 @@ func Routes() *web.Route {
996996
Delete(reqToken(), bind(api.PullReviewRequestOptions{}), repo.DeleteReviewRequests).
997997
Post(reqToken(), bind(api.PullReviewRequestOptions{}), repo.CreateReviewRequests)
998998
})
999-
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(false))
999+
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo())
10001000
m.Group("/statuses", func() {
10011001
m.Combo("/{sha}").Get(repo.GetCommitStatuses).
10021002
Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
10031003
}, reqRepoReader(unit.TypeCode))
10041004
m.Group("/commits", func() {
1005-
m.Get("", context.ReferencesGitRepo(false), repo.GetAllCommits)
1005+
m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits)
10061006
m.Group("/{ref}", func() {
10071007
m.Get("/status", repo.GetCombinedCommitStatusByRef)
10081008
m.Get("/statuses", repo.GetCommitStatusesByRef)
10091009
})
10101010
}, reqRepoReader(unit.TypeCode))
10111011
m.Group("/git", func() {
10121012
m.Group("/commits", func() {
1013-
m.Get("/{sha}", context.ReferencesGitRepo(false), repo.GetSingleCommit)
1013+
m.Get("/{sha}", repo.GetSingleCommit)
10141014
m.Get("/{sha}.{diffType:diff|patch}", repo.DownloadCommitDiffOrPatch)
10151015
})
10161016
m.Get("/refs", repo.GetGitAllRefs)
10171017
m.Get("/refs/*", repo.GetGitRefs)
1018-
m.Get("/trees/{sha}", context.RepoRefForAPI, repo.GetTree)
1019-
m.Get("/blobs/{sha}", context.RepoRefForAPI, repo.GetBlob)
1020-
m.Get("/tags/{sha}", context.RepoRefForAPI, repo.GetAnnotatedTag)
1018+
m.Get("/trees/{sha}", repo.GetTree)
1019+
m.Get("/blobs/{sha}", repo.GetBlob)
1020+
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
10211021
m.Get("/notes/{sha}", repo.GetNote)
1022-
}, reqRepoReader(unit.TypeCode))
1022+
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
10231023
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
10241024
m.Group("/contents", func() {
10251025
m.Get("", repo.GetContentsList)
@@ -1039,7 +1039,7 @@ func Routes() *web.Route {
10391039
Delete(reqToken(), repo.DeleteTopic)
10401040
}, reqAdmin())
10411041
}, reqAnyRepoReader())
1042-
m.Get("/issue_templates", context.ReferencesGitRepo(false), repo.GetIssueTemplates)
1042+
m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates)
10431043
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
10441044
}, repoAssignment())
10451045
})

routers/api/v1/repo/blob.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ func GetBlob(ctx *context.APIContext) {
4545
ctx.Error(http.StatusBadRequest, "", "sha not provided")
4646
return
4747
}
48-
if blob, err := files_service.GetBlobBySHA(ctx, ctx.Repo.Repository, sha); err != nil {
48+
49+
if blob, err := files_service.GetBlobBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, sha); err != nil {
4950
ctx.Error(http.StatusBadRequest, "", err)
5051
} else {
5152
ctx.JSON(http.StatusOK, blob)

routers/api/v1/repo/commits.go

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) {
269269
// "404":
270270
// "$ref": "#/responses/notFound"
271271
repoPath := repo_model.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
272+
// TODO: use gitRepo from context
272273
if err := git.GetRawDiff(
273274
ctx,
274275
repoPath,

routers/api/v1/repo/file.go

+7-17
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,7 @@ func GetRawFile(ctx *context.APIContext) {
6262
return
6363
}
6464

65-
commit := ctx.Repo.Commit
66-
67-
if ref := ctx.FormTrim("ref"); len(ref) > 0 {
68-
var err error
69-
commit, err = ctx.Repo.GitRepo.GetCommit(ref)
70-
if err != nil {
71-
if git.IsErrNotExist(err) {
72-
ctx.NotFound()
73-
} else {
74-
ctx.Error(http.StatusInternalServerError, "GetBlobByPath", err)
75-
}
76-
return
77-
}
78-
}
79-
80-
blob, err := commit.GetBlobByPath(ctx.Repo.TreePath)
65+
blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
8166
if err != nil {
8267
if git.IsErrNotExist(err) {
8368
ctx.NotFound()
@@ -157,13 +142,18 @@ func GetEditorconfig(ctx *context.APIContext) {
157142
// description: filepath of file to get
158143
// type: string
159144
// required: true
145+
// - name: ref
146+
// in: query
147+
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
148+
// type: string
149+
// required: false
160150
// responses:
161151
// 200:
162152
// description: success
163153
// "404":
164154
// "$ref": "#/responses/notFound"
165155

166-
ec, err := ctx.Repo.GetEditorconfig()
156+
ec, err := ctx.Repo.GetEditorconfig(ctx.Repo.Commit)
167157
if err != nil {
168158
if git.IsErrNotExist(err) {
169159
ctx.NotFound(err)

routers/api/v1/repo/hook.go

+5
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ func TestHook(ctx *context.APIContext) {
138138
// type: integer
139139
// format: int64
140140
// required: true
141+
// - name: ref
142+
// in: query
143+
// description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)"
144+
// type: string
145+
// required: false
141146
// responses:
142147
// "204":
143148
// "$ref": "#/responses/empty"

routers/api/v1/repo/notes.go

+5-7
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,13 @@ func GetNote(ctx *context.APIContext) {
5555
}
5656

5757
func getNote(ctx *context.APIContext, identifier string) {
58-
gitRepo, err := git.OpenRepository(ctx, ctx.Repo.Repository.RepoPath())
59-
if err != nil {
60-
ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
58+
if ctx.Repo.GitRepo == nil {
59+
ctx.InternalServerError(fmt.Errorf("no open git repo"))
6160
return
6261
}
63-
defer gitRepo.Close()
62+
6463
var note git.Note
65-
err = git.GetNote(ctx, gitRepo, identifier, &note)
66-
if err != nil {
64+
if err := git.GetNote(ctx, ctx.Repo.GitRepo, identifier, &note); err != nil {
6765
if git.IsErrNotExist(err) {
6866
ctx.NotFound(identifier)
6967
return
@@ -72,7 +70,7 @@ func getNote(ctx *context.APIContext, identifier string) {
7270
return
7371
}
7472

75-
cmt, err := convert.ToCommit(ctx.Repo.Repository, gitRepo, note.Commit, nil)
73+
cmt, err := convert.ToCommit(ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil)
7674
if err != nil {
7775
ctx.Error(http.StatusInternalServerError, "ToCommit", err)
7876
return

services/repository/files/content.go

+2-7
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref
164164
// Now populate the rest of the ContentsResponse based on entry type
165165
if entry.IsRegular() || entry.IsExecutable() {
166166
contentsResponse.Type = string(ContentTypeRegular)
167-
if blobResponse, err := GetBlobBySHA(ctx, repo, entry.ID.String()); err != nil {
167+
if blobResponse, err := GetBlobBySHA(ctx, repo, gitRepo, entry.ID.String()); err != nil {
168168
return nil, err
169169
} else if !forList {
170170
// We don't show the content if we are getting a list of FileContentResponses
@@ -220,12 +220,7 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref
220220
}
221221

222222
// GetBlobBySHA get the GitBlobResponse of a repository using a sha hash.
223-
func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, sha string) (*api.GitBlobResponse, error) {
224-
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.RepoPath())
225-
if err != nil {
226-
return nil, err
227-
}
228-
defer closer.Close()
223+
func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, sha string) (*api.GitBlobResponse, error) {
229224
gitBlob, err := gitRepo.GetBlob(sha)
230225
if err != nil {
231226
return nil, err

0 commit comments

Comments
 (0)