Skip to content

Commit

Permalink
tty initial size error
Browse files Browse the repository at this point in the history
Signed-off-by: Lifubang <lifubang@acmcoder.com>
  • Loading branch information
lifubang committed Nov 21, 2018
1 parent 422baf6 commit a3a34a1
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 26 deletions.
39 changes: 25 additions & 14 deletions cli/command/container/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@ import (

type fakeClient struct {
client.Client
inspectFunc func(string) (types.ContainerJSON, error)
execInspectFunc func(execID string) (types.ContainerExecInspect, 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)
containerStartFunc func(container string, options types.ContainerStartOptions) error
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
infoFunc func() (types.Info, error)
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
waitFunc func(string) (<-chan container.ContainerWaitOKBody, <-chan error)
containerListFunc func(types.ContainerListOptions) ([]types.Container, error)
containerExportFunc func(string) (io.ReadCloser, error)
Version string
inspectFunc func(string) (types.ContainerJSON, error)
execInspectFunc func(execID string) (types.ContainerExecInspect, 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)
containerStartFunc func(container string, options types.ContainerStartOptions) error
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
infoFunc func() (types.Info, error)
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
containerCopyFromFunc func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
logFunc func(string, types.ContainerLogsOptions) (io.ReadCloser, error)
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) {
Expand Down Expand Up @@ -132,3 +136,10 @@ func (f *fakeClient) ContainerExport(_ context.Context, container string) (io.Re
}
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
}
55 changes: 43 additions & 12 deletions cli/command/container/tty.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import (
)

// 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 {
return
return nil
}

options := types.ResizeOptions{
Expand All @@ -34,19 +34,50 @@ func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id strin
}

if err != nil {
logrus.Debugf("Error resize: %s", err)
// We add \r in the end is because
// when we use --debug flag, the first shell prompt don't return to the head of line!
logrus.Debugf("Error resize: %s\r", err)
}
return err
}

// 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 {
resizeTty := func() {
height, width := cli.Out().GetTtySize()
resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
}
// 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)
}

resizeTty()
// safeResizeTty is to resize the tty's size safely
func safeResizeTty(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
}
err := rttyFunc(ctx, cli, id, isExec)
if err != nil {
retryTimes := 5
retry := 0
go func() {
for {
time.Sleep(10 * time.Millisecond)
err = rttyFunc(ctx, cli, id, isExec)
if err != nil {
if retry < retryTimes {
retry++
continue
} else {
fmt.Fprintln(cli.Err(), "Resize tty error, we'll use a default size. You can resize the tty size manually.")
}
}
break
}
}()
}
}

// 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 {
safeResizeTty(ctx, cli, id, isExec, resizeTty)
if runtime.GOOS == "windows" {
go func() {
prevH, prevW := cli.Out().GetTtySize()
Expand All @@ -55,7 +86,7 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
h, w := cli.Out().GetTtySize()

if prevW != w || prevH != h {
resizeTty()
resizeTty(ctx, cli, id, isExec)
}
prevH = h
prevW = w
Expand All @@ -66,7 +97,7 @@ func MonitorTtySize(ctx context.Context, cli command.Cli, id string, isExec bool
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
for range sigchan {
resizeTty()
resizeTty(ctx, cli, id, isExec)
}
}()
}
Expand Down
30 changes: 30 additions & 0 deletions cli/command/container/tty_test.go
Original file line number Diff line number Diff line change
@@ -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 TestSafeResizeTtyErrors(t *testing.T) {
expectedError := "Resize tty error, we'll use a default size. You can resize the tty size manually.\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})
safeResizeTty(ctx, cli, "8mm8nn8tt8bb", true, fakeResizeTtyFunc)
time.Sleep(100 * time.Millisecond)
assert.Check(t, is.Equal(expectedError, cli.ErrBuffer().String()))
}

0 comments on commit a3a34a1

Please sign in to comment.