Skip to content

Commit

Permalink
Move attach command to cobra.
Browse files Browse the repository at this point in the history
Signed-off-by: Zhang Wei <[email protected]>
  • Loading branch information
WeiZhang555 committed Jun 6, 2016
1 parent 07a7c06 commit eceb862
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 121 deletions.
113 changes: 0 additions & 113 deletions api/client/attach.go

This file was deleted.

1 change: 0 additions & 1 deletion api/client/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
130 changes: 130 additions & 0 deletions api/client/container/attach.go
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 4 additions & 2 deletions api/client/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
1 change: 1 addition & 0 deletions cli/cobraadaptor/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
1 change: 0 additions & 1 deletion cli/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand Down
8 changes: 4 additions & 4 deletions integration-cli/docker_cli_run_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit eceb862

Please sign in to comment.