Preserve validation cancellation during reader shutdown

This commit is contained in:
2026-10-09 03:06:06 +00:00
parent 15dd58f5ac
commit 6eec022bb0
4 changed files with 69 additions and 7 deletions

View File

@@ -13,6 +13,7 @@ import (
// CandidateTree is an inventory of one captured commit with blob contents
// loaded lazily by object ID.
type CandidateTree struct {
context context.Context
repositoryDir string
entries []git.TreeEntry
byPath map[string]int
@@ -24,13 +25,14 @@ type CandidateTree struct {
}
// ReadCandidateTree enumerates the captured commit without reading from the
// worktree.
// worktree. The supplied context also governs the scoped reader through closure.
func ReadCandidateTree(ctx context.Context, repositoryDir, commit string) (*CandidateTree, error) {
entries, err := git.ReadTree(ctx, repositoryDir, commit)
if err != nil {
return nil, err
}
tree := &CandidateTree{
context: ctx,
repositoryDir: repositoryDir,
entries: entries,
byPath: make(map[string]int, len(entries)),
@@ -104,10 +106,12 @@ func (tree *CandidateTree) readBlob(ctx context.Context, entry git.TreeEntry) ([
return nil, fmt.Errorf("read committed path %q: candidate tree is closed", entry.Path)
}
if tree.blobReader == nil {
// The reader belongs to the tree and can outlive an individual read
// context. Each Read call still applies its own cancellation to the
// in-flight exchange.
tree.blobReader = git.NewBlobReader(context.Background(), tree.repositoryDir)
// The operation context governs shutdown independently of each read.
operationContext := tree.context
if operationContext == nil {
operationContext = context.Background()
}
tree.blobReader = git.NewBlobReader(operationContext, tree.repositoryDir)
}
contents, err := tree.blobReader.Read(ctx, entry.ObjectID)
if err != nil {