)
// 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.
// so let's create a batch stdin and stdout
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() {
+ ctxCancel()
_ = stdoutReader.Close()
_ = stdoutWriter.Close()
}
go func() {
stderr := strings.Builder{}
- err := NewCommand(args...).RunInDirFullPipeline(repository, stdoutWriter, &stderr, nil)
+ err := NewCommandContext(ctx, args...).RunInDirFullPipeline(repository, stdoutWriter, &stderr, nil)
if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
} else {
}
// NewLogNameStatusRepoParser returns a new parser for a git log raw output
-func NewLogNameStatusRepoParser(repository, head, treepath string, paths ...string) *LogNameStatusRepoParser {
- rd, cancel := LogNameStatusRepo(repository, head, treepath, paths...)
+func NewLogNameStatusRepoParser(ctx context.Context, repository, head, treepath string, paths ...string) *LogNameStatusRepoParser {
+ rd, cancel := LogNameStatusRepo(ctx, repository, head, treepath, paths...)
return &LogNameStatusRepoParser{
treepath: treepath,
paths: paths,
}
}
- g := NewLogNameStatusRepoParser(repo.Path, head.ID.String(), treepath, paths...)
- defer g.Close()
+ g := NewLogNameStatusRepoParser(ctx, repo.Path, head.ID.String(), treepath, paths...)
+ // 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))
remaining := len(paths)
for {
select {
case <-ctx.Done():
+ g.Close()
return nil, ctx.Err()
default:
}
remainingPaths = append(remainingPaths, pth)
}
}
- g = NewLogNameStatusRepoParser(repo.Path, lastEmptyParent, treepath, remainingPaths...)
+ g = NewLogNameStatusRepoParser(ctx, repo.Path, lastEmptyParent, treepath, remainingPaths...)
parentRemaining = map[string]bool{}
nextRestart = (remaining * 3) / 4
continue heaploop