Repository: moby/moby
File: client/container_exec.go (Go)

Code before:
	return ExecCreateResult{ID: response.ID}, err
}

type execStartAttachOptions struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
	// Terminal size [height, width], unused if Tty == false
	ConsoleSize *[2]uint `json:",omitempty"`
}

// ExecStartOptions holds options for starting a container exec.
type ExecStartOptions execStartAttachOptions

// ExecStartResult holds the result of starting a container exec.
type ExecStartResult struct {
}

// ExecStart starts an exec process already created in the docker host.
func (cli *Client) ExecStart(ctx context.Context, execID string, options ExecStartOptions) (ExecStartResult, error) {
	req := container.ExecStartRequest{
		Detach:      options.Detach,
		Tty:         options.Tty,
		ConsoleSize: options.ConsoleSize,
	}
	resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, req, nil)
	defer ensureReaderClosed(resp)
	return ExecStartResult{}, err
}

// ExecAttachOptions holds options for attaching to a container exec.
type ExecAttachOptions execStartAttachOptions

// ExecAttachResult holds the result of attaching to a container exec.
type ExecAttachResult struct {
	HijackedResponse
}

// ExecAttach attaches a connection to an exec process in the server.
//
// It returns a [HijackedResponse] with the hijacked connection
// and a reader to get output. It's up to the called to close
// the hijacked connection by calling [HijackedResponse.Close].
//
// The stream format on the response uses one of two formats:
//
//   - If the container is using a TTY, there is only a single stream (stdout)
//     and data is copied directly from the container output stream, no extra
//     multiplexing or headers.
//   - If the container is *not* using a TTY, streams for stdout and stderr are

Review comment (suggestion):
For a follow-up, I'm considering;

- Perhaps we should ditch `ExecAttach` altogether, and just have `ExecStart` (with options to attach)
- Change `Detach` to `Attach`, so that `ExecStart` defaults to just "starting", but optionally allows to attach.



Code after:
	err = json.NewDecoder(resp.Body).Decode(&response)
	return ExecCreateResult{ID: response.ID}, err
}

type ConsoleSize struct {
	Height, Width uint
}

// ExecStartOptions holds options for starting a container exec.
type ExecStartOptions struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	TTY bool
	// Terminal size [height, width], unused if TTY == false
	ConsoleSize ConsoleSize `json:",omitzero"`
}

// ExecStartResult holds the result of starting a container exec.
type ExecStartResult struct {
}

// ExecStart starts an exec process already created in the docker host.
func (cli *Client) ExecStart(ctx context.Context, execID string, options ExecStartOptions) (ExecStartResult, error) {
	req := container.ExecStartRequest{
		Detach: options.Detach,
		Tty:    options.TTY,
	}
	if err := applyConsoleSize(&req, &options.ConsoleSize); err != nil {
		return ExecStartResult{}, err
	}
	resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, req, nil)
	defer ensureReaderClosed(resp)
	return ExecStartResult{}, err
}

// ExecAttachOptions holds options for attaching to a container exec.
type ExecAttachOptions struct {
	// Check if there's a tty
	TTY bool
	// Terminal size [height, width], unused if TTY == false
	ConsoleSize ConsoleSize `json:",omitzero"`
}

// ExecAttachResult holds the result of attaching to a container exec.
type ExecAttachResult struct {
	HijackedResponse
}

// ExecAttach attaches a connection to an exec process in the server.
//