Skip to content

Commit a52e73d

Browse files
committed
Ensure BlameReaders close at end of request
this was thought to be due to timeouts, however on closer look this appears to be due to the Close() function of the BlameReader hanging with a blocked stdout pipe. This PR fixes this Close function to: * Cancel the context of the cmd * Close the StdoutReader - ensuring that the output pipe is closed Further it makes the context of the `git blame` command a child of the request context - ensuring that even if Close() is not called, on cancellation of the Request the blame is command will also be cancelled. Fixes go-gitea#11716 Closes go-gitea#11727 Signed-off-by: Andrew Thornton <[email protected]>
1 parent 8f48913 commit a52e73d

File tree

3 files changed

+13
-8
lines changed

3 files changed

+13
-8
lines changed

modules/git/blame.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
7979
// Close BlameReader - don't run NextPart after invoking that
8080
func (r *BlameReader) Close() error {
8181
defer process.GetManager().Remove(r.pid)
82-
defer r.cancel()
82+
r.cancel()
83+
84+
_ = r.output.Close()
8385

8486
if err := r.cmd.Wait(); err != nil {
8587
return fmt.Errorf("Wait: %v", err)
@@ -89,19 +91,19 @@ func (r *BlameReader) Close() error {
8991
}
9092

9193
// CreateBlameReader creates reader for given repository, commit and file
92-
func CreateBlameReader(repoPath, commitID, file string) (*BlameReader, error) {
94+
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
9395
gitRepo, err := OpenRepository(repoPath)
9496
if err != nil {
9597
return nil, err
9698
}
9799
gitRepo.Close()
98100

99-
return createBlameReader(repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
101+
return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
100102
}
101103

102-
func createBlameReader(dir string, command ...string) (*BlameReader, error) {
103-
// FIXME: graceful: This should have a timeout
104-
ctx, cancel := context.WithCancel(DefaultContext)
104+
func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) {
105+
// Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
106+
ctx, cancel := context.WithCancel(ctx)
105107
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
106108
cmd.Dir = dir
107109
cmd.Stderr = os.Stderr

modules/git/blame_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package git
66

77
import (
8+
"context"
89
"io/ioutil"
910
"testing"
1011

@@ -93,8 +94,10 @@ func TestReadingBlameOutput(t *testing.T) {
9394
if _, err = tempFile.WriteString(exampleBlame); err != nil {
9495
panic(err)
9596
}
97+
ctx, cancel := context.WithCancel(context.Background())
98+
defer cancel()
9699

97-
blameReader, err := createBlameReader("", "cat", tempFile.Name())
100+
blameReader, err := createBlameReader(ctx, "", "cat", tempFile.Name())
98101
if err != nil {
99102
panic(err)
100103
}

routers/repo/blame.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ func RefBlame(ctx *context.Context) {
123123
return
124124
}
125125

126-
blameReader, err := git.CreateBlameReader(models.RepoPath(userName, repoName), commitID, fileName)
126+
blameReader, err := git.CreateBlameReader(ctx.Req.Context(), models.RepoPath(userName, repoName), commitID, fileName)
127127
if err != nil {
128128
ctx.NotFound("CreateBlameReader", err)
129129
return

0 commit comments

Comments
 (0)