Add vendor
Specifically because I want to modify a dependency
This commit is contained in:
		
							
								
								
									
										15
									
								
								vendor/github.com/muesli/cancelreader/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/muesli/cancelreader/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # Binaries for programs and plugins | ||||
| *.exe | ||||
| *.exe~ | ||||
| *.dll | ||||
| *.so | ||||
| *.dylib | ||||
|  | ||||
| # Test binary, built with `go test -c` | ||||
| *.test | ||||
|  | ||||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||||
| *.out | ||||
|  | ||||
| # Dependency directories (remove the comment below to include it) | ||||
| # vendor/ | ||||
							
								
								
									
										47
									
								
								vendor/github.com/muesli/cancelreader/.golangci-soft.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/muesli/cancelreader/.golangci-soft.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| run: | ||||
|   tests: false | ||||
|  | ||||
| issues: | ||||
|   include: | ||||
|     - EXC0001 | ||||
|     - EXC0005 | ||||
|     - EXC0011 | ||||
|     - EXC0012 | ||||
|     - EXC0013 | ||||
|  | ||||
|   max-issues-per-linter: 0 | ||||
|   max-same-issues: 0 | ||||
|  | ||||
| linters: | ||||
|   enable: | ||||
|     # - dupl | ||||
|     - exhaustive | ||||
|     # - exhaustivestruct | ||||
|     - goconst | ||||
|     - godot | ||||
|     - godox | ||||
|     - gomnd | ||||
|     - gomoddirectives | ||||
|     - goprintffuncname | ||||
|     - ifshort | ||||
|     # - lll | ||||
|     - misspell | ||||
|     - nakedret | ||||
|     - nestif | ||||
|     - noctx | ||||
|     - nolintlint | ||||
|     - prealloc | ||||
|     - wrapcheck | ||||
|  | ||||
|   # disable default linters, they are already enabled in .golangci.yml | ||||
|   disable: | ||||
|     - deadcode | ||||
|     - errcheck | ||||
|     - gosimple | ||||
|     - govet | ||||
|     - ineffassign | ||||
|     - staticcheck | ||||
|     - structcheck | ||||
|     - typecheck | ||||
|     - unused | ||||
|     - varcheck | ||||
							
								
								
									
										29
									
								
								vendor/github.com/muesli/cancelreader/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/muesli/cancelreader/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| run: | ||||
|   tests: false | ||||
|  | ||||
| issues: | ||||
|   include: | ||||
|     - EXC0001 | ||||
|     - EXC0005 | ||||
|     - EXC0011 | ||||
|     - EXC0012 | ||||
|     - EXC0013 | ||||
|  | ||||
|   max-issues-per-linter: 0 | ||||
|   max-same-issues: 0 | ||||
|  | ||||
| linters: | ||||
|   enable: | ||||
|     - bodyclose | ||||
|     - exportloopref | ||||
|     - goimports | ||||
|     - gosec | ||||
|     - nilerr | ||||
|     - predeclared | ||||
|     - revive | ||||
|     - rowserrcheck | ||||
|     - sqlclosecheck | ||||
|     - tparallel | ||||
|     - unconvert | ||||
|     - unparam | ||||
|     - whitespace | ||||
							
								
								
									
										21
									
								
								vendor/github.com/muesli/cancelreader/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/muesli/cancelreader/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| MIT License | ||||
|  | ||||
| Copyright (c) 2022 Erik Geiser and Christian Muehlhaeuser | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										64
									
								
								vendor/github.com/muesli/cancelreader/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/muesli/cancelreader/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| # CancelReader | ||||
