make runAttach public and allow passing context

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2023-11-06 10:00:13 +01:00
parent 9cb175f02a
commit a4abe42cbd
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
3 changed files with 28 additions and 28 deletions

View File

@ -17,12 +17,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type attachOptions struct { // AttachOptions group options for `attach` command
noStdin bool type AttachOptions struct {
proxy bool NoStdin bool
detachKeys string Proxy bool
DetachKeys string
container string Container string
} }
func inspectContainerAndCheckState(ctx context.Context, cli client.APIClient, args string) (*types.ContainerJSON, error) { func inspectContainerAndCheckState(ctx context.Context, cli client.APIClient, args string) (*types.ContainerJSON, error) {
@ -45,15 +46,15 @@ func inspectContainerAndCheckState(ctx context.Context, cli client.APIClient, ar
// NewAttachCommand creates a new cobra.Command for `docker attach` // NewAttachCommand creates a new cobra.Command for `docker attach`
func NewAttachCommand(dockerCli command.Cli) *cobra.Command { func NewAttachCommand(dockerCli command.Cli) *cobra.Command {
var opts attachOptions var opts AttachOptions
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "attach [OPTIONS] CONTAINER", Use: "attach [OPTIONS] CONTAINER",
Short: "Attach local standard input, output, and error streams to a running container", Short: "Attach local standard input, output, and error streams to a running container",
Args: cli.ExactArgs(1), Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
opts.container = args[0] opts.Container = args[0]
return runAttach(dockerCli, &opts) return RunAttach(context.Background(), dockerCli, &opts)
}, },
Annotations: map[string]string{ Annotations: map[string]string{
"aliases": "docker container attach, docker attach", "aliases": "docker container attach, docker attach",
@ -64,36 +65,36 @@ func NewAttachCommand(dockerCli command.Cli) *cobra.Command {
} }
flags := cmd.Flags() flags := cmd.Flags()
flags.BoolVar(&opts.noStdin, "no-stdin", false, "Do not attach STDIN") flags.BoolVar(&opts.NoStdin, "no-stdin", false, "Do not attach STDIN")
flags.BoolVar(&opts.proxy, "sig-proxy", true, "Proxy all received signals to the process") flags.BoolVar(&opts.Proxy, "sig-proxy", true, "Proxy all received signals to the process")
flags.StringVar(&opts.detachKeys, "detach-keys", "", "Override the key sequence for detaching a container") flags.StringVar(&opts.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
return cmd return cmd
} }
func runAttach(dockerCli command.Cli, opts *attachOptions) error { // RunAttach executes an `attach` command
ctx := context.Background() func RunAttach(ctx context.Context, dockerCli command.Cli, opts *AttachOptions) error {
apiClient := dockerCli.Client() apiClient := dockerCli.Client()
// request channel to wait for client // request channel to wait for client
resultC, errC := apiClient.ContainerWait(ctx, opts.container, "") resultC, errC := apiClient.ContainerWait(ctx, opts.Container, "")
c, err := inspectContainerAndCheckState(ctx, apiClient, opts.container) c, err := inspectContainerAndCheckState(ctx, apiClient, opts.Container)
if err != nil { if err != nil {
return err return err
} }
if err := dockerCli.In().CheckTty(!opts.noStdin, c.Config.Tty); err != nil { if err := dockerCli.In().CheckTty(!opts.NoStdin, c.Config.Tty); err != nil {
return err return err
} }
detachKeys := dockerCli.ConfigFile().DetachKeys detachKeys := dockerCli.ConfigFile().DetachKeys
if opts.detachKeys != "" { if opts.DetachKeys != "" {
detachKeys = opts.detachKeys detachKeys = opts.DetachKeys
} }
options := container.AttachOptions{ options := container.AttachOptions{
Stream: true, Stream: true,
Stdin: !opts.noStdin && c.Config.OpenStdin, Stdin: !opts.NoStdin && c.Config.OpenStdin,
Stdout: true, Stdout: true,
Stderr: true, Stderr: true,
DetachKeys: detachKeys, DetachKeys: detachKeys,
@ -104,13 +105,13 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
in = dockerCli.In() in = dockerCli.In()
} }
if opts.proxy && !c.Config.Tty { if opts.Proxy && !c.Config.Tty {
sigc := notifyAllSignals() sigc := notifyAllSignals()
go ForwardAllSignals(ctx, dockerCli, opts.container, sigc) go ForwardAllSignals(ctx, dockerCli, opts.Container, sigc)
defer signal.StopCatch(sigc) defer signal.StopCatch(sigc)
} }
resp, errAttach := apiClient.ContainerAttach(ctx, opts.container, options) resp, errAttach := apiClient.ContainerAttach(ctx, opts.Container, options)
if errAttach != nil { if errAttach != nil {
return errAttach return errAttach
} }
@ -124,13 +125,13 @@ func runAttach(dockerCli command.Cli, opts *attachOptions) error {
// the container and not exit. // the container and not exit.
// //
// Recheck the container's state to avoid attach block. // Recheck the container's state to avoid attach block.
_, err = inspectContainerAndCheckState(ctx, apiClient, opts.container) _, err = inspectContainerAndCheckState(ctx, apiClient, opts.Container)
if err != nil { if err != nil {
return err return err
} }
if c.Config.Tty && dockerCli.Out().IsTerminal() { if c.Config.Tty && dockerCli.Out().IsTerminal() {
resizeTTY(ctx, dockerCli, opts.container) resizeTTY(ctx, dockerCli, opts.Container)
} }
streamer := hijackedIOStreamer{ streamer := hijackedIOStreamer{

View File

@ -52,7 +52,7 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
options.Container = args[0] options.Container = args[0]
options.Command = args[1:] options.Command = args[1:]
return RunExec(dockerCli, options) return RunExec(context.Background(), dockerCli, options)
}, },
ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(container types.Container) bool { ValidArgsFunction: completion.ContainerNames(dockerCli, false, func(container types.Container) bool {
return container.State != "paused" return container.State != "paused"
@ -96,13 +96,12 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
} }
// RunExec executes an `exec` command // RunExec executes an `exec` command
func RunExec(dockerCli command.Cli, options ExecOptions) error { func RunExec(ctx context.Context, dockerCli command.Cli, options ExecOptions) error {
execConfig, err := parseExec(options, dockerCli.ConfigFile()) execConfig, err := parseExec(options, dockerCli.ConfigFile())
if err != nil { if err != nil {
return err return err
} }
ctx := context.Background()
client := dockerCli.Client() client := dockerCli.Client()
// We need to check the tty _before_ we do the ContainerExecCreate, because // We need to check the tty _before_ we do the ContainerExecCreate, because

View File

@ -195,7 +195,7 @@ func TestRunExec(t *testing.T) {
t.Run(testcase.doc, func(t *testing.T) { t.Run(testcase.doc, func(t *testing.T) {
cli := test.NewFakeCli(&testcase.client) cli := test.NewFakeCli(&testcase.client)
err := RunExec(cli, testcase.options) err := RunExec(context.Background(), cli, testcase.options)
if testcase.expectedError != "" { if testcase.expectedError != "" {
assert.ErrorContains(t, err, testcase.expectedError) assert.ErrorContains(t, err, testcase.expectedError)
} else { } else {