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> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
		
							parent
							
								
									b26c3b482f
								
							
						
					
					
						commit
						97381aad5d
					
				| 
						 | 
					@ -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 New Issue