github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/command/container/tty.go (about) 1 package container 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 gosignal "os/signal" 8 "runtime" 9 "time" 10 11 "github.com/docker/cli/cli/command" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/client" 14 "github.com/docker/docker/pkg/signal" 15 "github.com/sirupsen/logrus" 16 ) 17 18 // resizeTtyTo resizes tty to specific height and width 19 func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, isExec bool) error { 20 if height == 0 && width == 0 { 21 return nil 22 } 23 24 options := types.ResizeOptions{ 25 Height: height, 26 Width: width, 27 } 28 29 var err error 30 if isExec { 31 err = client.ContainerExecResize(ctx, id, options) 32 } else { 33 err = client.ContainerResize(ctx, id, options) 34 } 35 36 if err != nil { 37 logrus.Debugf("Error resize: %s\r", err) 38 } 39 return err 40 } 41 42 // resizeTty is to resize the tty with cli out's tty size 43 func resizeTty(ctx context.Context, cli command.Cli, id string, isExec bool) error { 44 height, width := cli.Out().GetTtySize() 45 return resizeTtyTo(ctx, cli.Client(), id, height, width, isExec) 46 } 47 48 // initTtySize is to init the tty's size to the same as the window, if there is an error, it will retry 5 times. 49 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) { 50 rttyFunc := resizeTtyFunc 51 if rttyFunc == nil { 52 rttyFunc = resizeTty 53 } 54 if err := rttyFunc(ctx, cli, id, isExec); err != nil { 55 go func() { 56 var err error 57 for retry := 0; retry < 5; retry++ { 58 time.Sleep(10 * time.Millisecond) 59 if err = rttyFunc(ctx, cli, id, isExec); err == nil { 60 break 61 } 62 } 63 if err != nil { 64 fmt.Fprintln(cli.Err(), "failed to resize tty, using default size") 65 } 66 }() 67 } 68 } 69 70 // MonitorTtySize updates the container tty size when the terminal tty changes size 71 func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool) error { 72 initTtySize(ctx, cli, id, isExec, resizeTty) 73 if runtime.GOOS == "windows" { 74 go func() { 75 prevH, prevW := cli.Out().GetTtySize() 76 for { 77 time.Sleep(time.Millisecond * 250) 78 h, w := cli.Out().GetTtySize() 79 80 if prevW != w || prevH != h { 81 resizeTty(ctx, cli, id, isExec) 82 } 83 prevH = h 84 prevW = w 85 } 86 }() 87 } else { 88 sigchan := make(chan os.Signal, 1) 89 gosignal.Notify(sigchan, signal.SIGWINCH) 90 go func() { 91 for range sigchan { 92 resizeTty(ctx, cli, id, isExec) 93 } 94 }() 95 } 96 return nil 97 }