Jelajahi Sumber

Move attach command to cobra.

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Zhang Wei 9 tahun lalu
induk
melakukan
eceb8625a9

+ 0 - 113
api/client/attach.go

@@ -1,113 +0,0 @@
-package client
-
-import (
-	"fmt"
-	"io"
-	"net/http/httputil"
-
-	"golang.org/x/net/context"
-
-	"github.com/Sirupsen/logrus"
-	Cli "github.com/docker/docker/cli"
-	flag "github.com/docker/docker/pkg/mflag"
-	"github.com/docker/docker/pkg/signal"
-	"github.com/docker/engine-api/types"
-)
-
-// CmdAttach attaches to a running container.
-//
-// Usage: docker attach [OPTIONS] CONTAINER
-func (cli *DockerCli) CmdAttach(args ...string) error {
-	cmd := Cli.Subcmd("attach", []string{"CONTAINER"}, Cli.DockerCommands["attach"].Description, true)
-	noStdin := cmd.Bool([]string{"-no-stdin"}, false, "Do not attach STDIN")
-	proxy := cmd.Bool([]string{"-sig-proxy"}, true, "Proxy all received signals to the process")
-	detachKeys := cmd.String([]string{"-detach-keys"}, "", "Override the key sequence for detaching a container")
-
-	cmd.Require(flag.Exact, 1)
-
-	cmd.ParseFlags(args, true)
-
-	ctx := context.Background()
-
-	c, err := cli.client.ContainerInspect(ctx, cmd.Arg(0))
-	if err != nil {
-		return err
-	}
-
-	if !c.State.Running {
-		return fmt.Errorf("You cannot attach to a stopped container, start it first")
-	}
-
-	if c.State.Paused {
-		return fmt.Errorf("You cannot attach to a paused container, unpause it first")
-	}
-
-	if err := cli.CheckTtyInput(!*noStdin, c.Config.Tty); err != nil {
-		return err
-	}
-
-	if *detachKeys != "" {
-		cli.configFile.DetachKeys = *detachKeys
-	}
-
-	container := cmd.Arg(0)
-
-	options := types.ContainerAttachOptions{
-		Stream:     true,
-		Stdin:      !*noStdin && c.Config.OpenStdin,
-		Stdout:     true,
-		Stderr:     true,
-		DetachKeys: cli.configFile.DetachKeys,
-	}
-
-	var in io.ReadCloser
-	if options.Stdin {
-		in = cli.in
-	}
-
-	if *proxy && !c.Config.Tty {
-		sigc := cli.ForwardAllSignals(ctx, container)
-		defer signal.StopCatch(sigc)
-	}
-
-	resp, errAttach := cli.client.ContainerAttach(ctx, container, options)
-	if errAttach != nil && errAttach != httputil.ErrPersistEOF {
-		// ContainerAttach returns an ErrPersistEOF (connection closed)
-		// means server met an error and put it in Hijacked connection
-		// keep the error and read detailed error message from hijacked connection later
-		return errAttach
-	}
-	defer resp.Close()
-
-	if c.Config.Tty && cli.isTerminalOut {
-		height, width := cli.GetTtySize()
-		// To handle the case where a user repeatedly attaches/detaches without resizing their
-		// terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially
-		// resize it, then go back to normal. Without this, every attach after the first will
-		// require the user to manually resize or hit enter.
-		cli.resizeTtyTo(ctx, cmd.Arg(0), height+1, width+1, false)
-
-		// After the above resizing occurs, the call to MonitorTtySize below will handle resetting back
-		// to the actual size.
-		if err := cli.MonitorTtySize(ctx, cmd.Arg(0), false); err != nil {
-			logrus.Debugf("Error monitoring TTY size: %s", err)
-		}
-	}
-	if err := cli.HoldHijackedConnection(ctx, c.Config.Tty, in, cli.out, cli.err, resp); err != nil {
-		return err
-	}
-
-	if errAttach != nil {
-		return errAttach
-	}
-
-	_, status, err := cli.GetExitCode(ctx, container)
-	if err != nil {
-		return err
-	}
-	if status != 0 {
-		return Cli.StatusError{StatusCode: status}
-	}
-
-	return nil
-}

