Fix missing close in WalkGitLog (#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>
This commit is contained in:
parent
248b96d8a3
commit
0faf175694
1 changed files with 16 additions and 7 deletions
|
@ -18,11 +18,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogNameStatusRepo opens git log --raw in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
// LogNameStatusRepo opens git log --raw in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||||
func LogNameStatusRepo(repository, head, treepath string, paths ...string) (*bufio.Reader, func()) {
|
func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, paths ...string) (*bufio.Reader, func()) {
|
||||||
// We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
|
// We often want to feed the commits in order into cat-file --batch, followed by their trees and sub trees as necessary.
|
||||||
// so let's create a batch stdin and stdout
|
// so let's create a batch stdin and stdout
|
||||||
stdoutReader, stdoutWriter := nio.Pipe(buffer.New(32 * 1024))
|
stdoutReader, stdoutWriter := nio.Pipe(buffer.New(32 * 1024))
|
||||||
|
|
||||||
|
// Lets also create a context so that we can absolutely ensure that the command should die when we're done
|
||||||
|
ctx, ctxCancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
cancel := func() {
|
cancel := func() {
|
||||||
|
ctxCancel()
|
||||||
_ = stdoutReader.Close()
|
_ = stdoutReader.Close()
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}
|
}
|
||||||
|
@ -50,7 +55,7 @@ func LogNameStatusRepo(repository, head, treepath string, paths ...string) (*buf
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(args...).RunInDirFullPipeline(repository, stdoutWriter, &stderr, nil)
|
err := NewCommandContext(ctx, args...).RunInDirFullPipeline(repository, stdoutWriter, &stderr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,8 +80,8 @@ type LogNameStatusRepoParser struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogNameStatusRepoParser returns a new parser for a git log raw output
|
// NewLogNameStatusRepoParser returns a new parser for a git log raw output
|
||||||
func NewLogNameStatusRepoParser(repository, head, treepath string, paths ...string) *LogNameStatusRepoParser {
|
func NewLogNameStatusRepoParser(ctx context.Context, repository, head, treepath string, paths ...string) *LogNameStatusRepoParser {
|
||||||
rd, cancel := LogNameStatusRepo(repository, head, treepath, paths...)
|
rd, cancel := LogNameStatusRepo(ctx, repository, head, treepath, paths...)
|
||||||
return &LogNameStatusRepoParser{
|
return &LogNameStatusRepoParser{
|
||||||
treepath: treepath,
|
treepath: treepath,
|
||||||
paths: paths,
|
paths: paths,
|
||||||
|
@ -311,8 +316,11 @@ func WalkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g := NewLogNameStatusRepoParser(repo.Path, head.ID.String(), treepath, paths...)
|
g := NewLogNameStatusRepoParser(ctx, repo.Path, head.ID.String(), treepath, paths...)
|
||||||
defer g.Close()
|
// don't use defer g.Close() here as g may change its value - instead wrap in a func
|
||||||
|
defer func() {
|
||||||
|
g.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
results := make([]string, len(paths))
|
results := make([]string, len(paths))
|
||||||
remaining := len(paths)
|
remaining := len(paths)
|
||||||
|
@ -331,6 +339,7 @@ heaploop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
g.Close()
|
||||||
return nil, ctx.Err()
|
return nil, ctx.Err()
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
@ -380,7 +389,7 @@ heaploop:
|
||||||
remainingPaths = append(remainingPaths, pth)
|
remainingPaths = append(remainingPaths, pth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g = NewLogNameStatusRepoParser(repo.Path, lastEmptyParent, treepath, remainingPaths...)
|
g = NewLogNameStatusRepoParser(ctx, repo.Path, lastEmptyParent, treepath, remainingPaths...)
|
||||||
parentRemaining = map[string]bool{}
|
parentRemaining = map[string]bool{}
|
||||||
nextRestart = (remaining * 3) / 4
|
nextRestart = (remaining * 3) / 4
|
||||||
continue heaploop
|
continue heaploop
|
||||||
|
|
Reference in a new issue