Browse code

--help option and help command should print to stdout not stderr

--help and help are successful commands so output should not go to error.

QE teams have requested this change, also users doing docker help | less
or docker run --help | less would expect this to work.

Usage statement should only be printed when the user asks for it.
Errors should print error message and then suggest the docker COMMAND --help
command to see usage information.

The current behaviour causes the user to have to search for the error message
and sometimes scrolls right off the screen. For example a error on a
"docker run" command is very difficult to diagnose.

Finally erros should always exit with a non 0 exit code, if the user
makes a CLI error.

Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)

Dan Walsh authored on 2014/10/16 06:14:12
Showing 41 changed files
... ...
@@ -75,8 +75,8 @@ func (cli *DockerCli) Cmd(args ...string) error {
75 75
 	if len(args) > 0 {
76 76
 		method, exists := cli.getMethod(args[0])
77 77
 		if !exists {
78
-			fmt.Println("Error: Command not found:", args[0])
79
-			return cli.CmdHelp()
78
+			fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
79
+			os.Exit(1)
80 80
 		}
81 81
 		return method(args[1:]...)
82 82
 	}
... ...
@@ -90,9 +90,10 @@ func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet
90 90
 		if flags.FlagCountUndeprecated() > 0 {
91 91
 			options = "[OPTIONS] "
92 92
 		}
93
-		fmt.Fprintf(cli.err, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description)
93
+		fmt.Fprintf(cli.out, "\nUsage: docker %s %s%s\n\n%s\n\n", name, options, signature, description)
94
+		flags.SetOutput(cli.out)
94 95
 		flags.PrintDefaults()
95
-		os.Exit(2)
96
+		os.Exit(0)
96 97
 	}
97 98
 	return flags
98 99
 }
... ...
@@ -64,6 +64,8 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
64 64
 		method, exists := cli.getMethod(args[0])
