Browse code

api/client: Allow for multi-line usage help

Subcommands can provide multiple usage synopses.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)

Josh Hawn authored on 2015/05/14 11:45:01
Showing 42 changed files
... ...
@@ -17,7 +17,7 @@ import (
17 17
 // Usage: docker attach [OPTIONS] CONTAINER
18 18
 func (cli *DockerCli) CmdAttach(args ...string) error {
19 19
 	var (
20
-		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
20
+		cmd     = cli.Subcmd("attach", []string{"CONTAINER"}, "Attach to a running container", true)
21 21
 		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
22 22
 		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process")
23 23
 	)
... ...
@@ -43,7 +43,7 @@ const (
43 43
 //
44 44
 // Usage: docker build [OPTIONS] PATH | URL | -
45 45
 func (cli *DockerCli) CmdBuild(args ...string) error {
46
-	cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
46
+	cmd := cli.Subcmd("build", []string{"PATH | URL | -"}, "Build a new image from the source code at PATH", true)
47 47
 	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) for the image")
48 48
 	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
49 49
 	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
... ...
@@ -107,29 +107,62 @@ func (cli *DockerCli) Cmd(args ...string) error {
107 107
 // A subcommand represents an action that can be performed
108 108
 // from the Docker command line client.
109 109
 //
110
+// Multiple subcommand synopses may be provided with one 'Usage' line being
111
+// printed for each in the following way:
112
+//
113
+//	Usage:	docker <subcmd-name> [OPTIONS] <synopsis 0>
114
+// 		docker <subcmd-name> [OPTIONS] <synopsis 1>
115
+// 		...
116
+//
117
+// If no undeprecated flags are added to the returned FlagSet, "[OPTIONS]" will
118
+// not be included on the usage synopsis lines. If no synopses are given, only
119
+// one usage synopsis line will be printed with nothing following the
120
+// "[OPTIONS]" section
121
+//
110 122
 // To see all available subcommands, run "docker --help".
111
-func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bool) *flag.FlagSet {
123
+func (cli *DockerCli) Subcmd(name string, synopses []string, description string, exitOnError bool) *flag.FlagSet {
112 124
 	var errorHandling flag.ErrorHandling
113 125
 	if exitOnError {
114 126
 		errorHandling = flag.ExitOnError
115 127
 	} else {
116 128
 		errorHandling = flag.ContinueOnError
117 129
 	}
130
+
118 131
 	flags := flag.NewFlagSet(name, errorHandling)
119
-	if signature != "" {
120
-		signature = " " + signature
121
-	}
132
+
122 133
 	flags.Usage = func() {
123 134
 		flags.ShortUsage()
124 135
 		flags.PrintDefaults()
125 136
 	}
137
+
126 138
 	flags.ShortUsage = func() {
127 139
 		options := ""
128 140
 		if flags.FlagCountUndeprecated() > 0 {
129 141
 			options = " [OPTIONS]"
130 142
 		}
131
-		fmt.Fprintf(flags.Out(), "\nUsage: docker %s%s%s\n\n%s\n", name, options, signature, description)
143
+
144
+		if len(synopses) == 0 {
145
+			synopses = []string{""}
146
+		}
147
+
148
+		// Allow for multiple command usage synopses.
149
+		for i, synopsis := range synopses {
150
+			lead := "\t"
151
+			if i == 0 {
152
+				// First line needs the word 'Usage'.
153
+				lead = "Usage:\t"
154
+			}
155
+
156
+			if synopsis != "" {
157
+				synopsis = " " + synopsis
158
+			}
159
+
160
+			fmt.Fprintf(flags.Out(), "\n%sdocker %s%s%s", lead, name, options, synopsis)
161
+		}
162
+
163
+		fmt.Fprintf(flags.Out(), "\n\n%s\n", description)
132 164
 	}
165
+
133 166
 	return flags
134 167
 }
135 168
 
... ...
@@ -17,7 +17,7 @@ import (
17 17
 //
18 18
 // Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
19 19
 func (cli *DockerCli) CmdCommit(args ...string) error {
20
-	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
20
+	cmd := cli.Subcmd("commit", []string{"CONTAINER [REPOSITORY[:TAG]]"}, "Create a new image from a container's changes", true)
21 21
 	flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
22 22
 	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
23 23
 	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
... ...
@@ -16,7 +16,7 @@ import (
16 16
 //
17 17
 // Usage: docker cp CONTAINER:PATH HOSTDIR
18 18
 func (cli *DockerCli) CmdCp(args ...string) error {
19
-	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTDIR|-", "Copy files/folders from a PATH on the container to a HOSTDIR on the host\nrunning the command. Use '-' to write the data as a tar file to STDOUT.", true)
19
+	cmd := cli.Subcmd("cp", []string{"CONTAINER:PATH HOSTDIR|-"}, "Copy files/folders from a PATH on the container to a HOSTDIR on the host\nrunning the command. Use '-' to write the data as a tar file to STDOUT.", true)
20 20
 	cmd.Require(flag.Exact, 2)
21 21
 
22 22
 	cmd.ParseFlags(args, true)
... ...
@@ -135,7 +135,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
135 135
 //
136 136
 // Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
137 137
 func (cli *DockerCli) CmdCreate(args ...string) error {
138
-	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
138
+	cmd := cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new container", true)
139 139
 
140 140
 	// These are flags not stored in Config/HostConfig
141 141
 	var (
... ...
@@ -17,7 +17,7 @@ import (
17 17
 //
18 18
 // Usage: docker diff CONTAINER
19 19
 func (cli *DockerCli) CmdDiff(args ...string) error {
20
-	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
20
+	cmd := cli.Subcmd("diff", []string{"CONTAINER"}, "Inspect changes on a container's filesystem", true)
21 21
 	cmd.Require(flag.Exact, 1)
22 22
 	cmd.ParseFlags(args, true)
23 23
 
... ...
@@ -14,7 +14,7 @@ import (
14 14
 //
15 15
 // Usage: docker events [OPTIONS]
16 16
 func (cli *DockerCli) CmdEvents(args ...string) error {
17
-	cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
17
+	cmd := cli.Subcmd("events", nil, "Get real time events from the server", true)
18 18
 	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
19 19
 	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
20 20
 	flFilter := opts.NewListOpts(nil)
... ...
@@ -15,7 +15,7 @@ import (
15 15
 //
16 16
 // Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
17 17
 func (cli *DockerCli) CmdExec(args ...string) error {
18
-	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
18
+	cmd := cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, "Run a command in a running container", true)
19 19
 
20 20
 	execConfig, err := runconfig.ParseExec(cmd, args)
21 21
 	// just in case the ParseExec does not exit
... ...
@@ -14,7 +14,7 @@ import (
14 14
 //
15 15
 // Usage: docker export [OPTIONS] CONTAINER
16 16
 func (cli *DockerCli) CmdExport(args ...string) error {
17
-	cmd := cli.Subcmd("export", "CONTAINER", "Export a filesystem as a tar archive (streamed to STDOUT by default)", true)
17
+	cmd := cli.Subcmd("export", []string{"CONTAINER"}, "Export a filesystem as a tar archive (streamed to STDOUT by default)", true)
18 18
 	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
19 19
 	cmd.Require(flag.Exact, 1)
20 20
 
... ...
@@ -17,7 +17,7 @@ import (
17 17
 //
18 18
 // Usage: docker history [OPTIONS] IMAGE
19 19
 func (cli *DockerCli) CmdHistory(args ...string) error {
20
-	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
20
+	cmd := cli.Subcmd("history", []string{"IMAGE"}, "Show the history of an image", true)
21 21
 	human := cmd.Bool([]string{"H", "-human"}, true, "Print sizes and dates in human readable format")
22 22
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
23 23
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
... ...
@@ -21,7 +21,7 @@ import (
21 21
 //
22 22
 // Usage: docker images [OPTIONS] [REPOSITORY]
23 23
 func (cli *DockerCli) CmdImages(args ...string) error {
24
-	cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
24
+	cmd := cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true)
25 25
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
26 26
 	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
27 27
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
... ...
@@ -17,7 +17,7 @@ import (
17 17
 //
18 18
 // Usage: docker import [OPTIONS] URL [REPOSITORY[:TAG]]
19 19
 func (cli *DockerCli) CmdImport(args ...string) error {
20
-	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
20
+	cmd := cli.Subcmd("import", []string{"URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
21 21
 	flChanges := opts.NewListOpts(nil)
22 22
 	cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
23 23
 	cmd.Require(flag.Min, 1)
... ...
@@ -14,7 +14,7 @@ import (
14 14
 //
15 15
 // Usage: docker info
16 16
 func (cli *DockerCli) CmdInfo(args ...string) error {
17
-	cmd := cli.Subcmd("info", "", "Display system-wide information", true)
17
+	cmd := cli.Subcmd("info", nil, "Display system-wide information", true)
18 18
 	cmd.Require(flag.Exact, 0)
19 19
 	cmd.ParseFlags(args, true)
20 20
 
... ...
@@ -16,7 +16,7 @@ import (
16 16
 //
17 17
 // Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
18 18
 func (cli *DockerCli) CmdInspect(args ...string) error {
19
-	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
19
+	cmd := cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, "Return low-level information on a container or image", true)
20 20
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
21 21
 	cmd.Require(flag.Min, 1)
22 22
 
... ...
@@ -10,7 +10,7 @@ import (
10 10
 //
11 11
 // Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
12 12
 func (cli *DockerCli) CmdKill(args ...string) error {
13
-	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
13
+	cmd := cli.Subcmd("kill", []string{"CONTAINER [CONTAINER...]"}, "Kill a running container using SIGKILL or a specified signal", true)
14 14
 	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
15 15
 	cmd.Require(flag.Min, 1)
16 16
 
... ...
@@ -13,7 +13,7 @@ import (
13 13
 //
14 14
 // Usage: docker load [OPTIONS]
15 15
 func (cli *DockerCli) CmdLoad(args ...string) error {
16
-	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
16
+	cmd := cli.Subcmd("load", nil, "Load an image from a tar archive on STDIN", true)
17 17
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
18 18
 	cmd.Require(flag.Exact, 0)
19 19
 
... ...
@@ -21,7 +21,7 @@ import (
21 21
 //
22 22
 // Usage: docker login SERVER
23 23
 func (cli *DockerCli) CmdLogin(args ...string) error {
24
-	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
24
+	cmd := cli.Subcmd("login", []string{"[SERVER]"}, "Register or log in to a Docker registry server, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
25 25
 	cmd.Require(flag.Max, 1)
26 26
 
27 27
 	var username, password, email string
... ...
@@ -13,7 +13,7 @@ import (
13 13
 //
14 14
 // Usage: docker logout [SERVER]
15 15
 func (cli *DockerCli) CmdLogout(args ...string) error {
16
-	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
16
+	cmd := cli.Subcmd("logout", []string{"[SERVER]"}, "Log out from a Docker registry, if no server is\nspecified \""+registry.IndexServerAddress()+"\" is the default.", true)
17 17
 	cmd.Require(flag.Max, 1)
18 18
 
19 19
 	cmd.ParseFlags(args, true)
... ...
@@ -16,7 +16,7 @@ import (
16 16
 // docker logs [OPTIONS] CONTAINER
17 17
 func (cli *DockerCli) CmdLogs(args ...string) error {
18 18
 	var (
19
-		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
19
+		cmd    = cli.Subcmd("logs", []string{"CONTAINER"}, "Fetch the logs of a container", true)
20 20
 		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
21 21
 		since  = cmd.String([]string{"-since"}, "", "Show logs since timestamp")
22 22
 		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
... ...
@@ -10,7 +10,7 @@ import (
10 10
 //
11 11
 // Usage: docker pause CONTAINER [CONTAINER...]
12 12
 func (cli *DockerCli) CmdPause(args ...string) error {
13
-	cmd := cli.Subcmd("pause", "CONTAINER [CONTAINER...]", "Pause all processes within a container", true)
13
+	cmd := cli.Subcmd("pause", []string{"CONTAINER [CONTAINER...]"}, "Pause all processes within a container", true)
14 14
 	cmd.Require(flag.Min, 1)
15 15
 	cmd.ParseFlags(args, true)
16 16
 
... ...
@@ -14,7 +14,7 @@ import (
14 14
 //
15 15
 // Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
16 16
 func (cli *DockerCli) CmdPort(args ...string) error {
17
-	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that\nis NAT-ed to the PRIVATE_PORT", true)
17
+	cmd := cli.Subcmd("port", []string{"CONTAINER [PRIVATE_PORT[/PROTO]]"}, "List port mappings for the CONTAINER, or lookup the public-facing port that\nis NAT-ed to the PRIVATE_PORT", true)
18 18
 	cmd.Require(flag.Min, 1)
19 19
 	cmd.ParseFlags(args, true)
20 20
 
... ...
@@ -29,7 +29,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
29 29
 		psFilterArgs = filters.Args{}
30 30
 		v            = url.Values{}
31 31
 
32
-		cmd      = cli.Subcmd("ps", "", "List containers", true)
32
+		cmd      = cli.Subcmd("ps", nil, "List containers", true)
33 33
 		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
34 34
 		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
35 35
 		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)")
... ...
@@ -15,7 +15,7 @@ import (
15 15
 //
16 16
 // Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST]
17 17
 func (cli *DockerCli) CmdPull(args ...string) error {
18
-	cmd := cli.Subcmd("pull", "NAME[:TAG|@DIGEST]", "Pull an image or a repository from the registry", true)
18
+	cmd := cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, "Pull an image or a repository from the registry", true)
19 19
 	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
20 20
 	cmd.Require(flag.Exact, 1)
21 21
 
... ...
@@ -13,7 +13,7 @@ import (
13 13
 //
14 14
 // Usage: docker push NAME[:TAG]
15 15
 func (cli *DockerCli) CmdPush(args ...string) error {
16
-	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
16
+	cmd := cli.Subcmd("push", []string{"NAME[:TAG]"}, "Push an image or a repository to the registry", true)
17 17
 	cmd.Require(flag.Exact, 1)
18 18
 
19 19
 	cmd.ParseFlags(args, true)
... ...
@@ -10,7 +10,7 @@ import (
10 10
 //
11 11
 // Usage: docker rename OLD_NAME NEW_NAME
12 12
 func (cli *DockerCli) CmdRename(args ...string) error {
13
-	cmd := cli.Subcmd("rename", "OLD_NAME NEW_NAME", "Rename a container", true)
13
+	cmd := cli.Subcmd("rename", []string{"OLD_NAME NEW_NAME"}, "Rename a container", true)
14 14
 	cmd.Require(flag.Exact, 2)
15 15
 	cmd.ParseFlags(args, true)
16 16
 
... ...
@@ -12,7 +12,7 @@ import (
12 12
 //
13 13
 // Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
14 14
 func (cli *DockerCli) CmdRestart(args ...string) error {
15
-	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
15
+	cmd := cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true)
16 16
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
17 17
 	cmd.Require(flag.Min, 1)
18 18
 
... ...
@@ -12,7 +12,7 @@ import (
12 12
 //
13 13
 // Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
14 14
 func (cli *DockerCli) CmdRm(args ...string) error {
15
-	cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
15
+	cmd := cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, "Remove one or more containers", true)
16 16
 	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
17 17
 	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link")
18 18
 	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
... ...
@@ -14,7 +14,7 @@ import (
14 14
 // Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
15 15
 func (cli *DockerCli) CmdRmi(args ...string) error {
16 16
 	var (
17
-		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
17
+		cmd     = cli.Subcmd("rmi", []string{"IMAGE [IMAGE...]"}, "Remove one or more images", true)
18 18
 		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
19 19
 		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
20 20
 	)
... ...
@@ -38,7 +38,7 @@ func (cid *cidFile) Write(id string) error {
38 38
 //
39 39
 // Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
40 40
 func (cli *DockerCli) CmdRun(args ...string) error {
41
-	cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
41
+	cmd := cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, "Run a command in a new container", true)
42 42
 
43 43
 	// These are flags not stored in Config/HostConfig
44 44
 	var (
... ...
@@ -15,7 +15,7 @@ import (
15 15
 //
16 16
 // Usage: docker save [OPTIONS] IMAGE [IMAGE...]
17 17
 func (cli *DockerCli) CmdSave(args ...string) error {
18
-	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
18
+	cmd := cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
19 19
 	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
20 20
 	cmd.Require(flag.Min, 1)
21 21
 
... ...
@@ -25,7 +25,7 @@ func (r ByStars) Less(i, j int) bool { return r[i].StarCount < r[j].StarCount }
25 25
 //
26 26
 // Usage: docker search [OPTIONS] TERM
27 27
 func (cli *DockerCli) CmdSearch(args ...string) error {
28
-	cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
28
+	cmd := cli.Subcmd("search", []string{"TERM"}, "Search the Docker Hub for images", true)
29 29
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
30 30
 	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
31 31
 	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
... ...
@@ -48,7 +48,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
48 48
 		cErr chan error
49 49
 		tty  bool
50 50
 
51
-		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Start one or more stopped containers", true)
51
+		cmd       = cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, "Start one or more stopped containers", true)
52 52
 		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
53 53
 		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
54 54
 	)
... ...
@@ -122,7 +122,7 @@ func (s *containerStats) Display(w io.Writer) error {
122 122
 //
123 123
 // Usage: docker stats CONTAINER [CONTAINER...]
124 124
 func (cli *DockerCli) CmdStats(args ...string) error {
125
-	cmd := cli.Subcmd("stats", "CONTAINER [CONTAINER...]", "Display a live stream of one or more containers' resource usage statistics", true)
125
+	cmd := cli.Subcmd("stats", []string{"CONTAINER [CONTAINER...]"}, "Display a live stream of one or more containers' resource usage statistics", true)
126 126
 	noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result")
127 127
 	cmd.Require(flag.Min, 1)
128 128
 	cmd.ParseFlags(args, true)
... ...
@@ -14,7 +14,7 @@ import (
14 14
 //
15 15
 // Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
16 16
 func (cli *DockerCli) CmdStop(args ...string) error {
17
-	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true)
17
+	cmd := cli.Subcmd("stop", []string{"CONTAINER [CONTAINER...]"}, "Stop a running container by sending SIGTERM and then SIGKILL after a\ngrace period", true)
18 18
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing it")
19 19
 	cmd.Require(flag.Min, 1)
20 20
 
... ...
@@ -12,7 +12,7 @@ import (
12 12
 //
13 13
 // Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
14 14
 func (cli *DockerCli) CmdTag(args ...string) error {
15
-	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
15
+	cmd := cli.Subcmd("tag", []string{"IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]"}, "Tag an image into a repository", true)
16 16
 	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
17 17
 	cmd.Require(flag.Exact, 2)
18 18
 
... ...
@@ -15,7 +15,7 @@ import (
15 15
 //
16 16
 // Usage: docker top CONTAINER
17 17
 func (cli *DockerCli) CmdTop(args ...string) error {
18
-	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
18
+	cmd := cli.Subcmd("top", []string{"CONTAINER [ps OPTIONS]"}, "Display the running processes of a container", true)
19 19
 	cmd.Require(flag.Min, 1)
20 20
 
21 21
 	cmd.ParseFlags(args, true)
... ...
@@ -10,7 +10,7 @@ import (
10 10
 //
11 11
 // Usage: docker unpause CONTAINER [CONTAINER...]
12 12
 func (cli *DockerCli) CmdUnpause(args ...string) error {
13
-	cmd := cli.Subcmd("unpause", "CONTAINER [CONTAINER...]", "Unpause all processes within a container", true)
13
+	cmd := cli.Subcmd("unpause", []string{"CONTAINER [CONTAINER...]"}, "Unpause all processes within a container", true)
14 14
 	cmd.Require(flag.Min, 1)
15 15
 	cmd.ParseFlags(args, true)
16 16
 
... ...
@@ -18,7 +18,7 @@ import (
18 18
 //
19 19
 // Usage: docker version
20 20
 func (cli *DockerCli) CmdVersion(args ...string) error {
21
-	cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
21
+	cmd := cli.Subcmd("version", nil, "Show the Docker version information.", true)
22 22
 	cmd.Require(flag.Exact, 0)
23 23
 
24 24
 	cmd.ParseFlags(args, true)
... ...
@@ -12,7 +12,7 @@ import (
12 12
 //
13 13
 // Usage: docker wait CONTAINER [CONTAINER...]
14 14
 func (cli *DockerCli) CmdWait(args ...string) error {
15
-	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
15
+	cmd := cli.Subcmd("wait", []string{"CONTAINER [CONTAINER...]"}, "Block until a container stops, then print its exit code.", true)
16 16
 	cmd.Require(flag.Min, 1)
17 17
 
18 18
 	cmd.ParseFlags(args, true)
... ...
@@ -215,7 +215,7 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
215 215
 					c.Fatalf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q", args, stdout, stderr, ec, err)
216 216
 				}
217 217
 				// Should have just short usage
218
-				if !strings.Contains(stderr, "\nUsage: ") {
218
+				if !strings.Contains(stderr, "\nUsage:\t") {
219 219
 					c.Fatalf("Missing short usage on %q\nstderr:%q", args, stderr)
220 220
 				}
221 221
 				// But shouldn't have full usage
... ...
@@ -53,7 +53,7 @@ func (s *DockerSuite) TestSearchCmdOptions(c *check.C) {
53 53
 		c.Fatalf("failed to get search help information: %s, %v", out, err)
54 54
 	}
55 55
 
56
-	if !strings.Contains(out, "Usage: docker search [OPTIONS] TERM") {
56
+	if !strings.Contains(out, "Usage:\tdocker search [OPTIONS] TERM") {
57 57
 		c.Fatalf("failed to show docker search usage: %s, %v", out, err)
58 58
 	}
59 59