* Make cancel from CatFileBatch and CatFileBatchCheck wait for the command to end (#16479) Fix #16427 (again!) * handle sharing violation error code Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		
							parent
							
								
									d268c9d6e1
								
							
						
					
					
						commit
						0c3467ffb7
					
				
					 2 changed files with 34 additions and 2 deletions
				
			
		|  | @ -7,6 +7,7 @@ package git | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"context" | ||||||
| 	"io" | 	"io" | ||||||
| 	"math" | 	"math" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  | @ -28,16 +29,20 @@ type WriteCloserError interface { | ||||||
| func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func()) { | func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func()) { | ||||||
| 	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-check").RunInDirFullPipeline(repoPath, batchStdoutWriter, &stderr, batchStdinReader) | 		err := NewCommandContext(ctx, "cat-file", "--batch-check").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())) | ||||||
|  | @ -45,6 +50,7 @@ func CatFileBatchCheck(repoPath string) (WriteCloserError, *bufio.Reader, func() | ||||||
| 			_ = batchStdoutWriter.Close() | 			_ = batchStdoutWriter.Close() | ||||||
| 			_ = batchStdinReader.Close() | 			_ = batchStdinReader.Close() | ||||||
| 		} | 		} | ||||||
|  | 		close(closed) | ||||||
| 	}() | 	}() | ||||||
| 
 | 
 | ||||||
| 	// For simplicities sake we'll use a buffered reader to read from the cat-file --batch-check
 | 	// For simplicities sake we'll use a buffered reader to read from the cat-file --batch-check
 | ||||||
|  | @ -59,16 +65,20 @@ func CatFileBatch(repoPath string) (WriteCloserError, *bufio.Reader, func()) { | ||||||
| 	// 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 := nio.Pipe(buffer.New(32 * 1024)) | 	batchStdoutReader, batchStdoutWriter := nio.Pipe(buffer.New(32 * 1024)) | ||||||
|  | 	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())) | ||||||
|  | @ -76,6 +86,7 @@ func CatFileBatch(repoPath string) (WriteCloserError, *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
 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue