mirror of https://github.com/docker/cli.git
Merge pull request #1529 from lifubang/ttyexecresize
fixes 1492: tty initial size error
This commit is contained in:
commit
7f612bfca6
|
@ -12,20 +12,24 @@ import (
|
||||||
|
|
||||||
type fakeClient struct {
|
type fakeClient struct {
|
||||||
client.Client
|
client.Client
|
||||||
inspectFunc func(string) (types.ContainerJSON, error)
|
inspectFunc func(string) (types.ContainerJSON, error)
|
||||||
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
|
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
|
||||||
execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error)
|
execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error)
|
||||||
createContainerFunc func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error)
|
createContainerFunc func(config *container.Config,
|
||||||
containerStartFunc func(container string, options types.ContainerStartOptions) error
|
hostConfig *container.HostConfig,
|
||||||
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
|
networkingConfig *network.NetworkingConfig,
|
||||||
infoFunc func() (types.Info, error)
|
containerName string) (container.ContainerCreateCreatedBody, error)
|
||||||
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
|
containerStartFunc func(container string, options types.ContainerStartOptions) error
|
||||||
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
|
||||||
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
|
infoFunc func() (types.Info, error)
|
||||||
waitFunc func(string) (<-chan container.ContainerWaitOKBody, <-chan error)
|
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
|
||||||
containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
|
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
|
||||||
containerExportFunc func(string) (io.ReadCloser, error)
|
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
|
||||||
Version string
|
waitFunc func(string) (<-chan container.ContainerWaitOKBody, <-chan error)
|
||||||
|
containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
|
||||||
|
containerExportFunc func(string) (io.ReadCloser, error)
|
||||||
|
containerExecResizeFunc func(id string, options types.ResizeOptions) error
|
||||||
|
Version string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeClient) ContainerList(_ context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
func (f *fakeClient) ContainerList(_ context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
||||||
|
@ -132,3 +136,10 @@ func (f *fakeClient) ContainerExport(_ context.Context, container string) (io.Re
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fakeClient) ContainerExecResize(_ context.Context, id string, options types.ResizeOptions) error {
|
||||||
|
if f.containerExecResizeFunc != nil {
|
||||||
|
return f.containerExecResizeFunc(id, options)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// resizeTtyTo resizes tty to specific height and width
|
// resizeTtyTo resizes tty to specific height and width
|
||||||
func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, isExec bool) {
|
func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, isExec bool) error {
|
||||||
if height == 0 && width == 0 {
|
if height == 0 && width == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
options := types.ResizeOptions{
|
options := types.ResizeOptions{
|
||||||
|
@ -34,19 +34,42 @@ func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id strin
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("Error resize: %s", err)
|
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
|
// 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 {
|
func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool) error {
|
||||||
resizeTty := func() {
|
initTtySize(ctx, cli, id, isExec, resizeTty)
|
||||||
height, width := cli.Out().GetTtySize()
|
|
||||||
resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
|
|
||||||
}
|
|
||||||
|
|
||||||
resizeTty()
|
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
go func() {
|
go func() {
|
||||||
prevH, prevW := cli.Out().GetTtySize()
|
prevH, prevW := cli.Out().GetTtySize()
|
||||||
|
@ -55,7 +78,7 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
|
||||||
h, w := cli.Out().GetTtySize()
|
h, w := cli.Out().GetTtySize()
|
||||||
|
|
||||||
if prevW != w || prevH != h {
|
if prevW != w || prevH != h {
|
||||||
resizeTty()
|
resizeTty(ctx, cli, id, isExec)
|
||||||
}
|
}
|
||||||
prevH = h
|
prevH = h
|
||||||
prevW = w
|
prevW = w
|
||||||
|
@ -66,7 +89,7 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
|
||||||
gosignal.Notify(sigchan, signal.SIGWINCH)
|
gosignal.Notify(sigchan, signal.SIGWINCH)
|
||||||
go func() {
|
go func() {
|
||||||
for range sigchan {
|
for range sigchan {
|
||||||
resizeTty()
|
resizeTty(ctx, cli, id, isExec)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/docker/cli/internal/test"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gotest.tools/assert"
|
||||||
|
is "gotest.tools/assert/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInitTtySizeErrors(t *testing.T) {
|
||||||
|
expectedError := "failed to resize tty, using default size\n"
|
||||||
|
fakeContainerExecResizeFunc := func(id string, options types.ResizeOptions) error {
|
||||||
|
return errors.Errorf("Error response from daemon: no such exec")
|
||||||
|
}
|
||||||
|
fakeResizeTtyFunc := func(ctx context.Context, cli command.Cli, id string, isExec bool) error {
|
||||||
|
height, width := uint(1024), uint(768)
|
||||||
|
return resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
cli := test.NewFakeCli(&fakeClient{containerExecResizeFunc: fakeContainerExecResizeFunc})
|
||||||
|
initTtySize(ctx, cli, "8mm8nn8tt8bb", true, fakeResizeTtyFunc)
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
assert.Check(t, is.Equal(expectedError, cli.ErrBuffer().String()))
|
||||||
|
}
|
Loading…
Reference in New Issue