65 65
 		if !exists {
66 66
 			fmt.Fprintf(cli.err, "Error: Command not found: %s\n", args[0])
67
+			fmt.Fprintf(cli.err, "docker: '%s' is not a docker command. See 'docker --help'.\n", args[0])
68
+			os.Exit(1)
67 69
 		} else {
68 70
 			method("--help")
69 71
 			return nil
... ...
@@ -83,13 +85,18 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
83 83
 	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
84 84
 	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
85 85
 	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
86
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
87
+
86 88
 	if err := cmd.Parse(args); err != nil {
87 89
 		return nil
88 90
 	}
89
-	if cmd.NArg() != 1 {
91
+	if *help {
90 92
 		cmd.Usage()
91 93
 		return nil
92 94
 	}
95
+	if cmd.BadArgs(flag.Exact, 1) {
96
+		os.Exit(1)
97
+	}
93 98
 
94 99
 	var (
95 100
 		context  archive.Archive
... ...
@@ -254,10 +261,16 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
254 254
 	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
255 255
 	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
256 256
 	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
257
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
258
+
257 259
 	err := cmd.Parse(args)
258 260
 	if err != nil {
259 261
 		return nil
260 262
 	}
263
+	if *help {
264
+		cmd.Usage()
265
+		return nil
266
+	}
261 267
 	serverAddress := registry.IndexServerAddress()
262 268
 	if len(cmd.Args()) > 0 {
263 269
 		serverAddress = cmd.Arg(0)
... ...
@@ -390,13 +403,18 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
390 390
 // 'docker wait': block until a container stops
391 391
 func (cli *DockerCli) CmdWait(args ...string) error {
392 392
 	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
393
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
394
+
393 395
 	if err := cmd.Parse(args); err != nil {
394 396
 		return nil
395 397
 	}
396
-	if cmd.NArg() < 1 {
398
+	if *help {
397 399
 		cmd.Usage()
398 400
 		return nil
399 401
 	}
402
+	if cmd.BadArgs(flag.Min, 1) {
403
+		os.Exit(1)
404
+	}
400 405
 	var encounteredError error
401 406
 	for _, name := range cmd.Args() {
402 407
 		status, err := waitForExit(cli, name)
... ...
@@ -416,10 +434,8 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
416 416
 	if err := cmd.Parse(args); err != nil {
417 417
 		return nil
418 418
 	}
419
-
420
-	if cmd.NArg() > 0 {
421
-		cmd.Usage()
422
-		return nil
419
+	if cmd.BadArgs(flag.Exact, 0) {
420
+		os.Exit(1)
423 421
 	}
424 422
 	if dockerversion.VERSION != "" {
425 423
 		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
... ...
@@ -462,9 +478,8 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
462 462
 	if err := cmd.Parse(args); err != nil {
463 463
 		return nil
464 464
 	}
465
-	if cmd.NArg() > 0 {
466
-		cmd.Usage()
467
-		return nil
465
+	if cmd.BadArgs(flag.Exact, 0) {
466
+		os.Exit(1)
468 467
 	}
469 468
 
470 469
 	body, _, err := readBody(cli.call("GET", "/info", nil, false))
... ...
@@ -579,13 +594,18 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
579 579
 func (cli *DockerCli) CmdStop(args ...string) error {
580 580
 	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
581 581
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
582
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
583
+
582 584
 	if err := cmd.Parse(args); err != nil {
583 585
 		return nil
584 586
 	}
585
-	if cmd.NArg() < 1 {
587
+	if *help {
586 588
 		cmd.Usage()
587 589
 		return nil
588 590
 	}
591
+	if cmd.BadArgs(flag.Min, 1) {
592
+		os.Exit(1)
593
+	}
589 594
 
590 595
 	v := url.Values{}
591 596
 	v.Set("t", strconv.Itoa(*nSeconds))
... ...
@@ -606,13 +626,18 @@ func (cli *DockerCli) CmdStop(args ...string) error {
606 606
 func (cli *DockerCli) CmdRestart(args ...string) error {
607 607
 	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
608 608
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.")
609
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
610
+
609 611
 	if err := cmd.Parse(args); err != nil {
610 612
 		return nil
611 613
 	}
612
-	if cmd.NArg() < 1 {
614
+	if *help {
613 615
 		cmd.Usage()
614 616
 		return nil
615 617
 	}
618
+	if cmd.BadArgs(flag.Min, 1) {
619
+		os.Exit(1)
620
+	}
616 621
 
617 622
 	v := url.Values{}
618 623
 	v.Set("t", strconv.Itoa(*nSeconds))
... ...
@@ -664,15 +689,19 @@ func (cli *DockerCli) CmdStart(args ...string) error {
664 664
 		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
665 665
 		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
666 666
 		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
667
+		help      = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
667 668
 	)
668 669
 
669 670
 	if err := cmd.Parse(args); err != nil {
670 671
 		return nil
671 672
 	}
672
-	if cmd.NArg() < 1 {
673
+	if *help {
673 674
 		cmd.Usage()
674 675
 		return nil
675 676
 	}
677
+	if cmd.BadArgs(flag.Min, 1) {
678
+		os.Exit(1)
679
+	}
676 680
 
677 681
 	hijacked := make(chan io.Closer)
678 682
 
... ...
@@ -778,10 +807,8 @@ func (cli *DockerCli) CmdUnpause(args ...string) error {
778 778
 	if err := cmd.Parse(args); err != nil {
779 779
 		return nil
780 780
 	}
781
-
782
-	if cmd.NArg() != 1 {
783
-		cmd.Usage()
784
-		return nil
781
+	if cmd.BadArgs(flag.Exact, 1) {
782
+		os.Exit(1)
785 783
 	}
786 784
 
787 785
 	var encounteredError error
... ...
@@ -801,10 +828,8 @@ func (cli *DockerCli) CmdPause(args ...string) error {
801 801
 	if err := cmd.Parse(args); err != nil {
802 802
 		return nil
803 803
 	}
804
-
805
-	if cmd.NArg() != 1 {
806
-		cmd.Usage()
807
-		return nil
804
+	if cmd.BadArgs(flag.Exact, 1) {
805
+		os.Exit(1)
808 806
 	}
809 807
 
810 808
 	var encounteredError error
... ...
@@ -822,13 +847,18 @@ func (cli *DockerCli) CmdPause(args ...string) error {
822 822
 func (cli *DockerCli) CmdInspect(args ...string) error {
823 823
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
824 824
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
825
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
826
+
825 827
 	if err := cmd.Parse(args); err != nil {
826 828
 		return nil
827 829
 	}
828
-	if cmd.NArg() < 1 {
830
+	if *help {
829 831
 		cmd.Usage()
830 832
 		return nil
831 833
 	}
834
+	if cmd.BadArgs(flag.Min, 1) {
835
+		os.Exit(1)
836
+	}
832 837
 
833 838
 	var tmpl *template.Template
834 839
 	if *tmplStr != "" {
... ...
@@ -901,13 +931,18 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
901 901
 
902 902
 func (cli *DockerCli) CmdTop(args ...string) error {
903 903
 	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
904
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
905
+
904 906
 	if err := cmd.Parse(args); err != nil {
905 907
 		return nil
906 908
 	}
907
-	if cmd.NArg() == 0 {
909
+	if *help {
908 910
 		cmd.Usage()
909 911
 		return nil
910 912
 	}
913
+	if cmd.BadArgs(flag.Min, 1) {
914
+		os.Exit(1)
915
+	}
911 916
 	val := url.Values{}
912 917
 	if cmd.NArg() > 1 {
913 918
 		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
... ...
@@ -936,13 +971,17 @@ func (cli *DockerCli) CmdTop(args ...string) error {
936 936
 
937 937
 func (cli *DockerCli) CmdPort(args ...string) error {
938 938
 	cmd := cli.Subcmd("port", "CONTAINER [PRIVATE_PORT[/PROTO]]", "List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT")
939
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
939 940
 	if err := cmd.Parse(args); err != nil {
940 941
 		return nil
941 942
 	}
942
-	if cmd.NArg() < 1 {
943
+	if *help {
943 944
 		cmd.Usage()
944 945
 		return nil
945 946
 	}
947
+	if cmd.BadArgs(flag.Min, 1) {
948
+		os.Exit(1)
949
+	}
946 950
 
947 951
 	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
948 952
 	if err != nil {
... ...
@@ -995,13 +1034,18 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
995 995
 		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
996 996
 		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
997 997
 	)
998
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
999
+
998 1000
 	if err := cmd.Parse(args); err != nil {
999 1001
 		return nil
1000 1002
 	}
1001
-	if cmd.NArg() < 1 {
1003
+	if *help {
1002 1004
 		cmd.Usage()
1003 1005
 		return nil
1004 1006
 	}
1007
+	if cmd.BadArgs(flag.Min, 1) {
1008
+		os.Exit(1)
1009
+	}
1005 1010
 
1006 1011
 	v := url.Values{}
1007 1012
 	if *force {
... ...
@@ -1040,14 +1084,18 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
1040 1040
 	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image")
1041 1041
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
1042 1042
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1043
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1043 1044
 
1044 1045
 	if err := cmd.Parse(args); err != nil {
1045 1046
 		return nil
1046 1047
 	}
1047
-	if cmd.NArg() != 1 {
1048
+	if *help {
1048 1049
 		cmd.Usage()
1049 1050
 		return nil
1050 1051
 	}
1052
+	if cmd.BadArgs(flag.Exact, 1) {
1053
+		os.Exit(1)
1054
+	}
1051 1055
 
1052 1056
 	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
1053 1057
 	if err != nil {
... ...
@@ -1098,14 +1146,18 @@ func (cli *DockerCli) CmdRm(args ...string) error {
1098 1098
 	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
1099 1099
 	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
1100 1100
 	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
1101
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1101 1102
 
1102 1103
 	if err := cmd.Parse(args); err != nil {
1103 1104
 		return nil
1104 1105
 	}
1105
-	if cmd.NArg() < 1 {
1106
+	if *help {
1106 1107
 		cmd.Usage()
1107 1108
 		return nil
1108 1109
 	}
1110
+	if cmd.BadArgs(flag.Min, 1) {
1111
+		os.Exit(1)
1112
+	}
1109 1113
 
1110 1114
 	val := url.Values{}
1111 1115
 	if *v {
... ...
@@ -1136,14 +1188,18 @@ func (cli *DockerCli) CmdRm(args ...string) error {
1136 1136
 func (cli *DockerCli) CmdKill(args ...string) error {
1137 1137
 	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
1138 1138
 	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
1139
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1139 1140
 
1140 1141
 	if err := cmd.Parse(args); err != nil {
1141 1142
 		return nil
1142 1143
 	}
1143
-	if cmd.NArg() < 1 {
1144
+	if *help {
1144 1145
 		cmd.Usage()
1145 1146
 		return nil
1146 1147
 	}
1148
+	if cmd.BadArgs(flag.Min, 1) {
1149
+		os.Exit(1)
1150
+	}
1147 1151
 
1148 1152
 	var encounteredError error
1149 1153
 	for _, name := range cmd.Args() {
... ...
@@ -1159,15 +1215,18 @@ func (cli *DockerCli) CmdKill(args ...string) error {
1159 1159
 
1160 1160
 func (cli *DockerCli) CmdImport(args ...string) error {
1161 1161
 	cmd := cli.Subcmd("import", "URL|- [REPOSITORY[:TAG]]", "Create an empty filesystem image and import the contents of the tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.")
1162
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1162 1163
 
1163 1164
 	if err := cmd.Parse(args); err != nil {
1164 1165
 		return nil
1165 1166
 	}
1166
-	if cmd.NArg() < 1 {
1167
+	if *help {
1167 1168
 		cmd.Usage()
1168 1169
 		return nil
1169 1170
 	}
1170
-
1171
+	if cmd.BadArgs(flag.Min, 1) {
1172
+		os.Exit(1)
1173
+	}
1171 1174
 	var (
1172 1175
 		v          = url.Values{}
1173 1176
 		src        = cmd.Arg(0)
... ...
@@ -1201,15 +1260,19 @@ func (cli *DockerCli) CmdImport(args ...string) error {
1201 1201
 
1202 1202
 func (cli *DockerCli) CmdPush(args ...string) error {
1203 1203
 	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
1204
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1205
+
1204 1206
 	if err := cmd.Parse(args); err != nil {
1205 1207
 		return nil
1206 1208
 	}
1207
-	name := cmd.Arg(0)
1208
-
1209
-	if name == "" {
1209
+	if *help {
1210 1210
 		cmd.Usage()
1211 1211
 		return nil
1212 1212
 	}
1213
+	if cmd.BadArgs(flag.Exact, 1) {
1214
+		os.Exit(1)
1215
+	}
1216
+	name := cmd.Arg(0)
1213 1217
 
1214 1218
 	cli.LoadConfigFile()
1215 1219
 
... ...
@@ -1267,14 +1330,19 @@ func (cli *DockerCli) CmdPush(args ...string) error {
1267 1267
 func (cli *DockerCli) CmdPull(args ...string) error {
1268 1268
 	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
1269 1269
 	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
1270
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1271
+
1270 1272
 	if err := cmd.Parse(args); err != nil {
1271 1273
 		return nil
1272 1274
 	}
1273
-
1274
-	if cmd.NArg() != 1 {
1275
+	if *help {
1275 1276
 		cmd.Usage()
1276 1277
 		return nil
1277 1278
 	}
1279
+
1280
+	if cmd.BadArgs(flag.Exact, 1) {
1281
+		os.Exit(1)
1282
+	}
1278 1283
 	var (
1279 1284
 		v         = url.Values{}
1280 1285
 		remote    = cmd.Arg(0)
... ...
@@ -1338,6 +1406,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
1338 1338
 	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
1339 1339
 	flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
1340 1340
 	flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
1341
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1341 1342
 
1342 1343
 	flFilter := opts.NewListOpts(nil)
1343 1344
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
... ...
@@ -1345,10 +1414,13 @@ func (cli *DockerCli) CmdImages(args ...string) error {
1345 1345
 	if err := cmd.Parse(args); err != nil {
1346 1346
 		return nil
1347 1347
 	}
1348
-	if cmd.NArg() > 1 {
1348
+	if *help {
1349 1349
 		cmd.Usage()
1350 1350
 		return nil
1351 1351
 	}
1352
+	if cmd.BadArgs(flag.Max, 1) {
1353
+		os.Exit(1)
1354
+	}
1352 1355
 
1353 1356
 	// Consolidate all filter flags, and sanity check them early.
1354 1357
 	// They'll get process in the daemon/server.
... ...
@@ -1578,6 +1650,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1578 1578
 		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
1579 1579
 		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
1580 1580
 		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
1581
+		help     = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1581 1582
 		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1582 1583
 		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
1583 1584
 		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
... ...
@@ -1591,7 +1664,10 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1591 1591
 	if err := cmd.Parse(args); err != nil {
1592 1592
 		return nil
1593 1593
 	}
1594
-
1594
+	if *help {
1595
+		cmd.Usage()
1596
+		return nil
1597
+	}
1595 1598
 	if *last == -1 && *nLatest {
1596 1599
 		*last = 1
1597 1600
 	}
... ...
@@ -1732,20 +1808,28 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
1732 1732
 	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
1733 1733
 	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
1734 1734
 	flConfig := cmd.String([]string{"#run", "#-run"}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
1735
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1735 1736
 	if err := cmd.Parse(args); err != nil {
1736 1737
 		return nil
1737 1738
 	}
1739
+	if *help {
1740
+		cmd.Usage()
1741
+		return nil
1742
+	}
1743
+
1744
+	if cmd.BadArgs(flag.Max, 2) {
1745
+		os.Exit(1)
1746
+	}
1747
+
1748
+	if cmd.BadArgs(flag.Min, 1) {
1749
+		os.Exit(1)
1750
+	}
1738 1751
 
1739 1752
 	var (
1740 1753
 		name            = cmd.Arg(0)
1741 1754
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
1742 1755
 	)
1743 1756
 
1744
-	if name == "" || len(cmd.Args()) > 2 {
1745
-		cmd.Usage()
1746
-		return nil
1747
-	}
1748
-
1749 1757
 	//Check if the given image name can be resolved
1750 1758
 	if repository != "" {
1751 1759
 		if _, _, err := registry.ResolveRepositoryName(repository); err != nil {
... ...
@@ -1790,18 +1874,21 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
1790 1790
 	cmd := cli.Subcmd("events", "", "Get real time events from the server")
1791 1791
 	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
1792 1792
 	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
1793
-
1794 1793
 	flFilter := opts.NewListOpts(nil)
1795 1794
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
1795
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1796 1796
 
1797 1797
 	if err := cmd.Parse(args); err != nil {
1798 1798
 		return nil
1799 1799
 	}
1800
-
1801
-	if cmd.NArg() != 0 {
1800
+	if *help {
1802 1801
 		cmd.Usage()
1803 1802
 		return nil
1804 1803
 	}
1804
+	if cmd.BadArgs(flag.Exact, 0) {
1805
+		os.Exit(1)
1806
+	}
1807
+
1805 1808
 	var (
1806 1809
 		v               = url.Values{}
1807 1810
 		loc             = time.FixedZone(time.Now().Zone())
... ...
@@ -1849,14 +1936,18 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
1849 1849
 
1850 1850
 func (cli *DockerCli) CmdExport(args ...string) error {
1851 1851
 	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
1852
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1853
+
1852 1854
 	if err := cmd.Parse(args); err != nil {
1853 1855
 		return nil
1854 1856
 	}
1855
-
1856
-	if cmd.NArg() != 1 {
1857
+	if *help {
1857 1858
 		cmd.Usage()
1858 1859
 		return nil
1859 1860
 	}
1861
+	if cmd.BadArgs(flag.Exact, 1) {
1862
+		os.Exit(1)
1863
+	}
1860 1864
 
1861 1865
 	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
1862 1866
 		return err
... ...
@@ -1866,13 +1957,18 @@ func (cli *DockerCli) CmdExport(args ...string) error {
1866 1866
 
1867 1867
 func (cli *DockerCli) CmdDiff(args ...string) error {
1868 1868
 	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
1869
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1870
+
1869 1871
 	if err := cmd.Parse(args); err != nil {
1870 1872
 		return nil
1871 1873
 	}
1872
-	if cmd.NArg() != 1 {
1874
+	if *help {
1873 1875
 		cmd.Usage()
1874 1876
 		return nil
1875 1877
 	}
1878
+	if cmd.BadArgs(flag.Exact, 1) {
1879
+		os.Exit(1)
1880
+	}
1876 1881
 
1877 1882
 	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
1878 1883
 
... ...
@@ -1905,16 +2001,20 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
1905 1905
 		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
1906 1906
 		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
1907 1907
 		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
1908
+		help   = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1908 1909
 	)
1909 1910
 
1910 1911
 	if err := cmd.Parse(args); err != nil {
1911 1912
 		return nil
1912 1913
 	}
1913 1914
 
1914
-	if cmd.NArg() != 1 {
1915
+	if *help {
1915 1916
 		cmd.Usage()
1916 1917
 		return nil
1917 1918
 	}
1919
+	if cmd.BadArgs(flag.Exact, 1) {
1920
+		os.Exit(1)
1921
+	}
1918 1922
 	name := cmd.Arg(0)
1919 1923
 
1920 1924
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
... ...
@@ -1948,16 +2048,19 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
1948 1948
 		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container")
1949 1949
 		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
1950 1950
 		proxy   = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied.")
1951
+		help    = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
1951 1952
 	)
1952 1953
 
1953 1954
 	if err := cmd.Parse(args); err != nil {
1954 1955
 		return nil
1955 1956
 	}
1956
-
1957
-	if cmd.NArg() != 1 {
1957
+	if *help {
1958 1958
 		cmd.Usage()
1959 1959
 		return nil
1960 1960
 	}
1961
+	if cmd.BadArgs(flag.Exact, 1) {
1962
+		os.Exit(1)
1963
+	}
1961 1964
 	name := cmd.Arg(0)
1962 1965
 
1963 1966
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
... ...
@@ -2027,13 +2130,18 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
2027 2027
 	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
2028 2028
 	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
2029 2029
 	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
2030
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
2031
+
2030 2032
 	if err := cmd.Parse(args); err != nil {
2031 2033
 		return nil
2032 2034
 	}
2033
-	if cmd.NArg() != 1 {
2035
+	if *help {
2034 2036
 		cmd.Usage()
2035 2037
 		return nil
2036 2038
 	}
2039
+	if cmd.BadArgs(flag.Exact, 1) {
2040
+		os.Exit(1)
2041
+	}
2037 2042
 
2038 2043
 	v := url.Values{}
2039 2044
 	v.Set("term", cmd.Arg(0))
... ...
@@ -2079,13 +2187,18 @@ type ports []int
2079 2079
 func (cli *DockerCli) CmdTag(args ...string) error {
2080 2080
 	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
2081 2081
 	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
2082
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
2083
+
2082 2084
 	if err := cmd.Parse(args); err != nil {
2083 2085
 		return nil
2084 2086
 	}
2085
-	if cmd.NArg() != 2 {
2087
+	if *help {
2086 2088
 		cmd.Usage()
2087 2089
 		return nil
2088 2090
 	}
2091
+	if cmd.BadArgs(flag.Exact, 2) {
2092
+		os.Exit(1)
2093
+	}
2089 2094
 
2090 2095
 	var (
2091 2096
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
... ...
@@ -2158,6 +2271,7 @@ func newCIDFile(path string) (*cidFile, error) {
2158 2158
 	if _, err := os.Stat(path); err == nil {
2159 2159
 		return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
2160 2160
 	}
2161
+
2161 2162
 	f, err := os.Create(path)
2162 2163
 	if err != nil {
2163 2164
 		return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
... ...
@@ -2474,14 +2588,18 @@ func (cli *DockerCli) CmdRun(args ...string) error {
2474 2474
 
2475 2475
 func (cli *DockerCli) CmdCp(args ...string) error {
2476 2476
 	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
2477
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
2478
+
2477 2479
 	if err := cmd.Parse(args); err != nil {
2478 2480
 		return nil
2479 2481
 	}
2480
-
2481
-	if cmd.NArg() != 2 {
2482
+	if *help {
2482 2483
 		cmd.Usage()
2483 2484
 		return nil
2484 2485
 	}
2486
+	if cmd.BadArgs(flag.Exact, 2) {
2487
+		os.Exit(1)
2488
+	}
2485 2489
 
2486 2490
 	var copyData engine.Env
2487 2491
 	info := strings.Split(cmd.Arg(0), ":")
... ...
@@ -2514,16 +2632,20 @@ func (cli *DockerCli) CmdCp(args ...string) error {
2514 2514
 
2515 2515
 func (cli *DockerCli) CmdSave(args ...string) error {
2516 2516
 	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)")
2517
-	outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
2517
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
2518
+	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
2518 2519
 
2519 2520
 	if err := cmd.Parse(args); err != nil {
2520 2521
 		return err
2521 2522
 	}
2522 2523
 
2523
-	if cmd.NArg() < 1 {
2524
+	if *help {
2524 2525
 		cmd.Usage()
2525 2526
 		return nil
2526 2527
 	}
2528
+	if cmd.BadArgs(flag.Min, 1) {
2529
+		os.Exit(1)
2530
+	}
2527 2531
 
2528 2532
 	var (
2529 2533
 		output io.Writer = cli.out
... ...
@@ -2558,15 +2680,18 @@ func (cli *DockerCli) CmdSave(args ...string) error {
2558 2558
 func (cli *DockerCli) CmdLoad(args ...string) error {
2559 2559
 	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
2560 2560
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
2561
+	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
2561 2562
 
2562 2563
 	if err := cmd.Parse(args); err != nil {
2563 2564
 		return err
2564 2565
 	}
2565
-
2566
-	if cmd.NArg() != 0 {
2566
+	if *help {
2567 2567
 		cmd.Usage()
2568 2568
 		return nil
2569 2569
 	}
2570
+	if cmd.BadArgs(flag.Exact, 0) {
2571
+		os.Exit(1)
2572
+	}
2570 2573
 
2571 2574
 	var (
2572 2575
 		input io.Reader = cli.in
... ...
@@ -2588,14 +2713,9 @@ func (cli *DockerCli) CmdExec(args ...string) error {
2588 2588
 	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container")
2589 2589
 
2590 2590
 	execConfig, err := runconfig.ParseExec(cmd, args)
2591
-	if err != nil {
2592
-		cmd.Usage()
2591
+	if execConfig.Container == "" || err != nil {
2593 2592
 		return err
2594 2593
 	}
2595
-	if execConfig.Container == "" {
2596
-		cmd.Usage()
2597
-		return nil
2598
-	}
2599 2594
 
2600 2595
 	stream, _, err := cli.call("POST", "/containers/"+execConfig.Container+"/exec", execConfig, false)
2601 2596
 	if err != nil {
... ...
@@ -36,6 +36,7 @@ var (
36 36
 	flLogLevel    = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
37 37
 	flEnableCors  = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
38 38
 	flTls         = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by --tlsverify flag")
39
+	flHelp        = flag.Bool([]string{"h", "-help"}, false, "Print usage")
39 40
 	flTlsVerify   = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)")
40 41
 
41 42
 	// these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs
... ...
@@ -57,8 +58,9 @@ func init() {
57 57
 	opts.HostListVar(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode or connect to in client mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.")
58 58
 
59 59
 	flag.Usage = func() {
60
-		fmt.Fprint(os.Stderr, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n")
60
+		fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n\nA self-sufficient runtime for linux containers.\n\nOptions:\n")
61 61
 
62
+		flag.CommandLine.SetOutput(os.Stdout)
62 63
 		flag.PrintDefaults()
63 64
 
64 65
 		help := "\nCommands:\n"
... ...
@@ -105,6 +107,6 @@ func init() {
105 105
 			help += fmt.Sprintf("    %-10.10s%s\n", command[0], command[1])
106 106
 		}
107 107
 		help += "\nRun 'docker COMMAND --help' for more information on a command."
108
-		fmt.Fprintf(os.Stderr, "%s\n", help)
108
+		fmt.Fprintf(os.Stdout, "%s\n", help)
109 109
 	}
110 110
 }
... ...
@@ -6,6 +6,7 @@ docker-attach - Attach to a running container
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker attach**
9
+[**--help**]/
9 10
 [**--no-stdin**[=*false*]]
10 11
 [**--sig-proxy**[=*true*]]
11 12
 CONTAINER
... ...
@@ -24,6 +25,9 @@ It is forbidden to redirect the standard input of a docker attach command while
24 24
 attaching to a tty-enabled container (i.e.: launched with -t`).
25 25
 
26 26
 # OPTIONS
27
+**--help**
28
+  Print usage statement
29
+
27 30
 **--no-stdin**=*true*|*false*
28 31
    Do not attach STDIN. The default is *false*.
29 32
 
... ...
@@ -6,6 +6,7 @@ docker-build - Build a new image from the source code at PATH
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker build**
9
+[**--help**]
9 10
 [**--force-rm**[=*false*]]
10 11
 [**--no-cache**[=*false*]]
11 12
 [**-q**|**--quiet**[=*false*]]
... ...
@@ -36,6 +37,9 @@ as context.
36 36
 **--no-cache**=*true*|*false*
37 37
    Do not use cache when building the image. The default is *false*.
38 38
 
39
+**--help**
40
+  Print usage statement
41
+
39 42
 **-q**, **--quiet**=*true*|*false*
40 43
    Suppress the verbose output generated by the containers. The default is *false*.
41 44
 
... ...
@@ -7,6 +7,7 @@ docker-commit - Create a new image from a container's changes
7 7
 # SYNOPSIS
8 8
 **docker commit**
9 9
 [**-a**|**--author**[=*AUTHOR*]]
10
+[**--help**]
10 11
 [**-m**|**--message**[=*MESSAGE*]]
11 12
 [**-p**|**--pause**[=*true*]]
12 13
 CONTAINER [REPOSITORY[:TAG]]
... ...
@@ -18,6 +19,9 @@ Using an existing container's name or ID you can create a new image.
18 18
 **-a**, **--author**=""
19 19
    Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
20 20
 
21
+**--help**
22
+  Print usage statement
23
+
21 24
 **-m**, **--message**=""
22 25
    Commit message
23 26
 
... ...
@@ -6,6 +6,7 @@ docker-cp - Copy files/folders from the PATH to the HOSTPATH
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker cp**
9
+[**--help**]
9 10
 CONTAINER:PATH HOSTPATH
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -14,7 +15,8 @@ path. Paths are relative to the root of the filesystem. Files
14 14
 can be copied from a running or stopped container.
15 15
 
16 16
 # OPTIONS
17
-There are no available options.
17
+**--help**
18
+  Print usage statement
18 19
 
19 20
 # EXAMPLES
20 21
 An important shell script file, created in a bash shell, is copied from
... ...
@@ -21,6 +21,7 @@ docker-create - Create a new container
21 21
 [**--env-file**[=*[]*]]
22 22
 [**--expose**[=*[]*]]
23 23
 [**-h**|**--hostname**[=*HOSTNAME*]]
24
+[**--help**]
24 25
 [**-i**|**--interactive**[=*false*]]
25 26
 [**--ipc**[=*IPC*]]
26 27
 [**--link**[=*[]*]]
... ...
@@ -87,6 +88,9 @@ IMAGE [COMMAND] [ARG...]
87 87
 **-h**, **--hostname**=""
88 88
    Container host name
89 89
 
90
+**--help**
91
+  Print usage statement
92
+
90 93
 **-i**, **--interactive**=*true*|*false*
91 94
    Keep STDIN open even if not attached. The default is *false*.
92 95
 
... ...
@@ -6,6 +6,7 @@ docker-diff - Inspect changes on a container's filesystem
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker diff**
9
+[**--help**]
9 10
 CONTAINER
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -14,7 +15,8 @@ shortened container ID or the container name set using
14 14
 **docker run --name** option.
15 15
 
16 16
 # OPTIONS
17
-There are no available options.
17
+**--help**
18
+  Print usage statement
18 19
 
19 20
 # EXAMPLES
20 21
 Inspect the changes to on a nginx container:
... ...
@@ -6,6 +6,7 @@ docker-events - Get real time events from the server
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker events**
9
+[**--help**]
9 10
 [**--since**[=*SINCE*]]
10 11
 [**--until**[=*UNTIL*]]
11 12
 
... ...
@@ -23,6 +24,9 @@ and Docker images will report:
23 23
     untag, delete
24 24
 
25 25
 # OPTIONS
26
+**--help**
27
+  Print usage statement
28
+
26 29
 **--since**=""
27 30
    Show all events created since timestamp
28 31
 
... ...
@@ -7,6 +7,7 @@ docker-exec - Run a command in a running container
7 7
 # SYNOPSIS
8 8
 **docker exec**
9 9
 [**-d**|**--detach**[=*false*]]
10
+[**--help**]
10 11
 [**-i**|**--interactive**[=*false*]]
11 12
 [**-t**|**--tty**[=*false*]]
12 13
 CONTAINER COMMAND [ARG...]
... ...
@@ -25,6 +26,9 @@ container is unpaused, and then run
25 25
 **-d**, **--detach**=*true*|*false*
26 26
    Detached mode: run command in the background. The default is *false*.
27 27
 
28
+**--help**
29
+  Print usage statement
30
+
28 31
 **-i**, **--interactive**=*true*|*false*
29 32
    Keep STDIN open even if not attached. The default is *false*.
30 33
 
... ...
@@ -6,6 +6,7 @@ docker-export - Export the contents of a filesystem as a tar archive to STDOUT
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker export**
9
+[**--help**]
9 10
 CONTAINER
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -14,7 +15,8 @@ container ID or container name. The output is exported to STDOUT and can be
14 14
 redirected to a tar file.
15 15
 
16 16
 # OPTIONS
17
-There are no available options.
17
+**--help**
18
+  Print usage statement
18 19
 
19 20
 # EXAMPLES
20 21
 Export the contents of the container called angry_bell to a tar file
... ...
@@ -6,6 +6,7 @@ docker-history - Show the history of an image
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker history**
9
+[**--help**]
9 10
 [**--no-trunc**[=*false*]]
10 11
 [**-q**|**--quiet**[=*false*]]
11 12
 IMAGE
... ...
@@ -15,6 +16,9 @@ IMAGE
15 15
 Show the history of when and how an image was created.
16 16
 
17 17
 # OPTIONS
18
+**--help**
19
+  Print usage statement
20
+
18 21
 **--no-trunc**=*true*|*false*
19 22
    Don't truncate output. The default is *false*.
20 23
 
... ...
@@ -6,6 +6,7 @@ docker-images - List images
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker images**
9
+[**--help**]
9 10
 [**-a**|**--all**[=*false*]]
10 11
 [**-f**|**--filter**[=*[]*]]
11 12
 [**--no-trunc**[=*false*]]
... ...
@@ -35,6 +36,9 @@ versions.
35 35
 **-f**, **--filter**=[]
36 36
    Provide filter values (i.e. 'dangling=true')
37 37
 
38
+**--help**
39
+  Print usage statement
40
+
38 41
 **--no-trunc**=*true*|*false*
39 42
    Don't truncate output. The default is *false*.
40 43
 
... ...
@@ -6,6 +6,7 @@ docker-import - Create an empty filesystem image and import the contents of the
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker import**
9
+[**--help**]
9 10
 URL|- [REPOSITORY[:TAG]]
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -13,7 +14,8 @@ Create a new filesystem image from the contents of a tarball (`.tar`,
13 13
 `.tar.gz`, `.tgz`, `.bzip`, `.tar.xz`, `.txz`) into it, then optionally tag it.
14 14
 
15 15
 # OPTIONS
16
-There are no available options.
16
+**--help**
17
+  Print usage statement
17 18
 
18 19
 # EXAMPLES
19 20
 
... ...
@@ -6,6 +6,7 @@ docker-info - Display system-wide information
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker info**
9
+[**--help**]
9 10
 
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -20,7 +21,8 @@ allocates a certain amount of data space and meta data space from the space
20 20
 available on the volume where `/var/lib/docker` is mounted.
21 21
 
22 22
 # OPTIONS
23
-There are no available options.
23
+**--help**
24
+  Print usage statement
24 25
 
25 26
 # EXAMPLES
26 27
 
... ...
@@ -6,6 +6,7 @@ docker-inspect - Return low-level information on a container or image
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker inspect**
9
+[**--help**]
9 10
 [**-f**|**--format**[=*FORMAT*]]
10 11
 CONTAINER|IMAGE [CONTAINER|IMAGE...]
11 12
 
... ...
@@ -17,6 +18,9 @@ array. If a format is specified, the given template will be executed for
17 17
 each result.
18 18
 
19 19
 # OPTIONS
20
+**--help**
21
+  Print usage statement
22
+
20 23
 **-f**, **--format**=""
21 24
    Format the output using the given go template.
22 25
 
... ...
@@ -6,6 +6,7 @@ docker-kill - Kill a running container using SIGKILL or a specified signal
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker kill**
9
+[**--help**]
9 10
 [**-s**|**--signal**[=*"KILL"*]]
10 11
 CONTAINER [CONTAINER...]
11 12
 
... ...
@@ -15,6 +16,9 @@ The main process inside each container specified will be sent SIGKILL,
15 15
  or any signal specified with option --signal.
16 16
 
17 17
 # OPTIONS
18
+**--help**
19
+  Print usage statement
20
+
18 21
 **-s**, **--signal**="KILL"
19 22
    Signal to send to the container
20 23
 
... ...
@@ -6,6 +6,7 @@ docker-load - Load an image from a tar archive on STDIN
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker load**
9
+[**--help**]
9 10
 [**-i**|**--input**[=*INPUT*]]
10 11
 
11 12
 
... ...
@@ -15,6 +16,9 @@ Loads a tarred repository from a file or the standard input stream.
15 15
 Restores both images and tags.
16 16
 
17 17
 # OPTIONS
18
+**--help**
19
+  Print usage statement
20
+
18 21
 **-i**, **--input**=""
19 22
    Read from a tar archive file, instead of STDIN
20 23
 
... ...
@@ -7,6 +7,7 @@ docker-login - Register or log in to a Docker registry server, if no server is s
7 7
 # SYNOPSIS
8 8
 **docker login**
9 9
 [**-e**|**--email**[=*EMAIL*]]
10
+[**--help**]
10 11
 [**-p**|**--password**[=*PASSWORD*]]
11 12
 [**-u**|**--username**[=*USERNAME*]]
12 13
 [SERVER]
... ...
@@ -20,6 +21,9 @@ login to a private registry you can specify this by adding the server name.
20 20
 **-e**, **--email**=""
21 21
    Email
22 22
 
23
+**--help**
24
+  Print usage statement
25
+
23 26
 **-p**, **--password**=""
24 27
    Password
25 28
 
... ...
@@ -7,6 +7,7 @@ docker-logs - Fetch the logs of a container
7 7
 # SYNOPSIS
8 8
 **docker logs**
9 9
 [**-f**|**--follow**[=*false*]]
10
+[**--help**]
10 11
 [**-t**|**--timestamps**[=*false*]]
11 12
 [**--tail**[=*"all"*]]
12 13
 CONTAINER
... ...
@@ -22,6 +23,9 @@ The **docker logs --follow** command combines commands **docker logs** and
22 22
 then continue streaming new output from the container’s stdout and stderr.
23 23
 
24 24
 # OPTIONS
25
+**--help**
26
+  Print usage statement
27
+
25 28
 **-f**, **--follow**=*true*|*false*
26 29
    Follow log output. The default is *false*.
27 30
 
... ...
@@ -6,13 +6,15 @@ docker-port - List port mappings for the CONTAINER, or lookup the public-facing
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker port**
9
+[**--help**]
9 10
 CONTAINER [PRIVATE_PORT[/PROTO]]
10 11
 
11 12
 # DESCRIPTION
12 13
 List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT
13 14
 
14 15
 # OPTIONS
15
-There are no available options.
16
+**--help**
17
+  Print usage statement
16 18
 
17 19
 # EXAMPLES
18 20
 You can find out all the ports mapped by not specifying a `PRIVATE_PORT`, or
... ...
@@ -8,6 +8,7 @@ docker-ps - List containers
8 8
 **docker ps**
9 9
 [**-a**|**--all**[=*false*]]
10 10
 [**--before**[=*BEFORE*]]
11
+[**--help**]
11 12
 [**-f**|**--filter**[=*[]*]]
12 13
 [**-l**|**--latest**[=*false*]]
13 14
 [**-n**[=*-1*]]
... ...
@@ -29,6 +30,9 @@ the running containers.
29 29
 **--before**=""
30 30
    Show only container created before Id or Name, include non-running ones.
31 31
 
32
+**--help**
33
+  Print usage statement
34
+
32 35
 **-f**, **--filter**=[]
33 36
    Provide filter values. Valid filters:
34 37
                           exited=<int> - containers with exit code of <int>
... ...
@@ -7,6 +7,7 @@ docker-pull - Pull an image or a repository from the registry
7 7
 # SYNOPSIS
8 8
 **docker pull**
9 9
 [**-a**|**--all-tags**[=*false*]]
10
+[**--help**] 
10 11
 NAME[:TAG]
11 12
 
12 13
 # DESCRIPTION
... ...
@@ -19,8 +20,10 @@ It is also possible to specify a non-default registry to pull from.
19 19
 # OPTIONS
20 20
 **-a**, **--all-tags**=*true*|*false*
21 21
    Download all tagged images in the repository. The default is *false*.
22
+**--help**
23
+  Print usage statement
22 24
 
23
-# EXAMPLES
25
+# EXAMPLE
24 26
 
25 27
 # Pull a repository with multiple images
26 28
 # Note that if the  image is previously downloaded then the status would be
... ...
@@ -6,6 +6,7 @@ docker-push - Push an image or a repository to the registry
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker push**
9
+[**--help**]
9 10
 NAME[:TAG]
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -15,7 +16,8 @@ image can be pushed to another, perhaps private, registry as demonstrated in
15 15
 the example below.
16 16
 
17 17
 # OPTIONS
18
-There are no available options.
18
+**--help**
19
+  Print usage statement
19 20
 
20 21
 # EXAMPLES
21 22
 
... ...
@@ -6,6 +6,7 @@ docker-restart - Restart a running container
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker restart**
9
+[**--help**]
9 10
 [**-t**|**--time**[=*10*]]
10 11
 CONTAINER [CONTAINER...]
11 12
 
... ...
@@ -13,6 +14,9 @@ CONTAINER [CONTAINER...]
13 13
 Restart each container listed.
14 14
 
15 15
 # OPTIONS
16
+**--help**
17
+  Print usage statement
18
+
16 19
 **-t**, **--time**=10
17 20
    Number of seconds to try to stop for before killing the container. Once killed it will then be restarted. Default is 10 seconds.
18 21
 
... ...
@@ -19,6 +19,9 @@ remove a running container unless you use the \fB-f\fR option. To see all
19 19
 containers on a host use the **docker ps -a** command.
20 20
 
21 21
 # OPTIONS
22
+**--help**
23
+  Print usage statement
24
+
22 25
 **-f**, **--force**=*true*|*false*
23 26
    Force the removal of a running container (uses SIGKILL). The default is *false*.
24 27
 
... ...
@@ -7,6 +7,7 @@ docker-rmi - Remove one or more images
7 7
 # SYNOPSIS
8 8
 **docker rmi**
9 9
 [**-f**|**--force**[=*false*]]
10
+[**--help**]
10 11
 [**--no-prune**[=*false*]]
11 12
 IMAGE [IMAGE...]
12 13
 
... ...
@@ -21,6 +22,9 @@ use the **docker images** command.
21 21
 **-f**, **--force**=*true*|*false*
22 22
    Force removal of the image. The default is *false*.
23 23
 
24
+**--help**
25
+  Print usage statement
26
+
24 27
 **--no-prune**=*true*|*false*
25 28
    Do not delete untagged parents. The default is *false*.
26 29
 
... ...
@@ -22,6 +22,7 @@ docker-run - Run a command in a new container
22 22
 [**--env-file**[=*[]*]]
23 23
 [**--expose**[=*[]*]]
24 24
 [**-h**|**--hostname**[=*HOSTNAME*]]
25
+[**--help**]
25 26
 [**-i**|**--interactive**[=*false*]]
26 27
 [**--ipc**[=*IPC*]]
27 28
 [**--link**[=*[]*]]
... ...
@@ -153,6 +154,9 @@ ENTRYPOINT.
153 153
 
154 154
    Sets the container host name that is available inside the container.
155 155
 
156
+**--help**
157
+  Print usage statement
158
+
156 159
 **-i**, **--interactive**=*true*|*false*
157 160
    Keep STDIN open even if not attached. The default is *false*.
158 161
 
... ...
@@ -6,6 +6,7 @@ docker-save - Save an image(s) to a tar archive (streamed to STDOUT by default)
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker save**
9
+[**--help**]
9 10
 [**-o**|**--output**[=*OUTPUT*]]
10 11
 IMAGE [IMAGE...]
11 12
 
... ...
@@ -16,6 +17,9 @@ parent layers, and all tags + versions, or specified repo:tag.
16 16
 Stream to a file instead of STDOUT by using **-o**.
17 17
 
18 18
 # OPTIONS
19
+**--help**
20
+  Print usage statement
21
+
19 22
 **-o**, **--output**=""
20 23
    Write to a file, instead of STDOUT
21 24
 
... ...
@@ -7,6 +7,7 @@ docker-search - Search the Docker Hub for images
7 7
 # SYNOPSIS
8 8
 **docker search**
9 9
 [**--automated**[=*false*]]
10
+[**--help**]
10 11
 [**--no-trunc**[=*false*]]
11 12
 [**-s**|**--stars**[=*0*]]
12 13
 TERM
... ...
@@ -22,6 +23,9 @@ is automated.
22 22
 **--automated**=*true*|*false*
23 23
    Only show automated builds. The default is *false*.
24 24
 
25
+**--help**
26
+  Print usage statement
27
+
25 28
 **--no-trunc**=*true*|*false*
26 29
    Don't truncate output. The default is *false*.
27 30
 
... ...
@@ -7,6 +7,7 @@ docker-start - Restart a stopped container
7 7
 # SYNOPSIS
8 8
 **docker start**
9 9
 [**-a**|**--attach**[=*false*]]
10
+[**--help**]
10 11
 [**-i**|**--interactive**[=*false*]]
11 12
 CONTAINER [CONTAINER...]
12 13
 
... ...
@@ -18,6 +19,9 @@ Start a stopped container.
18 18
 **-a**, **--attach**=*true*|*false*
19 19
    Attach container's STDOUT and STDERR and forward all signals to the process. The default is *false*.
20 20
 
21
+**--help**
22
+  Print usage statement
23
+
21 24
 **-i**, **--interactive**=*true*|*false*
22 25
    Attach container's STDIN. The default is *false*.
23 26
 
... ...
@@ -6,6 +6,7 @@ docker-stop - Stop a running container by sending SIGTERM and then SIGKILL after
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker stop**
9
+[**--help**]
9 10
 [**-t**|**--time**[=*10*]]
10 11
 CONTAINER [CONTAINER...]
11 12
 
... ...
@@ -14,6 +15,9 @@ Stop a running container (Send SIGTERM, and then SIGKILL after
14 14
  grace period)
15 15
 
16 16
 # OPTIONS
17
+**--help**
18
+  Print usage statement
19
+
17 20
 **-t**, **--time**=10
18 21
    Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.
19 22
 
... ...
@@ -7,6 +7,7 @@ docker-tag - Tag an image into a repository
7 7
 # SYNOPSIS
8 8
 **docker tag**
9 9
 [**-f**|**--force**[=*false*]]
10
+[**--help**]
10 11
 IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
11 12
 
12 13
 # DESCRIPTION
... ...
@@ -6,6 +6,7 @@ docker-top - Display the running processes of a container
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker top**
9
+[**--help**]
9 10
 CONTAINER [ps OPTIONS]
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -14,7 +15,8 @@ Look up the running process of the container. ps-OPTION can be any of the
14 14
  options you would pass to a Linux ps command.
15 15
 
16 16
 # OPTIONS
17
-There are no available options.
17
+**--help**
18
+  Print usage statement
18 19
 
19 20
 # EXAMPLES
20 21
 
... ...
@@ -6,6 +6,7 @@ docker-wait - Block until a container stops, then print its exit code.
6 6
 
7 7
 # SYNOPSIS
8 8
 **docker wait**
9
+[**--help**]
9 10
 CONTAINER [CONTAINER...]
10 11
 
11 12
 # DESCRIPTION
... ...
@@ -13,7 +14,8 @@ CONTAINER [CONTAINER...]
13 13
 Block until a container stops, then print its exit code.
14 14
 
15 15
 # OPTIONS
16
-There are no available options.
16
+**--help**
17
+  Print usage statement
17 18
 
18 19
 # EXAMPLES
19 20
 
... ...
@@ -26,6 +26,9 @@ To see the man page for a command run **man docker <command>**.
26 26
 **-D**=*true*|*false*
27 27
    Enable debug mode. Default is false.
28 28
 
29
+**--help**
30
+  Print usage statement
31
+
29 32
 **-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host:port] to bind or
30 33
 unix://[/path/to/socket] to use.
31 34
    The socket(s) to bind to in daemon mode specified using one or more
... ...
@@ -15,6 +15,19 @@ or execute `docker help`:
15 15
 
16 16
       ...
17 17
 
18
+## Help
19
+To list the help on any command just execute the command, followed by the `--help` option.
20
+
21
+    $ sudo docker run --help
22
+
23
+    Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
24
+
25
+    Run a command in a new container
26
+
27
+      -a, --attach=[]            Attach to STDIN, STDOUT or STDERR.
28
+      -c, --cpu-shares=0         CPU shares (relative weight)
29
+    ...
30
+
18 31
 ## Option types
19 32
 
20 33
 Single character commandline options can be combined, so rather than
... ...
@@ -410,6 +410,47 @@ func IsSet(name string) bool {
410 410
 	return CommandLine.IsSet(name)
411 411
 }
412 412
 
413
+// Indicator used to pass to BadArgs function
414
+const (
415
+	Exact = 1
416
+	Max   = 2
417
+	Min   = 3
418
+)
419
+
420
+// Bad Args takes two arguments.
421
+// The first one indicates whether the number of arguments should, be
422
+// A Minimal number of arguments, a maximum number of arguments or
423
+// The exact number of arguments required
424
+// If the actuall number of arguments is not valid and error message
425
+// prints and true is returned, otherwise false is returned
426
+func (f *FlagSet) BadArgs(arg_type, nargs int) bool {
427
+	if arg_type == Max && f.NArg() > nargs {
428
+		if nargs == 1 {
429
+			fmt.Fprintf(f.out(), "docker: '%s' requires a maximum of 1 argument. See 'docker %s --help'.\n", f.name, f.name)
430
+		} else {
431
+			fmt.Fprintf(f.out(), "docker: '%s' requires a maximum of %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
432
+		}
433
+		return true
434
+	}
435
+	if arg_type == Exact && f.NArg() != nargs {
436
+		if nargs == 1 {
437
+			fmt.Fprintf(f.out(), "docker: '%s' requires 1 argument. See 'docker %s --help'.\n", f.name, f.name)
438
+		} else {
439
+			fmt.Fprintf(f.out(), "docker: '%s' requires %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
440
+		}
441
+		return true
442
+	}
443
+	if arg_type == Min && f.NArg() < nargs {
444
+		if nargs == 1 {
445
+			fmt.Fprintf(f.out(), "docker: '%s' requires a minimum of 1 argument. See 'docker %s --help'.\n", f.name, f.name)
446
+		} else {
447
+			fmt.Fprintf(f.out(), "docker: '%s' requires a minimum of %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
448
+		}
449
+		return true
450
+	}
451
+	return false
452
+}
453
+
413 454
 // Set sets the value of the named flag.
414 455
 func (f *FlagSet) Set(name, value string) error {
415 456
 	flag, ok := f.formal[name]
... ...
@@ -483,7 +524,7 @@ func defaultUsage(f *FlagSet) {
483 483
 // Usage prints to standard error a usage message documenting all defined command-line flags.
484 484
 // The function is a variable that may be changed to point to a custom function.
485 485
 var Usage = func() {
486
-	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
486
+	fmt.Fprintf(CommandLine.output, "Usage of %s:\n", os.Args[0])
487 487
 	PrintDefaults()
488 488
 }
489 489
 
... ...
@@ -789,7 +830,7 @@ func Var(value Value, names []string, usage string) {
789 789
 func (f *FlagSet) failf(format string, a ...interface{}) error {
790 790
 	err := fmt.Errorf(format, a...)
791 791
 	fmt.Fprintln(f.out(), err)
792
-	f.usage()
792
+	fmt.Fprintf(f.out(), "See 'docker %s --help'.\n", f.name)
793 793
 	return err
794 794
 }
795 795
 
... ...
@@ -5,6 +5,7 @@ import (
5 5
 
6 6
 	"github.com/docker/docker/engine"
7 7
 	flag "github.com/docker/docker/pkg/mflag"
8
+	"os"
8 9
 )
9 10
 
10 11
 type ExecConfig struct {
... ...
@@ -45,17 +46,22 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
45 45
 		flStdin   = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
46 46
 		flTty     = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
47 47
 		flDetach  = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
48
+		help      = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
48 49
 		execCmd   []string
49 50
 		container string
50 51
 	)
51 52
 	if err := cmd.Parse(args); err != nil {
52 53
 		return nil, err
53 54
 	}
54
-	parsedArgs := cmd.Args()
55
-	if len(parsedArgs) < 2 {
56
-		return nil, fmt.Errorf("not enough arguments to create exec command")
55
+	if *help {
56
+		cmd.Usage()
57
+		return nil, nil
58
+	}
59
+	if cmd.BadArgs(flag.Min, 2) {
60
+		os.Exit(1)
57 61
 	}
58 62
 	container = cmd.Arg(0)
63
+	parsedArgs := cmd.Args()
59 64
 	execCmd = parsedArgs[1:]
60 65
 
61 66
 	execConfig := &ExecConfig{
... ...
@@ -2,6 +2,7 @@ package runconfig
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"os"
5 6
 	"path"
6 7
 	"strconv"
7 8
 	"strings"
... ...
@@ -61,6 +62,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
61 61
 		flMacAddress      = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
62 62
 		flIpcMode         = cmd.String([]string{"-ipc"}, "", "Default is to create a private IPC namespace (POSIX SysV IPC) for the container\n'container:<name|id>': reuses another container shared memory, semaphores and message queues\n'host': use the host shared memory,semaphores and message queues inside the container.  Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.")
63 63
 		flRestartPolicy   = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
64
+		help              = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
64 65
 	)
65 66
 
66 67
 	cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
... ...
@@ -86,6 +88,13 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
86 86
 	if err := cmd.Parse(args); err != nil {
87 87
 		return nil, nil, cmd, err
88 88
 	}
89
+	if *help {
90
+		cmd.Usage()
91
+		return nil, nil, cmd, nil
92
+	}
93
+	if cmd.BadArgs(flag.Min, 1) {
94
+		os.Exit(1)
95
+	}
89 96
 
90 97
 	// Validate input params
91 98
 	if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
... ...
@@ -156,11 +165,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
156 156
 		parsedArgs = cmd.Args()
157 157
 		runCmd     []string
158 158
 		entrypoint []string
159
-		image      string
159
+		image      = cmd.Arg(0)
160 160
 	)
161
-	if len(parsedArgs) >= 1 {
162
-		image = cmd.Arg(0)
163
-	}
164 161
 	if len(parsedArgs) > 1 {
165 162
 		runCmd = parsedArgs[1:]
166 163
 	}