Skip to content

Commit 63ea4f9

Browse files
committed
feat: cp docker cli code
1 parent 35bf3cd commit 63ea4f9

File tree

2 files changed

+56
-73
lines changed

2 files changed

+56
-73
lines changed

internal/command/cli.go

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,13 @@ func (cli *DebugCli) ContainerClean(ctx context.Context, id string) error {
383383
}
384384

385385
// ExecCreate exec create
386-
func (cli *DebugCli) ExecCreate(options execOptions, container string) (types.IDResponse, error) {
386+
func (cli *DebugCli) ExecCreate(options execOptions, containerStr string) (types.IDResponse, error) {
387387
var workDir = options.workDir
388388
if workDir == "" && cli.config.MountDir != "" {
389389
workDir = path.Join(cli.config.MountDir, options.targetDir)
390390
}
391-
opt := types.ExecConfig{
391+
h, w := cli.out.GetTtySize()
392+
opt := container.ExecOptions{
392393
User: options.user,
393394
Privileged: options.privileged,
394395
DetachKeys: options.detachKeys,
@@ -398,34 +399,67 @@ func (cli *DebugCli) ExecCreate(options execOptions, container string) (types.ID
398399
AttachStdout: true,
399400
WorkingDir: workDir,
400401
Cmd: options.command,
402+
ConsoleSize: &[2]uint{h, w},
401403
}
402404
ctx, cancel := cli.withContent(cli.config.Timeout)
403405
defer cancel()
404-
resp, err := cli.client.ContainerExecCreate(ctx, container, opt)
406+
resp, err := cli.client.ContainerExecCreate(ctx, containerStr, opt)
405407
return resp, errors.WithStack(err)
406408
}
407409

408410
// ExecStart exec start
409-
func (cli *DebugCli) ExecStart(_ execOptions, execID string) error {
410-
execConfig := types.ExecStartCheck{
411-
Tty: true,
411+
func (cli *DebugCli) ExecStart(options execOptions, execID string) error {
412+
h, w := cli.out.GetTtySize()
413+
execConfig := container.ExecStartOptions{
414+
Tty: true,
415+
ConsoleSize: &[2]uint{h, w},
412416
}
413417

414418
ctx, cancel := cli.withContent(cli.config.Timeout)
415-
response, err := cli.client.ContainerExecAttach(ctx, execID, execConfig)
416419
defer cancel()
420+
response, err := cli.client.ContainerExecAttach(ctx, execID, execConfig)
417421
if err != nil {
418422
return errors.WithStack(err)
419423
}
420-
streamer := tty.HijackedIOStreamer{
421-
Streams: cli,
422-
InputStream: cli.in,
423-
OutputStream: cli.out,
424-
ErrorStream: cli.err,
425-
Resp: response,
426-
TTY: true,
424+
defer response.Close()
425+
errCh := make(chan error, 1)
426+
go func() {
427+
defer close(errCh)
428+
streamer := tty.HijackedIOStreamer{
429+
Streams: cli,
430+
InputStream: cli.in,
431+
OutputStream: cli.out,
432+
ErrorStream: cli.err,
433+
Resp: response,
434+
TTY: true,
435+
DetachKeys: options.detachKeys,
436+
}
437+
errCh <- streamer.Stream(cli.ctx)
438+
}()
439+
if err := tty.MonitorTtySize(cli.ctx, cli.client, cli.out, execID, true); err != nil {
440+
_, _ = fmt.Fprintln(cli.err, "Error monitoring TTY size:", err)
427441
}
428-
return streamer.Stream(cli.ctx, cli.config.ReadTimeout)
442+
if err := <-errCh; err != nil {
443+
logrus.Debugf("Error hijack: %s", err)
444+
return err
445+
}
446+
return getExecExitStatus(cli.ctx, cli.client, execID)
447+
}
448+
449+
func getExecExitStatus(ctx context.Context, apiClient client.ContainerAPIClient, execID string) error {
450+
resp, err := apiClient.ContainerExecInspect(ctx, execID)
451+
if err != nil {
452+
// If we can't connect, then the daemon probably died.
453+
if !client.IsErrConnectionFailed(err) {
454+
return err
455+
}
456+
return errors.Errorf("ExitStatus %d", -1)
457+
}
458+
status := resp.ExitCode
459+
if status != 0 {
460+
return errors.Errorf("ExitStatus %d", status)
461+
}
462+
return nil
429463
}
430464

431465
// FindContainer find container

pkg/tty/hijack.go

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@ package tty
22

33
import (
44
"context"
5-
"io"
6-
"net"
7-
"runtime"
8-
"sync"
9-
"time"
10-
115
"github.com/docker/docker/api/types"
126
"github.com/docker/docker/pkg/ioutils"
137
"github.com/docker/docker/pkg/stdcopy"
148
"github.com/moby/term"
159
"github.com/pkg/errors"
1610
"github.com/sirupsen/logrus"
1711
"github.com/zeromake/docker-debug/pkg/stream"
12+
"io"
13+
"runtime"
14+
"sync"
1815
)
1916

2017
// The default escape key sequence: ctrl-p, ctrl-q
@@ -39,7 +36,7 @@ type HijackedIOStreamer struct {
3936
// to/from the hijacked connection, blocking until it is either done reading
4037
// output, the user inputs the detach key sequence when in TTY mode, or when
4138
// the given context is cancelled.
42-
func (h *HijackedIOStreamer) Stream(ctx context.Context, readTimeout time.Duration) error {
39+
func (h *HijackedIOStreamer) Stream(ctx context.Context) error {
4340
restoreInput, err := h.setupInput()
4441
if err != nil {
4542
return errors.Errorf("unable to setup input stream: %s", err)
@@ -48,7 +45,7 @@ func (h *HijackedIOStreamer) Stream(ctx context.Context, readTimeout time.Durati
4845
defer restoreInput()
4946
defer h.Resp.Close()
5047
outputDone := h.beginOutputStream(restoreInput)
51-
inputDone, detached := h.beginInputStream(ctx, restoreInput, readTimeout)
48+
inputDone, detached := h.beginInputStream(restoreInput)
5249

5350
select {
5451
case err = <-outputDone:
@@ -143,61 +140,13 @@ func (h *HijackedIOStreamer) beginOutputStream(restoreInput func()) <-chan error
143140
return outputDone
144141
}
145142

146-
var errInvalidWrite = errors.New("invalid write result")
147-
148-
func Copy(ctx context.Context, dst net.Conn, src io.Reader, writeTimeout time.Duration) (written int64, err error) {
149-
size := 32 * 1024
150-
buf := make([]byte, size)
151-
for {
152-
select {
153-
case <-ctx.Done():
154-
err = ctx.Err()
155-
return
156-
default:
157-
}
158-
nr, er := src.Read(buf)
159-
if nr > 0 {
160-
// docker container is stop check
161-
if writeTimeout > 0 {
162-
err = dst.SetWriteDeadline(time.Now().Add(writeTimeout))
163-
if err != nil {
164-
break
165-
}
166-
}
167-
nw, ew := dst.Write(buf[0:nr])
168-
if nw < 0 || nr < nw {
169-
nw = 0
170-
if ew == nil {
171-
ew = errInvalidWrite
172-
}
173-
}
174-
written += int64(nw)
175-
if ew != nil {
176-
err = ew
177-
break
178-
}
179-
if nr != nw {
180-
err = io.ErrShortWrite
181-
break
182-
}
183-
}
184-
if er != nil {
185-
if er != io.EOF {
186-
err = er
187-
}
188-
break
189-
}
190-
}
191-
return
192-
}
193-
194-
func (h *HijackedIOStreamer) beginInputStream(ctx context.Context, restoreInput func(), readTimeout time.Duration) (doneC <-chan struct{}, detachedC <-chan error) {
143+
func (h *HijackedIOStreamer) beginInputStream(restoreInput func()) (doneC <-chan struct{}, detachedC <-chan error) {
195144
inputDone := make(chan struct{})
196145
detached := make(chan error)
197146

198147
go func() {
199148
if h.InputStream != nil {
200-
_, err := Copy(ctx, h.Resp.Conn, h.InputStream, readTimeout)
149+
_, err := io.Copy(h.Resp.Conn, h.InputStream)
201150
restoreInput()
202151

203152
logrus.Debug("[hijack] End of stdin")

0 commit comments

Comments
 (0)