Improve terminal reuse and attach

Currently attach and the editor do not share the same logic for saving
and restoring the terminal, and are not suitable for nesting (when the
caller wants to create something, attach, and then delete something when
the attach is over).  This commit moves the interrupt protection logic
to a util package and supports nesting interrupt handlers.
This commit is contained in:
Clayton Coleman
2016-02-20 13:53:11 -05:00
parent 4d98abf26c
commit 3a29e3971b
7 changed files with 242 additions and 106 deletions

View File

@@ -23,13 +23,13 @@ import (
"math/rand"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"github.com/docker/docker/pkg/term"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/util/term"
)
const (
@@ -125,7 +125,7 @@ func (e Editor) Launch(path string) error {
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
glog.V(5).Infof("Opening file with editor %v", args)
if err := withSafeTTYAndInterrupts(cmd.Run); err != nil {
if err := (term.TTY{In: os.Stdin, TryDev: true}).Safe(cmd.Run); err != nil {
if err, ok := err.(*exec.Error); ok {
if err.Err == exec.ErrNotFound {
return fmt.Errorf("unable to launch the editor %q", strings.Join(e.Args, " "))
@@ -160,40 +160,6 @@ func (e Editor) LaunchTempFile(prefix, suffix string, r io.Reader) ([]byte, stri
return bytes, path, err
}
// withSafeTTYAndInterrupts invokes the provided function after the terminal
// state has been stored, and then on any error or termination attempts to
// restore the terminal state to its prior behavior. It also eats signals
// for the duration of the function.
func withSafeTTYAndInterrupts(fn func() error) error {
ch := make(chan os.Signal, 1)
signal.Notify(ch, childSignals...)
defer signal.Stop(ch)
inFd := os.Stdin.Fd()
if !term.IsTerminal(inFd) {
if f, err := os.Open("/dev/tty"); err == nil {
defer f.Close()
inFd = f.Fd()
}
}
if term.IsTerminal(inFd) {
state, err := term.SaveState(inFd)
if err != nil {
return err
}
go func() {
if _, ok := <-ch; !ok {
return
}
term.RestoreTerminal(inFd, state)
}()
defer term.RestoreTerminal(inFd, state)
return fn()
}
return fn()
}
func tempFile(prefix, suffix string) (f *os.File, err error) {
dir := os.TempDir()