|  | ||||
| [](https://github.com/muesli/cancelreader/releases) | ||||
| [](https://pkg.go.dev/github.com/muesli/cancelreader) | ||||
| [](/LICENSE) | ||||
| [](https://github.com/muesli/cancelreader/actions) | ||||
| [](https://goreportcard.com/report/muesli/cancelreader) | ||||
|  | ||||
| A cancelable reader for Go | ||||
|  | ||||
| This package is based on the fantastic work of [Erik Geiser](https://github.com/erikgeiser) | ||||
| in Charm's [Bubble Tea](https://github.com/charmbracelet/bubbletea) framework. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| `NewReader` returns a reader with a `Cancel` function. If the input reader is a | ||||
| `File`, the cancel function can be used to interrupt a blocking `Read` call. | ||||
| In this case, the cancel function returns true if the call was canceled | ||||
| successfully. If the input reader is not a `File`, the cancel function does | ||||
| nothing and always returns false. | ||||
|  | ||||
| ```go | ||||
| r, err := cancelreader.NewReader(file) | ||||
| if err != nil { | ||||
|     // handle error | ||||
|     ... | ||||
| } | ||||
|  | ||||
| // cancel after five seconds | ||||
| go func() { | ||||
|     time.Sleep(5 * time.Second) | ||||
|     r.Cancel() | ||||
| }() | ||||
|  | ||||
| // keep reading | ||||
| for { | ||||
|     var buf [1024]byte | ||||
|     _, err := r.Read(buf[:]) | ||||
|  | ||||
|     if errors.Is(err, cancelreader.ErrCanceled) { | ||||
|         fmt.Println("canceled!") | ||||
|         break | ||||
|     } | ||||
|     if err != nil { | ||||
|         // handle other errors | ||||
|         ... | ||||
|     } | ||||
|  | ||||
|     // handle data | ||||
|     ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## Implementations | ||||
|  | ||||
| - The Linux implementation is based on the epoll mechanism | ||||
| - The BSD and macOS implementation is based on the kqueue mechanism | ||||
| - The generic Unix implementation is based on the posix select syscall | ||||
|  | ||||
| ## Caution | ||||
|  | ||||
| The Windows implementation is based on WaitForMultipleObject with overlapping | ||||
| reads from CONIN$. At this point it only supports canceling reads from | ||||
| `os.Stdin`. | ||||
							
								
								
									
										93
									
								
								vendor/github.com/muesli/cancelreader/cancelreader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								vendor/github.com/muesli/cancelreader/cancelreader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| package cancelreader | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| // ErrCanceled gets returned when trying to read from a canceled reader. | ||||
| var ErrCanceled = fmt.Errorf("read canceled") | ||||
|  | ||||
| // CancelReader is a io.Reader whose Read() calls can be canceled without data | ||||
| // being consumed. The cancelReader has to be closed. | ||||
| type CancelReader interface { | ||||
| 	io.ReadCloser | ||||
|  | ||||
| 	// Cancel cancels ongoing and future reads an returns true if it succeeded. | ||||
| 	Cancel() bool | ||||
| } | ||||
|  | ||||
| // File represents an input/output resource with a file descriptor. | ||||
| type File interface { | ||||
| 	io.ReadWriteCloser | ||||
|  | ||||
| 	// Fd returns its file descriptor | ||||
| 	Fd() uintptr | ||||
|  | ||||
| 	// Name returns its file name. | ||||
| 	Name() string | ||||
| } | ||||
|  | ||||
| // fallbackCancelReader implements cancelReader but does not actually support | ||||
| // cancelation during an ongoing Read() call. Thus, Cancel() always returns | ||||
| // false. However, after calling Cancel(), new Read() calls immediately return | ||||
| // errCanceled and don't consume any data anymore. | ||||
| type fallbackCancelReader struct { | ||||
| 	r io.Reader | ||||
| 	cancelMixin | ||||
| } | ||||
|  | ||||
| // newFallbackCancelReader is a fallback for NewReader that cannot actually | ||||
| // cancel an ongoing read but will immediately return on future reads if it has | ||||
| // been canceled. | ||||
| func newFallbackCancelReader(reader io.Reader) (CancelReader, error) { | ||||
| 	return &fallbackCancelReader{r: reader}, nil | ||||
| } | ||||
|  | ||||
| func (r *fallbackCancelReader) Read(data []byte) (int, error) { | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	n, err := r.r.Read(data) | ||||
| 	/* | ||||
| 		If the underlying reader is a blocking reader (e.g. an open connection), | ||||
| 		it might happen that 1 goroutine cancels the reader while its stuck in | ||||
| 		the read call waiting for something. | ||||
| 		If that happens, we should still cancel the read. | ||||
| 	*/ | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
| 	return n, err // nolint: wrapcheck | ||||
| } | ||||
|  | ||||
| func (r *fallbackCancelReader) Cancel() bool { | ||||
| 	r.setCanceled() | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (r *fallbackCancelReader) Close() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // cancelMixin represents a goroutine-safe cancelation status. | ||||
| type cancelMixin struct { | ||||
| 	unsafeCanceled bool | ||||
| 	lock           sync.Mutex | ||||
| } | ||||
|  | ||||
| func (c *cancelMixin) isCanceled() bool { | ||||
| 	c.lock.Lock() | ||||
| 	defer c.lock.Unlock() | ||||
|  | ||||
| 	return c.unsafeCanceled | ||||
| } | ||||
|  | ||||
| func (c *cancelMixin) setCanceled() { | ||||
| 	c.lock.Lock() | ||||
| 	defer c.lock.Unlock() | ||||
|  | ||||
| 	c.unsafeCanceled = true | ||||
| } | ||||
							
								
								
									
										146
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| //go:build darwin || freebsd || netbsd || openbsd || dragonfly | ||||
| // +build darwin freebsd netbsd openbsd dragonfly | ||||
|  | ||||
| package cancelreader | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // NewReader returns a reader and a cancel function. If the input reader is a | ||||
| // File, the cancel function can be used to interrupt a blocking read call. | ||||
| // In this case, the cancel function returns true if the call was canceled | ||||
| // successfully. If the input reader is not a File, the cancel function | ||||
| // does nothing and always returns false. The BSD and macOS implementation is | ||||
| // based on the kqueue mechanism. | ||||
| func NewReader(reader io.Reader) (CancelReader, error) { | ||||
| 	file, ok := reader.(File) | ||||
| 	if !ok { | ||||
| 		return newFallbackCancelReader(reader) | ||||
| 	} | ||||
|  | ||||
| 	// kqueue returns instantly when polling /dev/tty so fallback to select | ||||
| 	if file.Name() == "/dev/tty" { | ||||
| 		return newSelectCancelReader(reader) | ||||
| 	} | ||||
|  | ||||
| 	kQueue, err := unix.Kqueue() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("create kqueue: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	r := &kqueueCancelReader{ | ||||
| 		file:   file, | ||||
| 		kQueue: kQueue, | ||||
| 	} | ||||
|  | ||||
| 	r.cancelSignalReader, r.cancelSignalWriter, err = os.Pipe() | ||||
| 	if err != nil { | ||||
| 		_ = unix.Close(kQueue) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	unix.SetKevent(&r.kQueueEvents[0], int(file.Fd()), unix.EVFILT_READ, unix.EV_ADD) | ||||
| 	unix.SetKevent(&r.kQueueEvents[1], int(r.cancelSignalReader.Fd()), unix.EVFILT_READ, unix.EV_ADD) | ||||
|  | ||||
| 	return r, nil | ||||
| } | ||||
|  | ||||
| type kqueueCancelReader struct { | ||||
| 	file               File | ||||
| 	cancelSignalReader File | ||||
| 	cancelSignalWriter File | ||||
| 	cancelMixin | ||||
| 	kQueue       int | ||||
| 	kQueueEvents [2]unix.Kevent_t | ||||
| } | ||||
|  | ||||
| func (r *kqueueCancelReader) Read(data []byte) (int, error) { | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	err := r.wait() | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, ErrCanceled) { | ||||
| 			// remove signal from pipe | ||||
| 			var b [1]byte | ||||
| 			_, errRead := r.cancelSignalReader.Read(b[:]) | ||||
| 			if errRead != nil { | ||||
| 				return 0, fmt.Errorf("reading cancel signal: %w", errRead) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	return r.file.Read(data) | ||||
| } | ||||
|  | ||||
| func (r *kqueueCancelReader) Cancel() bool { | ||||
| 	r.setCanceled() | ||||
|  | ||||
| 	// send cancel signal | ||||
| 	_, err := r.cancelSignalWriter.Write([]byte{'c'}) | ||||
| 	return err == nil | ||||
| } | ||||
|  | ||||
| func (r *kqueueCancelReader) Close() error { | ||||
| 	var errMsgs []string | ||||
|  | ||||
| 	// close kqueue | ||||
| 	err := unix.Close(r.kQueue) | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing kqueue: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	// close pipe | ||||
| 	err = r.cancelSignalWriter.Close() | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal writer: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	err = r.cancelSignalReader.Close() | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal reader: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	if len(errMsgs) > 0 { | ||||
| 		return fmt.Errorf(strings.Join(errMsgs, ", ")) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r *kqueueCancelReader) wait() error { | ||||
| 	events := make([]unix.Kevent_t, 1) | ||||
|  | ||||
| 	for { | ||||
| 		_, err := unix.Kevent(r.kQueue, r.kQueueEvents[:], events, nil) | ||||
| 		if errors.Is(err, unix.EINTR) { | ||||
| 			continue // try again if the syscall was interrupted | ||||
| 		} | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("kevent: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		break | ||||
| 	} | ||||
|  | ||||
| 	ident := uint64(events[0].Ident) | ||||
| 	switch ident { | ||||
| 	case uint64(r.file.Fd()): | ||||
| 		return nil | ||||
| 	case uint64(r.cancelSignalReader.Fd()): | ||||
| 		return ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Errorf("unknown error") | ||||
| } | ||||
							
								
								
									
										12
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_default.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_default.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| //go:build !darwin && !windows && !linux && !solaris && !freebsd && !netbsd && !openbsd && !dragonfly | ||||
| // +build !darwin,!windows,!linux,!solaris,!freebsd,!netbsd,!openbsd,!dragonfly | ||||
|  | ||||
| package cancelreader | ||||
|  | ||||
| import "io" | ||||
|  | ||||
| // NewReader returns a fallbackCancelReader that satisfies the CancelReader but | ||||
| // does not actually support cancellation. | ||||
| func NewReader(reader io.Reader) (CancelReader, error) { | ||||
| 	return newFallbackCancelReader(reader) | ||||
| } | ||||
							
								
								
									
										154
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| //go:build linux | ||||
| // +build linux | ||||
|  | ||||
| package cancelreader | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // NewReader returns a reader and a cancel function. If the input reader is a | ||||
| // File, the cancel function can be used to interrupt a blocking read call. | ||||
| // In this case, the cancel function returns true if the call was canceled | ||||
| // successfully. If the input reader is not a File, the cancel function | ||||
| // does nothing and always returns false. The Linux implementation is based on | ||||
| // the epoll mechanism. | ||||
| func NewReader(reader io.Reader) (CancelReader, error) { | ||||
| 	file, ok := reader.(File) | ||||
| 	if !ok { | ||||
| 		return newFallbackCancelReader(reader) | ||||
| 	} | ||||
|  | ||||
| 	epoll, err := unix.EpollCreate1(0) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("create epoll: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	r := &epollCancelReader{ | ||||
| 		file:  file, | ||||
| 		epoll: epoll, | ||||
| 	} | ||||
|  | ||||
| 	r.cancelSignalReader, r.cancelSignalWriter, err = os.Pipe() | ||||
| 	if err != nil { | ||||
| 		_ = unix.Close(epoll) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = unix.EpollCtl(epoll, unix.EPOLL_CTL_ADD, int(file.Fd()), &unix.EpollEvent{ | ||||
| 		Events: unix.EPOLLIN, | ||||
| 		Fd:     int32(file.Fd()), | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		_ = unix.Close(epoll) | ||||
| 		return nil, fmt.Errorf("add reader to epoll interest list") | ||||
| 	} | ||||
|  | ||||
| 	err = unix.EpollCtl(epoll, unix.EPOLL_CTL_ADD, int(r.cancelSignalReader.Fd()), &unix.EpollEvent{ | ||||
| 		Events: unix.EPOLLIN, | ||||
| 		Fd:     int32(r.cancelSignalReader.Fd()), | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		_ = unix.Close(epoll) | ||||
| 		return nil, fmt.Errorf("add reader to epoll interest list") | ||||
| 	} | ||||
|  | ||||
| 	return r, nil | ||||
| } | ||||
|  | ||||
| type epollCancelReader struct { | ||||
| 	file               File | ||||
| 	cancelSignalReader File | ||||
| 	cancelSignalWriter File | ||||
| 	cancelMixin | ||||
| 	epoll int | ||||
| } | ||||
|  | ||||
| func (r *epollCancelReader) Read(data []byte) (int, error) { | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	err := r.wait() | ||||
| 	if err != nil { | ||||
| 		if errors.Is(err, ErrCanceled) { | ||||
| 			// remove signal from pipe | ||||
| 			var b [1]byte | ||||
| 			_, readErr := r.cancelSignalReader.Read(b[:]) | ||||
| 			if readErr != nil { | ||||
| 				return 0, fmt.Errorf("reading cancel signal: %w", readErr) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	return r.file.Read(data) | ||||
| } | ||||
|  | ||||
| func (r *epollCancelReader) Cancel() bool { | ||||
| 	r.setCanceled() | ||||
|  | ||||
| 	// send cancel signal | ||||
| 	_, err := r.cancelSignalWriter.Write([]byte{'c'}) | ||||
| 	return err == nil | ||||
| } | ||||
|  | ||||
| func (r *epollCancelReader) Close() error { | ||||
| 	var errMsgs []string | ||||
|  | ||||
| 	// close kqueue | ||||
| 	err := unix.Close(r.epoll) | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing epoll: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	// close pipe | ||||
| 	err = r.cancelSignalWriter.Close() | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal writer: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	err = r.cancelSignalReader.Close() | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal reader: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	if len(errMsgs) > 0 { | ||||
| 		return fmt.Errorf(strings.Join(errMsgs, ", ")) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r *epollCancelReader) wait() error { | ||||
| 	events := make([]unix.EpollEvent, 1) | ||||
|  | ||||
| 	for { | ||||
| 		_, err := unix.EpollWait(r.epoll, events, -1) | ||||
| 		if errors.Is(err, unix.EINTR) { | ||||
| 			continue // try again if the syscall was interrupted | ||||
| 		} | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("kevent: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		break | ||||
| 	} | ||||
|  | ||||
| 	switch events[0].Fd { | ||||
| 	case int32(r.file.Fd()): | ||||
| 		return nil | ||||
| 	case int32(r.cancelSignalReader.Fd()): | ||||
| 		return ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Errorf("unknown error") | ||||
| } | ||||
							
								
								
									
										136
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_select.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_select.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| //go:build solaris || darwin || freebsd || netbsd || openbsd || dragonfly | ||||
| // +build solaris darwin freebsd netbsd openbsd dragonfly | ||||
|  | ||||
| package cancelreader | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // newSelectCancelReader returns a reader and a cancel function. If the input | ||||
| // reader is a File, the cancel function can be used to interrupt a | ||||
| // blocking call read call. In this case, the cancel function returns true if | ||||
| // the call was canceled successfully. If the input reader is not a File or | ||||
| // the file descriptor is 1024 or larger, the cancel function does nothing and | ||||
| // always returns false. The generic unix implementation is based on the posix | ||||
| // select syscall. | ||||
| func newSelectCancelReader(reader io.Reader) (CancelReader, error) { | ||||
| 	file, ok := reader.(File) | ||||
| 	if !ok || file.Fd() >= unix.FD_SETSIZE { | ||||
| 		return newFallbackCancelReader(reader) | ||||
| 	} | ||||
| 	r := &selectCancelReader{file: file} | ||||
|  | ||||
| 	var err error | ||||
|  | ||||
| 	r.cancelSignalReader, r.cancelSignalWriter, err = os.Pipe() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return r, nil | ||||
| } | ||||
|  | ||||
| type selectCancelReader struct { | ||||
| 	file               File | ||||
| 	cancelSignalReader File | ||||
| 	cancelSignalWriter File | ||||
| 	cancelMixin | ||||
| } | ||||
|  | ||||
| func (r *selectCancelReader) Read(data []byte) (int, error) { | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		err := waitForRead(r.file, r.cancelSignalReader) | ||||
| 		if err != nil { | ||||
| 			if errors.Is(err, unix.EINTR) { | ||||
| 				continue // try again if the syscall was interrupted | ||||
| 			} | ||||
|  | ||||
| 			if errors.Is(err, ErrCanceled) { | ||||
| 				// remove signal from pipe | ||||
| 				var b [1]byte | ||||
| 				_, readErr := r.cancelSignalReader.Read(b[:]) | ||||
| 				if readErr != nil { | ||||
| 					return 0, fmt.Errorf("reading cancel signal: %w", readErr) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			return 0, err | ||||
| 		} | ||||
|  | ||||
| 		return r.file.Read(data) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *selectCancelReader) Cancel() bool { | ||||
| 	r.setCanceled() | ||||
|  | ||||
| 	// send cancel signal | ||||
| 	_, err := r.cancelSignalWriter.Write([]byte{'c'}) | ||||
| 	return err == nil | ||||
| } | ||||
|  | ||||
| func (r *selectCancelReader) Close() error { | ||||
| 	var errMsgs []string | ||||
|  | ||||
| 	// close pipe | ||||
| 	err := r.cancelSignalWriter.Close() | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal writer: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	err = r.cancelSignalReader.Close() | ||||
| 	if err != nil { | ||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("closing cancel signal reader: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	if len(errMsgs) > 0 { | ||||
| 		return fmt.Errorf(strings.Join(errMsgs, ", ")) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func waitForRead(reader, abort File) error { | ||||
| 	readerFd := int(reader.Fd()) | ||||
| 	abortFd := int(abort.Fd()) | ||||
|  | ||||
| 	maxFd := readerFd | ||||
| 	if abortFd > maxFd { | ||||
| 		maxFd = abortFd | ||||
| 	} | ||||
|  | ||||
| 	// this is a limitation of the select syscall | ||||
| 	if maxFd >= unix.FD_SETSIZE { | ||||
| 		return fmt.Errorf("cannot select on file descriptor %d which is larger than 1024", maxFd) | ||||
| 	} | ||||
|  | ||||
| 	fdSet := &unix.FdSet{} | ||||
| 	fdSet.Set(int(reader.Fd())) | ||||
| 	fdSet.Set(int(abort.Fd())) | ||||
|  | ||||
| 	_, err := unix.Select(maxFd+1, fdSet, nil, nil, nil) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("select: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	if fdSet.IsSet(abortFd) { | ||||
| 		return ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	if fdSet.IsSet(readerFd) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Errorf("select returned without setting a file descriptor") | ||||
| } | ||||
							
								
								
									
										18
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| //go:build solaris | ||||
| // +build solaris | ||||
|  | ||||
| package cancelreader | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // NewReader returns a reader and a cancel function. If the input reader is a | ||||
| // File, the cancel function can be used to interrupt a blocking read call. | ||||
| // In this case, the cancel function returns true if the call was canceled | ||||
| // successfully. If the input reader is not a File or the file descriptor | ||||
| // is 1024 or larger, the cancel function does nothing and always returns false. | ||||
| // The generic unix implementation is based on the posix select syscall. | ||||
| func NewReader(reader io.Reader) (CancelReader, error) { | ||||
| 	return newSelectCancelReader(reader) | ||||
| } | ||||
							
								
								
									
										244
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								vendor/github.com/muesli/cancelreader/cancelreader_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
| //go:build windows | ||||
| // +build windows | ||||
|  | ||||
| package cancelreader | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 	"unicode/utf16" | ||||
|  | ||||
| 	"golang.org/x/sys/windows" | ||||
| ) | ||||
|  | ||||
| var fileShareValidFlags uint32 = 0x00000007 | ||||
|  | ||||
| // NewReader returns a reader and a cancel function. If the input reader is a | ||||
| // File with the same file descriptor as os.Stdin, the cancel function can | ||||
| // be used to interrupt a blocking read call. In this case, the cancel function | ||||
| // returns true if the call was canceled successfully. If the input reader is | ||||
| // not a File with the same file descriptor as os.Stdin, the cancel | ||||
| // function does nothing and always returns false. The Windows implementation | ||||
| // is based on WaitForMultipleObject with overlapping reads from CONIN$. | ||||
| func NewReader(reader io.Reader) (CancelReader, error) { | ||||
| 	if f, ok := reader.(File); !ok || f.Fd() != os.Stdin.Fd() { | ||||
| 		return newFallbackCancelReader(reader) | ||||
| 	} | ||||
|  | ||||
| 	// it is necessary to open CONIN$ (NOT windows.STD_INPUT_HANDLE) in | ||||
| 	// overlapped mode to be able to use it with WaitForMultipleObjects. | ||||
| 	conin, err := windows.CreateFile( | ||||
| 		&(utf16.Encode([]rune("CONIN$\x00"))[0]), windows.GENERIC_READ|windows.GENERIC_WRITE, | ||||
| 		fileShareValidFlags, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_OVERLAPPED, 0) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("open CONIN$ in overlapping mode: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	resetConsole, err := prepareConsole(conin) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("prepare console: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	// flush input, otherwise it can contain events which trigger | ||||
| 	// WaitForMultipleObjects but which ReadFile cannot read, resulting in an | ||||
| 	// un-cancelable read | ||||
| 	err = flushConsoleInputBuffer(conin) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("flush console input buffer: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	cancelEvent, err := windows.CreateEvent(nil, 0, 0, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("create stop event: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	return &winCancelReader{ | ||||
| 		conin:              conin, | ||||
| 		cancelEvent:        cancelEvent, | ||||
| 		resetConsole:       resetConsole, | ||||
| 		blockingReadSignal: make(chan struct{}, 1), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type winCancelReader struct { | ||||
| 	conin       windows.Handle | ||||
| 	cancelEvent windows.Handle | ||||
| 	cancelMixin | ||||
|  | ||||
| 	resetConsole       func() error | ||||
| 	blockingReadSignal chan struct{} | ||||
| } | ||||
|  | ||||
| func (r *winCancelReader) Read(data []byte) (int, error) { | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	err := r.wait() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	if r.isCanceled() { | ||||
| 		return 0, ErrCanceled | ||||
| 	} | ||||
|  | ||||
| 	// windows.Read does not work on overlapping windows.Handles | ||||
| 	return r.readAsync(data) | ||||
| } | ||||
|  | ||||
| // Cancel cancels ongoing and future Read() calls and returns true if the | ||||
| // cancelation of the ongoing Read() was successful. On Windows Terminal, | ||||
| // WaitForMultipleObjects sometimes immediately returns without input being | ||||
| // available. In this case, graceful cancelation is not possible and Cancel() | ||||
| // returns false. | ||||
| func (r *winCancelReader) Cancel() bool { | ||||
| 	r.setCanceled() | ||||
|  | ||||
| 	select { | ||||
| 	case r.blockingReadSignal <- struct{}{}: | ||||
| 		err := windows.SetEvent(r.cancelEvent) | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		<-r.blockingReadSignal | ||||
| 	case <-time.After(100 * time.Millisecond): | ||||
| 		// Read() hangs in a GetOverlappedResult which is likely due to | ||||
| 		// WaitForMultipleObjects returning without input being available | ||||
| 		// so we cannot cancel this ongoing read. | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (r *winCancelReader) Close() error { | ||||
| 	err := windows.CloseHandle(r.cancelEvent) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("closing cancel event handle: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	err = r.resetConsole() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	err = windows.Close(r.conin) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("closing CONIN$") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r *winCancelReader) wait() error { | ||||
| 	event, err := windows.WaitForMultipleObjects([]windows.Handle{r.conin, r.cancelEvent}, false, windows.INFINITE) | ||||
| 	switch { | ||||
| 	case windows.WAIT_OBJECT_0 <= event && event < windows.WAIT_OBJECT_0+2: | ||||
| 		if event == windows.WAIT_OBJECT_0+1 { | ||||
| 			return ErrCanceled | ||||
| 		} | ||||
|  | ||||
| 		if event == windows.WAIT_OBJECT_0 { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		return fmt.Errorf("unexpected wait object is ready: %d", event-windows.WAIT_OBJECT_0) | ||||
| 	case windows.WAIT_ABANDONED <= event && event < windows.WAIT_ABANDONED+2: | ||||
| 		return fmt.Errorf("abandoned") | ||||
| 	case event == uint32(windows.WAIT_TIMEOUT): | ||||
| 		return fmt.Errorf("timeout") | ||||
| 	case event == windows.WAIT_FAILED: | ||||
| 		return fmt.Errorf("failed") | ||||
| 	default: | ||||
| 		return fmt.Errorf("unexpected error: %w", error(err)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readAsync is necessary to read from a windows.Handle in overlapping mode. | ||||
| func (r *winCancelReader) readAsync(data []byte) (int, error) { | ||||
| 	hevent, err := windows.CreateEvent(nil, 0, 0, nil) | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("create event: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	overlapped := windows.Overlapped{ | ||||
| 		HEvent: hevent, | ||||
| 	} | ||||
|  | ||||
| 	var n uint32 | ||||
|  | ||||
| 	err = windows.ReadFile(r.conin, data, &n, &overlapped) | ||||
| 	if err != nil && err != windows.ERROR_IO_PENDING { | ||||
| 		return int(n), err | ||||
| 	} | ||||
|  | ||||
| 	r.blockingReadSignal <- struct{}{} | ||||
| 	err = windows.GetOverlappedResult(r.conin, &overlapped, &n, true) | ||||
| 	if err != nil { | ||||
| 		return int(n), nil | ||||
| 	} | ||||
| 	<-r.blockingReadSignal | ||||
|  | ||||
| 	return int(n), nil | ||||
| } | ||||
|  | ||||
| func prepareConsole(input windows.Handle) (reset func() error, err error) { | ||||
| 	var originalMode uint32 | ||||
|  | ||||
| 	err = windows.GetConsoleMode(input, &originalMode) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("get console mode: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	var newMode uint32 | ||||
| 	newMode &^= windows.ENABLE_ECHO_INPUT | ||||
| 	newMode &^= windows.ENABLE_LINE_INPUT | ||||
| 	newMode &^= windows.ENABLE_MOUSE_INPUT | ||||
| 	newMode &^= windows.ENABLE_WINDOW_INPUT | ||||
| 	newMode &^= windows.ENABLE_PROCESSED_INPUT | ||||
|  | ||||
| 	newMode |= windows.ENABLE_EXTENDED_FLAGS | ||||
| 	newMode |= windows.ENABLE_INSERT_MODE | ||||
| 	newMode |= windows.ENABLE_QUICK_EDIT_MODE | ||||
|  | ||||
| 	// Enabling virtual terminal input is necessary for processing certain | ||||
| 	// types of input like X10 mouse events and arrows keys with the current | ||||
| 	// bytes-based input reader. It does, however, prevent cancelReader from | ||||
| 	// being able to cancel input. The planned solution for this is to read | ||||
| 	// Windows events in a more native fashion, rather than the current simple | ||||
| 	// bytes-based input reader which works well on unix systems. | ||||
| 	newMode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT | ||||
|  | ||||
| 	err = windows.SetConsoleMode(input, newMode) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("set console mode: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	return func() error { | ||||
| 		err := windows.SetConsoleMode(input, originalMode) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("reset console mode: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	modkernel32                 = windows.NewLazySystemDLL("kernel32.dll") | ||||
| 	procFlushConsoleInputBuffer = modkernel32.NewProc("FlushConsoleInputBuffer") | ||||
| ) | ||||
|  | ||||
| func flushConsoleInputBuffer(consoleInput windows.Handle) error { | ||||
| 	r, _, e := syscall.Syscall(procFlushConsoleInputBuffer.Addr(), 1, | ||||
| 		uintptr(consoleInput), 0, 0) | ||||
| 	if r == 0 { | ||||
| 		return error(e) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user