github.1git.de/docker/cli@v26.1.3+incompatible/cli/streams/in.go (about)

     1  package streams
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"os"
     7  	"runtime"
     8  
     9  	"github.com/moby/term"
    10  )
    11  
    12  // In is an input stream to read user input. It implements [io.ReadCloser]
    13  // with additional utilities, such as putting the terminal in raw mode.
    14  type In struct {
    15  	commonStream
    16  	in io.ReadCloser
    17  }
    18  
    19  // Read implements the [io.Reader] interface.
    20  func (i *In) Read(p []byte) (int, error) {
    21  	return i.in.Read(p)
    22  }
    23  
    24  // Close implements the [io.Closer] interface.
    25  func (i *In) Close() error {
    26  	return i.in.Close()
    27  }
    28  
    29  // SetRawTerminal sets raw mode on the input terminal. It is a no-op if In
    30  // is not a TTY, or if the "NORAW" environment variable is set to a non-empty
    31  // value.
    32  func (i *In) SetRawTerminal() (err error) {
    33  	if !i.isTerminal || os.Getenv("NORAW") != "" {
    34  		return nil
    35  	}
    36  	i.state, err = term.SetRawTerminal(i.fd)
    37  	return err
    38  }
    39  
    40  // CheckTty checks if we are trying to attach to a container TTY
    41  // from a non-TTY client input stream, and if so, returns an error.
    42  func (i *In) CheckTty(attachStdin, ttyMode bool) error {
    43  	// In order to attach to a container tty, input stream for the client must
    44  	// be a tty itself: redirecting or piping the client standard input is
    45  	// incompatible with `docker run -t`, `docker exec -t` or `docker attach`.
    46  	if ttyMode && attachStdin && !i.isTerminal {
    47  		const eText = "the input device is not a TTY"
    48  		if runtime.GOOS == "windows" {
    49  			return errors.New(eText + ".  If you are using mintty, try prefixing the command with 'winpty'")
    50  		}
    51  		return errors.New(eText)
    52  	}
    53  	return nil
    54  }
    55  
    56  // NewIn returns a new [In] from an [io.ReadCloser].
    57  func NewIn(in io.ReadCloser) *In {
    58  	i := &In{in: in}
    59  	i.fd, i.isTerminal = term.GetFdInfo(in)
    60  	return i
    61  }