-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Save patches to temporary files #9296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
26d4e75
f6cfef0
f86ac61
5d6d313
e349449
810898f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8,6 +8,7 @@ package models | |||||||||
import ( | ||||||||||
"bufio" | ||||||||||
"fmt" | ||||||||||
"io/ioutil" | ||||||||||
"os" | ||||||||||
"path" | ||||||||||
"path/filepath" | ||||||||||
|
@@ -595,11 +596,11 @@ func (pr *PullRequest) testPatch(e Engine) (err error) { | |||||||||
} | ||||||||||
|
||||||||||
// NewPullRequest creates new pull request with labels for repository. | ||||||||||
func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) { | ||||||||||
func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patchFileSize int64, patchFileName string) (err error) { | ||||||||||
// Retry several times in case INSERT fails due to duplicate key for (repo_id, index); see #7887 | ||||||||||
i := 0 | ||||||||||
for { | ||||||||||
if err = newPullRequestAttempt(repo, pull, labelIDs, uuids, pr, patch); err == nil { | ||||||||||
if err = newPullRequestAttempt(repo, pull, labelIDs, uuids, pr, patchFileSize, patchFileName); err == nil { | ||||||||||
return nil | ||||||||||
} | ||||||||||
if !IsErrNewIssueInsert(err) { | ||||||||||
|
@@ -613,7 +614,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str | |||||||||
return fmt.Errorf("NewPullRequest: too many errors attempting to insert the new issue. Last error was: %v", err) | ||||||||||
} | ||||||||||
|
||||||||||
func newPullRequestAttempt(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) { | ||||||||||
func newPullRequestAttempt(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patchFileSize int64, patchFileName string) (err error) { | ||||||||||
sess := x.NewSession() | ||||||||||
defer sess.Close() | ||||||||||
if err = sess.Begin(); err != nil { | ||||||||||
|
@@ -636,8 +637,8 @@ func newPullRequestAttempt(repo *Repository, pull *Issue, labelIDs []int64, uuid | |||||||||
pr.Index = pull.Index | ||||||||||
pr.BaseRepo = repo | ||||||||||
pr.Status = PullRequestStatusChecking | ||||||||||
if len(patch) > 0 { | ||||||||||
if err = repo.savePatch(sess, pr.Index, patch); err != nil { | ||||||||||
if patchFileSize > 0 { | ||||||||||
if err = repo.savePatch(sess, pr.Index, patchFileName); err != nil { | ||||||||||
return fmt.Errorf("SavePatch: %v", err) | ||||||||||
} | ||||||||||
|
||||||||||
|
@@ -800,12 +801,23 @@ func (pr *PullRequest) UpdatePatch() (err error) { | |||||||||
return fmt.Errorf("Update: %v", err) | ||||||||||
} | ||||||||||
|
||||||||||
patch, err := headGitRepo.GetPatch(pr.MergeBase, pr.HeadBranch) | ||||||||||
tmpPatchFile, err := ioutil.TempFile("", "patch") | ||||||||||
if err != nil { | ||||||||||
return fmt.Errorf("GetPatch: %v", err) | ||||||||||
log.Error("Unable to create temporary patch file! Error: %v", err) | ||||||||||
return fmt.Errorf("Unable to create temporary patch file! Error: %v", err) | ||||||||||
} | ||||||||||
defer func() { | ||||||||||
_ = os.Remove(tmpPatchFile.Name()) | ||||||||||
}() | ||||||||||
|
||||||||||
if err := headGitRepo.GetPatch(pr.MergeBase, pr.HeadBranch, tmpPatchFile); err != nil { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
tmpPatchFile.Close() | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
log.Error("Unable to get patch file from %s to %s in %s/%s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name, err) | ||||||||||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
return fmt.Errorf("Unable to get patch file from %s to %s in %s/%s Error: %v", pr.MergeBase, pr.HeadBranch, pr.BaseRepo.MustOwner().Name, pr.BaseRepo.Name, err) | ||||||||||
} | ||||||||||
|
||||||||||
if err = pr.BaseRepo.SavePatch(pr.Index, patch); err != nil { | ||||||||||
tmpPatchFile.Close() | ||||||||||
if err = pr.BaseRepo.SavePatch(pr.Index, tmpPatchFile.Name()); err != nil { | ||||||||||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
return fmt.Errorf("BaseRepo.SavePatch: %v", err) | ||||||||||
} | ||||||||||
|
||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,8 @@ import ( | |
"fmt" | ||
"html" | ||
"io" | ||
"io/ioutil" | ||
"os" | ||
"path" | ||
"strings" | ||
|
||
|
@@ -785,12 +787,29 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) | |
return | ||
} | ||
|
||
patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch) | ||
tmpPatchFile, err := ioutil.TempFile("", "patch") | ||
if err != nil { | ||
ctx.ServerError("CreateTemporaryFile", err) | ||
return | ||
} | ||
defer func() { | ||
_ = os.Remove(tmpPatchFile.Name()) | ||
}() | ||
|
||
if err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch, tmpPatchFile); err != nil { | ||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tmpPatchFile.Close() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same with tmpPatchFile.Close() |
||
ctx.ServerError("GetPatch", err) | ||
return | ||
} | ||
|
||
stat, err := tmpPatchFile.Stat() | ||
if err != nil { | ||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tmpPatchFile.Close() | ||
ctx.ServerError("StatPatch", err) | ||
return | ||
} | ||
tmpPatchFile.Close() | ||
|
||
pullIssue := &models.Issue{ | ||
RepoID: repo.ID, | ||
Title: form.Title, | ||
|
@@ -813,7 +832,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) | |
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt | ||
// instead of 500. | ||
|
||
if err := pull_service.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch, assigneeIDs); err != nil { | ||
if err := pull_service.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, stat.Size(), tmpPatchFile.Name(), assigneeIDs); err != nil { | ||
if models.IsErrUserDoesNotHaveAccessToRepo(err) { | ||
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error()) | ||
return | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the patch should be saved even if it's got 0 bytes. The reason is that a previous PR creation attempt (from a different PR, with patch data) could have failed between this step and the commit, so a left-over patch file (named after this same index number) might still be lingering in the directory. I hope that makes sense.
In fact, there are scenarios where that patch could be broken anyway with this retry mechanism. Mmm.... we should be locking that path, at the very least? Sorry, I wasn't aware that there were destinations other than the database when I wrote the retry code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would make it simpler if we dropped that file size test.
Tbh I'm not certain that the patch files are ever actually cleaned up. I don't remember seeing any code looking at deleting them. I actually forgot to look explicitly - that's not like me!!
You're also right about the lack of file locking. This might be because we have generally migrated from the repoworkingcopy lock mechanism to rely on git locking but obviously this doesn't use that mechanism. #9302 obviously isn't affected by this.
I guess the question is how important is it provide a backport?
If we're not going to backport - then I'm happy to close this and move to the more radical refactor.
(It's not like this is the only place we still read in potentially huge amounts of data - diff and blame are both still doing that, and a change to streaming there will require huge refactoring.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, backporting is not my call, but I'm OK with not backporting this as long as #9302 makes it in time for 1.11.