* Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end Fix #16427 (again!) * handle sharing violation error code Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
parent
e6c222511d
commit
3299f044d3
2 changed files with 30 additions and 3 deletions
|
@ -7,6 +7,7 @@ package git
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -15,20 +16,24 @@ import (
|
||||||
|
|
||||||
// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
// CatFileBatch opens git cat-file --batch in the provided repo and returns a stdin pipe, a stdout reader and cancel function
|
||||||
func CatFileBatch(repoPath string) (*io.PipeWriter, *bufio.Reader, func()) {
|
func CatFileBatch(repoPath string) (*io.PipeWriter, *bufio.Reader, func()) {
|
||||||
// Next 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
|
||||||
batchStdinReader, batchStdinWriter := io.Pipe()
|
batchStdinReader, batchStdinWriter := io.Pipe()
|
||||||
batchStdoutReader, batchStdoutWriter := io.Pipe()
|
batchStdoutReader, batchStdoutWriter := io.Pipe()
|
||||||
|
ctx, ctxCancel := context.WithCancel(DefaultContext)
|
||||||
|
closed := make(chan struct{})
|
||||||
cancel := func() {
|
cancel := func() {
|
||||||
_ = batchStdinReader.Close()
|
_ = batchStdinReader.Close()
|
||||||
_ = batchStdinWriter.Close()
|
_ = batchStdinWriter.Close()
|
||||||
_ = batchStdoutReader.Close()
|
_ = batchStdoutReader.Close()
|
||||||
_ = batchStdoutWriter.Close()
|
_ = batchStdoutWriter.Close()
|
||||||
|
ctxCancel()
|
||||||
|
<-closed
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand("cat-file", "--batch").RunInDirFullPipeline(repoPath, batchStdoutWriter, &stderr, batchStdinReader)
|
err := NewCommandContext(ctx, "cat-file", "--batch").RunInDirFullPipeline(repoPath, batchStdoutWriter, &stderr, batchStdinReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
||||||
_ = batchStdinReader.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = batchStdinReader.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
||||||
|
@ -36,10 +41,11 @@ func CatFileBatch(repoPath string) (*io.PipeWriter, *bufio.Reader, func()) {
|
||||||
_ = batchStdoutWriter.Close()
|
_ = batchStdoutWriter.Close()
|
||||||
_ = batchStdinReader.Close()
|
_ = batchStdinReader.Close()
|
||||||
}
|
}
|
||||||
|
close(closed)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// For simplicities sake we'll us a buffered reader to read from the cat-file --batch
|
// For simplicities sake we'll us a buffered reader to read from the cat-file --batch
|
||||||
batchReader := bufio.NewReader(batchStdoutReader)
|
batchReader := bufio.NewReaderSize(batchStdoutReader, 32*1024)
|
||||||
|
|
||||||
return batchStdinWriter, batchReader, cancel
|
return batchStdinWriter, batchReader, cancel
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,13 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const windowsSharingViolationError syscall.Errno = 32
|
||||||
|
|
||||||
// Remove removes the named file or (empty) directory with at most 5 attempts.
|
// Remove removes the named file or (empty) directory with at most 5 attempts.
|
||||||
func Remove(name string) error {
|
func Remove(name string) error {
|
||||||
var err error
|
var err error
|
||||||
|
@ -25,6 +28,12 @@ func Remove(name string) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" {
|
||||||
|
// try again
|
||||||
|
<-time.After(100 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if unwrapped == syscall.ENOENT {
|
if unwrapped == syscall.ENOENT {
|
||||||
// it's already gone
|
// it's already gone
|
||||||
return nil
|
return nil
|
||||||
|
@ -48,6 +57,12 @@ func RemoveAll(name string) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" {
|
||||||
|
// try again
|
||||||
|
<-time.After(100 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if unwrapped == syscall.ENOENT {
|
if unwrapped == syscall.ENOENT {
|
||||||
// it's already gone
|
// it's already gone
|
||||||
return nil
|
return nil
|
||||||
|
@ -71,6 +86,12 @@ func Rename(oldpath, newpath string) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if unwrapped == windowsSharingViolationError && runtime.GOOS == "windows" {
|
||||||
|
// try again
|
||||||
|
<-time.After(100 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if i == 0 && os.IsNotExist(err) {
|
if i == 0 && os.IsNotExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue