@ -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