Skip to content

Commit

Permalink
fixes tty size error
Browse files Browse the repository at this point in the history
Signed-off-by: Lifubang <lifubang@acmcoder.com>

code optimization

Signed-off-by: Lifubang <lifubang@acmcoder.com>

fixes no such exec error when tty resize

Signed-off-by: Lifubang <lifubang@acmcoder.com>
  • Loading branch information
lifubang committed Nov 15, 2018
1 parent 3ea56aa commit 06fd12f
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 25 deletions.
38 changes: 25 additions & 13 deletions cli/command/container/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +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)
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)
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)
containerExecResizeFunc func(id string, options types.ResizeOptions) error
createContainerFunc func(
config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
containerName string) (container.ContainerCreateCreatedBody, error)
Version string
}

func (f *fakeClient) ContainerList(_ context.Context, options types.ContainerListOptions) ([]types.Container, error) {
Expand Down Expand Up @@ -124,3 +129,10 @@ func (f *fakeClient) ContainerStart(_ context.Context, container string, options
}
return nil
}

func (f *fakeClient) ContainerExecResize(_ context.Context, id string, options types.ResizeOptions) error {
if f.containerExecResizeFunc != nil {
return f.containerExecResizeFunc(id, options)
}
return nil
}
53 changes: 41 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,48 @@ func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id strin
}

if err != nil {
logrus.Debugf("Error resize: %s", err)
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, nil)
if runtime.GOOS == "windows" {
go func() {
prevH, prevW := cli.Out().GetTtySize()
Expand All @@ -55,7 +84,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 +95,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 06fd12f

Please sign in to comment.