mirror of https://github.com/docker/cli.git
127 lines
3.1 KiB
Go
127 lines
3.1 KiB
Go
package container
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
gosignal "os/signal"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/docker/pkg/signal"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// resizeTtyTo resizes tty to specific height and width
|
|
func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, isExec bool) error {
|
|
if height == 0 && width == 0 {
|
|
return nil
|
|
}
|
|
|
|
options := types.ResizeOptions{
|
|
Height: height,
|
|
Width: width,
|
|
}
|
|
|
|
var err error
|
|
if isExec {
|
|
err = client.ContainerExecResize(ctx, id, options)
|
|
} else {
|
|
err = client.ContainerResize(ctx, id, options)
|
|
}
|
|
|
|
if err != nil {
|
|
logrus.Debugf("Error resize: %s\r", err)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// resizeTty is to resize the tty with cli out's tty size
|
|
func resizeTty(ctx context.Context, cli command.Cli, id string, isExec bool) error {
|
|
height, width := cli.Out().GetTtySize()
|
|
return resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
|
|
}
|
|
|
|
// initTtySize is to init the tty's size to the same as the window, if there is an error, it will retry 5 times.
|
|
func initTtySize(ctx context.Context, cli command.Cli, id string, isExec bool, resizeTtyFunc func(ctx context.Context, cli command.Cli, id string, isExec bool) error) {
|
|
rttyFunc := resizeTtyFunc
|
|
if rttyFunc == nil {
|
|
rttyFunc = resizeTty
|
|
}
|
|
if err := rttyFunc(ctx, cli, id, isExec); err != nil {
|
|
go func() {
|
|
var err error
|
|
for retry := 0; retry < 5; retry++ {
|
|
time.Sleep(10 * time.Millisecond)
|
|
if err = rttyFunc(ctx, cli, id, isExec); err == nil {
|
|
break
|
|
}
|
|
}
|
|
if err != nil {
|
|
fmt.Fprintln(cli.Err(), "failed to resize tty, using default size")
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
// MonitorTtySize updates the container tty size when the terminal tty changes size
|
|
func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool) error {
|
|
initTtySize(ctx, cli, id, isExec, resizeTty)
|
|
if runtime.GOOS == "windows" {
|
|
go func() {
|
|
prevH, prevW := cli.Out().GetTtySize()
|
|
for {
|
|
time.Sleep(time.Millisecond * 250)
|
|
h, w := cli.Out().GetTtySize()
|
|
|
|
if prevW != w || prevH != h {
|
|
resizeTty(ctx, cli, id, isExec)
|
|
}
|
|
prevH = h
|
|
prevW = w
|
|
}
|
|
}()
|
|
} else {
|
|
sigchan := make(chan os.Signal, 1)
|
|
gosignal.Notify(sigchan, signal.SIGWINCH)
|
|
go func() {
|
|
for range sigchan {
|
|
resizeTty(ctx, cli, id, isExec)
|
|
}
|
|
}()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ForwardAllSignals forwards signals to the container
|
|
func ForwardAllSignals(ctx context.Context, cli command.Cli, cid string) chan os.Signal {
|
|
sigc := make(chan os.Signal, 128)
|
|
signal.CatchAll(sigc)
|
|
go func() {
|
|
for s := range sigc {
|
|
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
|
continue
|
|
}
|
|
var sig string
|
|
for sigStr, sigN := range signal.SignalMap {
|
|
if sigN == s {
|
|
sig = sigStr
|
|
break
|
|
}
|
|
}
|
|
if sig == "" {
|
|
fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s)
|
|
continue
|
|
}
|
|
|
|
if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
|
|
logrus.Debugf("Error sending signal: %s", err)
|
|
}
|
|
}
|
|
}()
|
|
return sigc
|
|
}
|