Skip to content

Commit 659b946

Browse files
authored
Fix missing close in WalkGitLog (#17008) (#17009)
Backport #17008 When the external context is cancelled it is possible for the GitLogReader to not itself be Closed. This PR does three things: 1. Instead of adding a plain defer it wraps the `g.Close` in a func as `g` may change. 2. It adds the missing explicit g.Close - although the defer fix makes this unnecessary. 3. It passes down the external context as the base context for the GitLogReader meaning that the cancellation of the external context will pass down automatically. Fix #17007 Signed-off-by: Andrew Thornton <art27@cantab.net>
1 parent 56ab5ec commit 659b946

File tree

1 file changed

+16
-7
lines changed

1 file changed

+16
-7
lines changed

modules/git/log_name_status.go

+16-7
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,16 @@ import (
1818
)
1919

2020
// LogNameStatusRepo opens git log --raw in the provided repo and returns a stdin pipe, a stdout reader and cancel function
21-
func LogNameStatusRepo(repository, head, treepath string, paths ...string) (*bufio.Reader, func()) {
21+
func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, paths ...string) (*bufio.Reader, func()) {
2222
// We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
2323
// so let's create a batch stdin and stdout
2424
stdoutReader, stdoutWriter := nio.Pipe(buffer.New(32 * 1024))
25+
26+
// Lets also create a context so that we can absolutely ensure that the command should die when we're done
27+
ctx, ctxCancel := context.WithCancel(ctx)
28+
2529
cancel := func() {
30+
ctxCancel()
2631
_ = stdoutReader.Close()
2732
_ = stdoutWriter.Close()
2833
}
@@ -50,7 +55,7 @@ func LogNameStatusRepo(repository, head, treepath string, paths ...string) (*buf
5055

5156
go func() {
5257
stderr := strings.Builder{}
53-
err := NewCommand(args...).RunInDirFullPipeline(repository, stdoutWriter, &stderr, nil)
58+
err := NewCommandContext(ctx, args...).RunInDirFullPipeline(repository, stdoutWriter, &stderr, nil)
5459
if err != nil {
5560
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
5661
} else {
@@ -75,8 +80,8 @@ type LogNameStatusRepoParser struct {
7580
}
7681

7782
// NewLogNameStatusRepoParser returns a new parser for a git log raw output
78-
func NewLogNameStatusRepoParser(repository, head, treepath string, paths ...string) *LogNameStatusRepoParser {
79-
rd, cancel := LogNameStatusRepo(repository, head, treepath, paths...)
83+
func NewLogNameStatusRepoParser(ctx context.Context, repository, head, treepath string, paths ...string) *LogNameStatusRepoParser {
84+
rd, cancel := LogNameStatusRepo(ctx, repository, head, treepath, paths...)
8085
return &LogNameStatusRepoParser{
8186
treepath: treepath,
8287
paths: paths,
@@ -311,8 +316,11 @@ func WalkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath st
311316
}
312317
}
313318

314-
g := NewLogNameStatusRepoParser(repo.Path, head.ID.String(), treepath, paths...)
315-
defer g.Close()
319+
g := NewLogNameStatusRepoParser(ctx, repo.Path, head.ID.String(), treepath, paths...)
320+
// don't use defer g.Close() here as g may change its value - instead wrap in a func
321+
defer func() {
322+
g.Close()
323+
}()
316324

317325
results := make([]string, len(paths))
318326
remaining := len(paths)
@@ -331,6 +339,7 @@ heaploop:
331339
for {
332340
select {
333341
case <-ctx.Done():
342+
g.Close()
334343
return nil, ctx.Err()
335344
default:
336345
}
@@ -380,7 +389,7 @@ heaploop:
380389
remainingPaths = append(remainingPaths, pth)
381390
}
382391
}
383-
g = NewLogNameStatusRepoParser(repo.Path, lastEmptyParent, treepath, remainingPaths...)
392+
g = NewLogNameStatusRepoParser(ctx, repo.Path, lastEmptyParent, treepath, remainingPaths...)
384393
parentRemaining = map[string]bool{}
385394
nextRestart = (remaining * 3) / 4
386395
continue heaploop

0 commit comments

Comments
 (0)