浏览代码

Merge pull request #1462 from docker/rawTerminal

set terminal in character mode when attached to a container
Guillaume Tardif 4 年之前
父节点
当前提交
ee4e85ae1d
共有 5 个文件被更改,包括 44 次插入14 次删除
  1. 2 2
      api/compose/api.go
  2. 24 9
      local/compose/attach.go
  3. 1 1
      local/compose/create.go
  4. 2 1
      local/compose/run.go
  5. 15 1
      utils/logs.go

+ 2 - 2
api/compose/api.go

@@ -186,8 +186,8 @@ type RunOptions struct {
 	Entrypoint        []string
 	Detach            bool
 	AutoRemove        bool
-	Writer            io.Writer
-	Reader            io.Reader
+	Writer            io.WriteCloser
+	Reader            io.ReadCloser
 	Tty               bool
 	WorkingDir        string
 	User              string

+ 24 - 9
local/compose/attach.go

@@ -27,6 +27,7 @@ import (
 	"github.com/docker/compose-cli/utils"
 
 	"github.com/compose-spec/compose-go/types"
+	"github.com/docker/cli/cli/streams"
 	moby "github.com/docker/docker/api/types"
 	"github.com/docker/docker/pkg/stdcopy"
 )
@@ -108,26 +109,40 @@ func (s *composeService) attachContainer(ctx context.Context, container moby.Con
 		Service:   container.Labels[serviceLabel],
 	})
 
-	return s.attachContainerStreams(ctx, container.ID, service.Tty, nil, w)
+	_, err = s.attachContainerStreams(ctx, container.ID, service.Tty, nil, w)
+	return err
 }
 
-func (s *composeService) attachContainerStreams(ctx context.Context, container string, tty bool, r io.Reader, w io.Writer) error {
+func (s *composeService) attachContainerStreams(ctx context.Context, container string, tty bool, r io.ReadCloser, w io.Writer) (func(), error) {
+	var (
+		in      *streams.In
+		restore = func() { /* noop */ }
+	)
+	if r != nil {
+		in = streams.NewIn(r)
+		restore = in.RestoreTerminal
+	}
+
 	stdin, stdout, err := s.getContainerStreams(ctx, container)
 	if err != nil {
-		return err
+		return restore, err
 	}
 
 	go func() {
 		<-ctx.Done()
-		stdout.Close() //nolint:errcheck
-		if stdin != nil {
-			stdin.Close() //nolint:errcheck
+		if in != nil {
+			in.Close() //nolint:errcheck
 		}
+		stdout.Close() //nolint:errcheck
 	}()
 
-	if r != nil && stdin != nil {
+	if in != nil && stdin != nil {
+		err := in.SetRawTerminal()
+		if err != nil {
+			return restore, err
+		}
 		go func() {
-			io.Copy(stdin, r) //nolint:errcheck
+			io.Copy(stdin, in) //nolint:errcheck
 		}()
 	}
 
@@ -140,7 +155,7 @@ func (s *composeService) attachContainerStreams(ctx context.Context, container s
 			}
 		}()
 	}
-	return nil
+	return restore, nil
 }
 
 func (s *composeService) getContainerStreams(ctx context.Context, container string) (io.WriteCloser, io.ReadCloser, error) {

+ 1 - 1
local/compose/create.go

@@ -249,7 +249,7 @@ func (s *composeService) getCreateOptions(ctx context.Context, p *types.Project,
 		ExposedPorts:    buildContainerPorts(service),
 		Tty:             tty,
 		OpenStdin:       stdinOpen,
-		StdinOnce:       true,
+		StdinOnce:       attachStdin && stdinOpen,
 		AttachStdin:     attachStdin,
 		AttachStderr:    true,
 		AttachStdout:    true,

+ 2 - 1
local/compose/run.go

@@ -86,10 +86,11 @@ func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.
 		return 0, err
 	}
 	oneoffContainer := containers[0]
-	err = s.attachContainerStreams(ctx, oneoffContainer.ID, service.Tty, opts.Reader, opts.Writer)
+	restore, err := s.attachContainerStreams(ctx, oneoffContainer.ID, service.Tty, opts.Reader, opts.Writer)
 	if err != nil {
 		return 0, err
 	}
+	defer restore()
 
 	err = s.apiClient.ContainerStart(ctx, containerID, apitypes.ContainerStartOptions{})
 	if err != nil {

+ 15 - 1
utils/logs.go

@@ -62,7 +62,7 @@ func (a *allowListLogConsumer) Register(name string) {
 }
 
 // GetWriter creates a io.Writer that will actually split by line and format by LogConsumer
-func GetWriter(container, service string, events compose.ContainerEventListener) io.Writer {
+func GetWriter(container, service string, events compose.ContainerEventListener) io.WriteCloser {
 	return &splitBuffer{
 		buffer:    bytes.Buffer{},
 		service:   service,
@@ -100,3 +100,17 @@ func (s *splitBuffer) Write(b []byte) (int, error) {
 	}
 	return n, nil
 }
+
+func (s *splitBuffer) Close() error {
+	b := s.buffer.Bytes()
+	if len(b) == 0 {
+		return nil
+	}
+	s.consumer(compose.ContainerEvent{
+		Type:      compose.ContainerEventLog,
+		Service:   s.service,
+		Container: s.container,
+		Line:      string(b),
+	})
+	return nil
+}