github.com/olljanat/moby@v1.13.1/cli/command/in.go (about)

     1  package command
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"os"
     7  	"runtime"
     8  
     9  	"github.com/docker/docker/pkg/term"
    10  )
    11  
    12  // InStream is an input stream used by the DockerCli to read user input
    13  type InStream struct {
    14  	in         io.ReadCloser
    15  	fd         uintptr
    16  	isTerminal bool
    17  	state      *term.State
    18  }
    19  
    20  func (i *InStream) Read(p []byte) (int, error) {
    21  	return i.in.Read(p)
    22  }
    23  
    24  // Close implements the Closer interface
    25  func (i *InStream) Close() error {
    26  	return i.in.Close()
    27  }
    28  
    29  // FD returns the file descriptor number for this stream
    30  func (i *InStream) FD() uintptr {
    31  	return i.fd
    32  }
    33  
    34  // IsTerminal returns true if this stream is connected to a terminal
    35  func (i *InStream) IsTerminal() bool {
    36  	return i.isTerminal
    37  }
    38  
    39  // SetRawTerminal sets raw mode on the input terminal
    40  func (i *InStream) SetRawTerminal() (err error) {
    41  	if os.Getenv("NORAW") != "" || !i.isTerminal {
    42  		return nil
    43  	}
    44  	i.state, err = term.SetRawTerminal(i.fd)
    45  	return err
    46  }
    47  
    48  // RestoreTerminal restores normal mode to the terminal
    49  func (i *InStream) RestoreTerminal() {
    50  	if i.state != nil {
    51  		term.RestoreTerminal(i.fd, i.state)
    52  	}
    53  }
    54  
    55  // CheckTty checks if we are trying to attach to a container tty
    56  // from a non-tty client input stream, and if so, returns an error.
    57  func (i *InStream) CheckTty(attachStdin, ttyMode bool) error {
    58  	// In order to attach to a container tty, input stream for the client must
    59  	// be a tty itself: redirecting or piping the client standard input is
    60  	// incompatible with `docker run -t`, `docker exec -t` or `docker attach`.
    61  	if ttyMode && attachStdin && !i.isTerminal {
    62  		eText := "the input device is not a TTY"
    63  		if runtime.GOOS == "windows" {
    64  			return errors.New(eText + ".  If you are using mintty, try prefixing the command with 'winpty'")
    65  		}
    66  		return errors.New(eText)
    67  	}
    68  	return nil
    69  }
    70  
    71  // NewInStream returns a new InStream object from a ReadCloser
    72  func NewInStream(in io.ReadCloser) *InStream {
    73  	fd, isTerminal := term.GetFdInfo(in)
    74  	return &InStream{in: in, fd: fd, isTerminal: isTerminal}
    75  }