mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
working tty
This commit is contained in:
parent
22f5e35579
commit
e5104a4cb4
3 changed files with 60 additions and 12 deletions
38
api.go
38
api.go
|
@ -451,14 +451,14 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
|||
|
||||
fmt.Fprintln(file, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n")
|
||||
if rtime.graph.LookupRemoteImage(name, rtime.authConfig) {
|
||||
if err := rtime.graph.PullImage(file, name, rtime.authConfig); err != nil {
|
||||
fmt.Fprintln(file, "Error: "+err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
if err := rtime.graph.PullRepository(file, name, "", rtime.repositories, rtime.authConfig); err != nil {
|
||||
fmt.Fprintln(file, "Error: "+err.Error())
|
||||
}
|
||||
if err := rtime.graph.PullImage(file, name, rtime.authConfig); err != nil {
|
||||
fmt.Fprintln(file, "Error: "+err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
if err := rtime.graph.PullRepository(file, name, "", rtime.repositories, rtime.authConfig); err != nil {
|
||||
fmt.Fprintln(file, "Error: "+err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
r.Path("/containers").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -482,6 +482,18 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
|||
}
|
||||
defer file.Close()
|
||||
|
||||
if config.Tty {
|
||||
oldState, err := SetRawTerminal()
|
||||
if err != nil {
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
log.Printf("Can't set the terminal in raw mode: %s", err)
|
||||
}
|
||||
} else {
|
||||
defer RestoreTerminal(oldState)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fmt.Fprintln(file, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n")
|
||||
container, err := rtime.Create(&config)
|
||||
if err != nil {
|
||||
|
@ -493,7 +505,7 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
|||
fmt.Fprintln(file, "Error: "+err.Error())
|
||||
return
|
||||
}
|
||||
} else if err := rtime.graph.PullRepository(file, config.Image, "", rtime.repositories, rtime.authConfig); err != nil {
|
||||
} else if err := rtime.graph.PullRepository(file, config.Image, "", rtime.repositories, rtime.authConfig); err != nil {
|
||||
fmt.Fprintln(file, "Error: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
@ -523,7 +535,7 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
|||
cStdout = file
|
||||
}
|
||||
if config.AttachStderr {
|
||||
cStderr = file // FIXME: rcli can't differentiate stdout from stderr
|
||||
cStderr = file // FIXME: api can't differentiate stdout from stderr
|
||||
}
|
||||
|
||||
attachErr := container.Attach(cStdin, file, cStdout, cStderr)
|
||||
|
@ -538,6 +550,12 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
|||
Debugf("Waiting for attach to return\n")
|
||||
<-attachErr
|
||||
// Expecting I/O pipe error, discarding
|
||||
|
||||
// If we are in stdinonce mode, wait for the process to end
|
||||
// otherwise, simply return
|
||||
if config.StdinOnce && !config.Tty {
|
||||
container.Wait()
|
||||
}
|
||||
})
|
||||
|
||||
r.Path("/containers/{name:.*}/attach").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
13
commands.go
13
commands.go
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/term"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -967,7 +968,7 @@ func call(method, path string) ([]byte, error) {
|
|||
|
||||
}
|
||||
|
||||
func callStream(method, path string, data interface{}, isTerminal bool) error {
|
||||
func callStream(method, path string, data interface{}, setRawTerminal bool) error {
|
||||
var body io.Reader
|
||||
if data != nil {
|
||||
buf, err := json.Marshal(data)
|
||||
|
@ -996,6 +997,14 @@ func callStream(method, path string, data interface{}, isTerminal bool) error {
|
|||
rwc, _ := clientconn.Hijack()
|
||||
defer rwc.Close()
|
||||
|
||||
if setRawTerminal && term.IsTerminal(int(os.Stdin.Fd())) && os.Getenv("NORAW") == "" {
|
||||
if oldState, err := SetRawTerminal(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer RestoreTerminal(oldState)
|
||||
}
|
||||
}
|
||||
|
||||
receiveStdout := Go(func() error {
|
||||
_, err := io.Copy(os.Stdout, rwc)
|
||||
return err
|
||||
|
@ -1009,7 +1018,7 @@ func callStream(method, path string, data interface{}, isTerminal bool) error {
|
|||
if err := <-receiveStdout; err != nil {
|
||||
return err
|
||||
}
|
||||
if isTerminal {
|
||||
if !term.IsTerminal(int(os.Stdin.Fd())) {
|
||||
if err := <-sendStdin; err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
21
utils.go
21
utils.go
|
@ -5,12 +5,14 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/rcli"
|
||||
"github.com/dotcloud/docker/term"
|
||||
"index/suffixarray"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -384,3 +386,22 @@ func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
|||
}
|
||||
return written, err
|
||||
}
|
||||
|
||||
func SetRawTerminal() (*term.State, error) {
|
||||
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
_ = <-c
|
||||
term.Restore(int(os.Stdin.Fd()), oldState)
|
||||
os.Exit(0)
|
||||
}()
|
||||
return oldState, err
|
||||
}
|
||||
|
||||
func RestoreTerminal(state *term.State) {
|
||||
term.Restore(int(os.Stdin.Fd()), state)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue