123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- package execdriver
- import (
- "github.com/dotcloud/docker/pkg/term"
- "github.com/kr/pty"
- "io"
- "os"
- )
- type Term interface {
- io.Closer
- Resize(height, width int) error
- }
- type Pipes struct {
- Stdin io.ReadCloser
- Stdout, Stderr io.Writer
- }
- func NewPipes(stdin io.ReadCloser, stdout, stderr io.Writer, useStdin bool) *Pipes {
- p := &Pipes{
- Stdout: stdout,
- Stderr: stderr,
- }
- if useStdin {
- p.Stdin = stdin
- }
- return p
- }
- func SetTerminal(command *Command, pipes *Pipes) error {
- var (
- term Term
- err error
- )
- if command.Tty {
- term, err = NewTtyConsole(command, pipes)
- } else {
- term, err = NewStdConsole(command, pipes)
- }
- if err != nil {
- return err
- }
- command.Terminal = term
- return nil
- }
- type TtyConsole struct {
- Master *os.File
- Slave *os.File
- }
- func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
- ptyMaster, ptySlave, err := pty.Open()
- if err != nil {
- return nil, err
- }
- tty := &TtyConsole{
- Master: ptyMaster,
- Slave: ptySlave,
- }
- if err := tty.attach(command, pipes); err != nil {
- tty.Close()
- return nil, err
- }
- return tty, nil
- }
- func (t *TtyConsole) Resize(h, w int) error {
- return term.SetWinsize(t.Master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
- }
- func (t *TtyConsole) attach(command *Command, pipes *Pipes) error {
- command.Stdout = t.Slave
- command.Stderr = t.Slave
- command.Console = t.Slave.Name()
- go func() {
- if wb, ok := pipes.Stdout.(interface {
- CloseWriters() error
- }); ok {
- defer wb.CloseWriters()
- }
- io.Copy(pipes.Stdout, t.Master)
- }()
- if pipes.Stdin != nil {
- command.Stdin = t.Slave
- command.SysProcAttr.Setctty = true
- go func() {
- defer pipes.Stdin.Close()
- io.Copy(t.Master, pipes.Stdin)
- }()
- }
- return nil
- }
- func (t *TtyConsole) Close() error {
- t.Slave.Close()
- return t.Master.Close()
- }
- type StdConsole struct {
- }
- func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) {
- std := &StdConsole{}
- if err := std.attach(command, pipes); err != nil {
- return nil, err
- }
- return std, nil
- }
- func (s *StdConsole) attach(command *Command, pipes *Pipes) error {
- command.Stdout = pipes.Stdout
- command.Stderr = pipes.Stderr
- if pipes.Stdin != nil {
- stdin, err := command.StdinPipe()
- if err != nil {
- return err
- }
- go func() {
- defer stdin.Close()
- io.Copy(stdin, pipes.Stdin)
- }()
- }
- return nil
- }
- func (s *StdConsole) Resize(h, w int) error {
- // we do not need to reside a non tty
- return nil
- }
- func (s *StdConsole) Close() error {
- // nothing to close here
- return nil
- }
|