+ 0 - 1
api/client/commands.go

@@ -3,7 +3,6 @@ package client
 // Command returns a cli command handler if one exists
 func (cli *DockerCli) Command(name string) func(...string) error {
 	return map[string]func(...string) error{
-		"attach":  cli.CmdAttach,
 		"build":   cli.CmdBuild,
 		"commit":  cli.CmdCommit,
 		"cp":      cli.CmdCp,

+ 130 - 0
api/client/container/attach.go

@@ -0,0 +1,130 @@
+package container
+
+import (
+	"fmt"
+	"io"
+	"net/http/httputil"
+
+	"golang.org/x/net/context"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/api/client"
+	"github.com/docker/docker/cli"
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/engine-api/types"
+	"github.com/spf13/cobra"
+)
+
+type attachOptions struct {
+	noStdin    bool
+	proxy      bool
+	detachKeys string
+
+	container string
+}
+
+// NewAttachCommand creats a new cobra.Command for `docker attach`
+func NewAttachCommand(dockerCli *client.DockerCli) *cobra.Command {
+	var opts attachOptions
+
+	cmd := &cobra.Command{
+		Use:   "attach [OPTIONS] CONTAINER",
+		Short: "Attach to a running container",
+		Args:  cli.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			opts.container = args[0]
+			return runAttach(dockerCli, &opts)
+		},
+	}
+	cmd.SetFlagErrorFunc(flagErrorFunc)
+
+	flags := cmd.Flags()
+	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.StringVar(&opts.detachKeys, "detach-keys", "", "Override the key sequence for detaching a container")
+	return cmd
+}
+
+func runAttach(dockerCli *client.DockerCli, opts *attachOptions) error {
+	ctx := context.Background()
+
+	c, err := dockerCli.Client().ContainerInspect(ctx, opts.container)
+	if err != nil {
+		return err
+	}
+
+	if !c.State.Running {
+		return fmt.Errorf("You cannot attach to a stopped container, start it first")
+	}
+
+	if c.State.Paused {
+		return fmt.Errorf("You cannot attach to a paused container, unpause it first")
+	}
+
+	if err := dockerCli.CheckTtyInput(!opts.noStdin, c.Config.Tty); err != nil {
+		return err
+	}
+
+	if opts.detachKeys != "" {
+		dockerCli.ConfigFile().DetachKeys = opts.detachKeys
+	}
+
+	options := types.ContainerAttachOptions{
+		Stream:     true,
+		Stdin:      !opts.noStdin && c.Config.OpenStdin,
+		Stdout:     true,
+		Stderr:     true,
+		DetachKeys: dockerCli.ConfigFile().DetachKeys,
+	}
+
+	var in io.ReadCloser
+	if options.Stdin {
+		in = dockerCli.In()
+	}
+
+	if opts.proxy && !c.Config.Tty {
+		sigc := dockerCli.ForwardAllSignals(ctx, opts.container)
+		defer signal.StopCatch(sigc)
+	}
+
+	resp, errAttach := dockerCli.Client().ContainerAttach(ctx, opts.container, options)
+	if errAttach != nil && errAttach != httputil.ErrPersistEOF {
+		// ContainerAttach returns an ErrPersistEOF (connection closed)
+		// means server met an error and put it in Hijacked connection
+		// keep the error and read detailed error message from hijacked connection later
+		return errAttach
+	}
+	defer resp.Close()
+
+	if c.Config.Tty && dockerCli.IsTerminalOut() {
+		height, width := dockerCli.GetTtySize()
+		// To handle the case where a user repeatedly attaches/detaches without resizing their
+		// terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially
+		// resize it, then go back to normal. Without this, every attach after the first will
+		// require the user to manually resize or hit enter.
+		dockerCli.ResizeTtyTo(ctx, opts.container, height+1, width+1, false)
+
+		// After the above resizing occurs, the call to MonitorTtySize below will handle resetting back
+		// to the actual size.
+		if err := dockerCli.MonitorTtySize(ctx, opts.container, false); err != nil {
+			logrus.Debugf("Error monitoring TTY size: %s", err)
+		}
+	}
+	if err := dockerCli.HoldHijackedConnection(ctx, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp); err != nil {
+		return err
+	}
+
+	if errAttach != nil {
+		return errAttach
+	}
+
+	_, status, err := dockerCli.GetExitCode(ctx, opts.container)
+	if err != nil {
+		return err
+	}
+	if status != 0 {
+		return cli.StatusError{StatusCode: status}
+	}
+
+	return nil
+}

+ 4 - 2
api/client/utils.go

@@ -62,10 +62,12 @@ func (cli *DockerCli) RegistryAuthenticationPrivilegedFunc(index *registrytypes.
 
 func (cli *DockerCli) resizeTty(ctx context.Context, id string, isExec bool) {
 	height, width := cli.GetTtySize()
-	cli.resizeTtyTo(ctx, id, height, width, isExec)
+	cli.ResizeTtyTo(ctx, id, height, width, isExec)
 }
 
-func (cli *DockerCli) resizeTtyTo(ctx context.Context, id string, height, width int, isExec bool) {
+// ResizeTtyTo resizes tty to specific height and width
+// TODO: this can be unexported again once all container related commands move to package container
+func (cli *DockerCli) ResizeTtyTo(ctx context.Context, id string, height, width int, isExec bool) {
 	if height == 0 && width == 0 {
 		return
 	}

+ 1 - 0
cli/cobraadaptor/adaptor.go

@@ -34,6 +34,7 @@ func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor {
 	rootCmd.SetFlagErrorFunc(cli.FlagErrorFunc)
 	rootCmd.SetOutput(stdout)
 	rootCmd.AddCommand(
+		container.NewAttachCommand(dockerCli),
 		container.NewCreateCommand(dockerCli),
 		container.NewDiffCommand(dockerCli),
 		container.NewExportCommand(dockerCli),

+ 0 - 1
cli/usage.go

@@ -8,7 +8,6 @@ type Command struct {
 
 // DockerCommandUsage lists the top level docker commands and their short usage
 var DockerCommandUsage = []Command{
-	{"attach", "Attach to a running container"},
 	{"build", "Build an image from a Dockerfile"},
 	{"commit", "Create a new image from a container's changes"},
 	{"cp", "Copy files/folders between a container and the local filesystem"},

+ 4 - 4
integration-cli/docker_cli_run_unix_test.go

@@ -150,7 +150,7 @@ func (s *DockerSuite) TestRunAttachDetachFromFlag(c *check.C) {
 
 	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat")
 
-	cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-a,a'", name)
+	cmd := exec.Command(dockerBinary, "attach", "--detach-keys=ctrl-a,a", name)
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		c.Fatal(err)
@@ -210,7 +210,7 @@ func (s *DockerSuite) TestRunAttachDetachFromInvalidFlag(c *check.C) {
 	c.Assert(waitRun(name), check.IsNil)
 
 	// specify an invalid detach key, container will ignore it and use default
-	cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-A,a'", name)
+	cmd := exec.Command(dockerBinary, "attach", "--detach-keys=ctrl-A,a", name)
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		c.Fatal(err)
@@ -348,7 +348,7 @@ func (s *DockerSuite) TestRunAttachDetachKeysOverrideConfig(c *check.C) {
 	name := "attach-detach"
 	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat")
 
-	cmd := exec.Command(dockerBinary, "attach", "--detach-keys='ctrl-a,a'", name)
+	cmd := exec.Command(dockerBinary, "attach", "--detach-keys=ctrl-a,a", name)
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		c.Fatal(err)
@@ -408,7 +408,7 @@ func (s *DockerSuite) TestRunAttachInvalidDetachKeySequencePreserved(c *check.C)
 
 	dockerCmd(c, "run", "--name", name, "-itd", "busybox", "cat")
 
-	cmd := exec.Command(dockerBinary, "attach", "--detach-keys='a,b,c'", name)
+	cmd := exec.Command(dockerBinary, "attach", "--detach-keys=a,b,c", name)
 	stdout, err := cmd.StdoutPipe()
 	if err != nil {
 		c.Fatal(err)