working tty
This commit is contained in:
parent
22f5e35579
commit
e5104a4cb4
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")
|
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 rtime.graph.LookupRemoteImage(name, rtime.authConfig) {
|
||||||
if err := rtime.graph.PullImage(file, name, rtime.authConfig); err != nil {
|
if err := rtime.graph.PullImage(file, name, rtime.authConfig); err != nil {
|
||||||
fmt.Fprintln(file, "Error: "+err.Error())
|
fmt.Fprintln(file, "Error: "+err.Error())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := rtime.graph.PullRepository(file, name, "", rtime.repositories, rtime.authConfig); err != nil {
|
if err := rtime.graph.PullRepository(file, name, "", rtime.repositories, rtime.authConfig); err != nil {
|
||||||
fmt.Fprintln(file, "Error: "+err.Error())
|
fmt.Fprintln(file, "Error: "+err.Error())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Path("/containers").Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
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()
|
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")
|
fmt.Fprintln(file, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n")
|
||||||
container, err := rtime.Create(&config)
|
container, err := rtime.Create(&config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -493,7 +505,7 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
||||||
fmt.Fprintln(file, "Error: "+err.Error())
|
fmt.Fprintln(file, "Error: "+err.Error())
|
||||||
return
|
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())
|
fmt.Fprintln(file, "Error: "+err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -523,7 +535,7 @@ func ListenAndServe(addr string, rtime *Runtime) error {
|
||||||
cStdout = file
|
cStdout = file
|
||||||
}
|
}
|
||||||
if config.AttachStderr {
|
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)
|
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")
|
Debugf("Waiting for attach to return\n")
|
||||||
<-attachErr
|
<-attachErr
|
||||||
// Expecting I/O pipe error, discarding
|
// 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) {
|
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"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/dotcloud/docker/term"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"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
|
var body io.Reader
|
||||||
if data != nil {
|
if data != nil {
|
||||||
buf, err := json.Marshal(data)
|
buf, err := json.Marshal(data)
|
||||||
|
@ -996,6 +997,14 @@ func callStream(method, path string, data interface{}, isTerminal bool) error {
|
||||||
rwc, _ := clientconn.Hijack()
|
rwc, _ := clientconn.Hijack()
|
||||||
defer rwc.Close()
|
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 {
|
receiveStdout := Go(func() error {
|
||||||
_, err := io.Copy(os.Stdout, rwc)
|
_, err := io.Copy(os.Stdout, rwc)
|
||||||
return err
|
return err
|
||||||
|
@ -1009,7 +1018,7 @@ func callStream(method, path string, data interface{}, isTerminal bool) error {
|
||||||
if err := <-receiveStdout; err != nil {
|
if err := <-receiveStdout; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if isTerminal {
|
if !term.IsTerminal(int(os.Stdin.Fd())) {
|
||||||
if err := <-sendStdin; err != nil {
|
if err := <-sendStdin; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
21
utils.go
21
utils.go
|
@ -5,12 +5,14 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/rcli"
|
"github.com/dotcloud/docker/rcli"
|
||||||
|
"github.com/dotcloud/docker/term"
|
||||||
"index/suffixarray"
|
"index/suffixarray"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -384,3 +386,22 @@ func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
||||||
}
|
}
|
||||||
return written, err
|
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…
Reference in New Issue