diff --git a/api.go b/api.go index 81b4ff963b..e66dc1e648 100644 --- a/api.go +++ b/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) { diff --git a/commands.go b/commands.go index e39c03f242..c934fe6bb4 100644 --- a/commands.go +++ b/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 } diff --git a/utils.go b/utils.go index 68e12b20bd..5ff1ad7a03 100644 --- a/utils.go +++ b/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) +}