set terminal in character mode when attached to a container

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2021-03-24 15:37:08 +01:00
parent 9f81314124
commit d4a8e92f46
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
5 changed files with 44 additions and 14 deletions

View File

@ -181,8 +181,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

View File

@ -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) {

View File

@ -247,7 +247,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,

View File

@ -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 {

View File

@ -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
}