Browse code

Exit with non-zero code on first argument parsing error

Ignoring return value of ParseFlags leads to exit code 0 if bad
arguments are supplied. This patch makes sure that subcommands exit
with non-zero code in such a case.

Signed-off-by: Michal Minar <miminar@redhat.com>

Michal Minar authored on 2014/11/25 01:34:13
Showing 3 changed files
... ...
@@ -83,8 +83,14 @@ func (cli *DockerCli) Cmd(args ...string) error {
83 83
 	return cli.CmdHelp()
84 84
 }
85 85
 
86
-func (cli *DockerCli) Subcmd(name, signature, description string) *flag.FlagSet {
87
-	flags := flag.NewFlagSet(name, flag.ContinueOnError)
86
+func (cli *DockerCli) Subcmd(name, signature, description string, exitOnError bool) *flag.FlagSet {
87
+	var errorHandling flag.ErrorHandling
88
+	if exitOnError {
89
+		errorHandling = flag.ExitOnError
90
+	} else {
91
+		errorHandling = flag.ContinueOnError
92
+	}
93
+	flags := flag.NewFlagSet(name, errorHandling)
88 94
 	flags.Usage = func() {
89 95
 		options := ""
90 96
 		if flags.FlagCountUndeprecated() > 0 {
... ...
@@ -77,7 +77,7 @@ func (cli *DockerCli) CmdHelp(args ...string) error {
77 77
 }
78 78
 
79 79
 func (cli *DockerCli) CmdBuild(args ...string) error {
80
-	cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH")
80
+	cmd := cli.Subcmd("build", "PATH | URL | -", "Build a new image from the source code at PATH", true)
81 81
 	tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
82 82
 	suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the verbose output generated by the containers")
83 83
 	noCache := cmd.Bool([]string{"#no-cache", "-no-cache"}, false, "Do not use cache when building the image")
... ...
@@ -86,9 +86,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
86 86
 	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
87 87
 	cmd.Require(flag.Exact, 1)
88 88
 
89
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
90
-		return nil
91
-	}
89
+	utils.ParseFlags(cmd, args, true)
92 90
 
93 91
 	var (
94 92
 		context  archive.Archive
... ...
@@ -246,7 +244,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
246 246
 
247 247
 // 'docker login': login / register a user to registry service.
248 248
 func (cli *DockerCli) CmdLogin(args ...string) error {
249
-	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
249
+	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
250 250
 	cmd.Require(flag.Max, 1)
251 251
 
252 252
 	var username, password, email string
... ...
@@ -255,9 +253,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
255 255
 	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
256 256
 	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
257 257
 
258
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
259
-		return nil
260
-	}
258
+	utils.ParseFlags(cmd, args, true)
261 259
 
262 260
 	serverAddress := registry.IndexServerAddress()
263 261
 	if len(cmd.Args()) > 0 {
... ...
@@ -364,12 +360,10 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
364 364
 
365 365
 // log out from a Docker registry
366 366
 func (cli *DockerCli) CmdLogout(args ...string) error {
367
-	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
367
+	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.", true)
368 368
 	cmd.Require(flag.Max, 1)
369 369
 
370
-	if err := utils.ParseFlags(cmd, args, false); err != nil {
371
-		return nil
372
-	}
370
+	utils.ParseFlags(cmd, args, false)
373 371
 	serverAddress := registry.IndexServerAddress()
374 372
 	if len(cmd.Args()) > 0 {
375 373
 		serverAddress = cmd.Arg(0)
... ...
@@ -391,12 +385,10 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
391 391
 
392 392
 // 'docker wait': block until a container stops
393 393
 func (cli *DockerCli) CmdWait(args ...string) error {
394
-	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
394
+	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.", true)
395 395
 	cmd.Require(flag.Min, 1)
396 396
 
397
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
398
-		return nil
399
-	}
397
+	utils.ParseFlags(cmd, args, true)
400 398
 
401 399
 	var encounteredError error
402 400
 	for _, name := range cmd.Args() {
... ...
@@ -413,12 +405,10 @@ func (cli *DockerCli) CmdWait(args ...string) error {
413 413
 
414 414
 // 'docker version': show version information
415 415
 func (cli *DockerCli) CmdVersion(args ...string) error {
416
-	cmd := cli.Subcmd("version", "", "Show the Docker version information.")
416
+	cmd := cli.Subcmd("version", "", "Show the Docker version information.", true)
417 417
 	cmd.Require(flag.Exact, 0)
418 418
 
419
-	if err := utils.ParseFlags(cmd, args, false); err != nil {
420
-		return nil
421
-	}
419
+	utils.ParseFlags(cmd, args, false)
422 420
 
423 421
 	if dockerversion.VERSION != "" {
424 422
 		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
... ...
@@ -457,11 +447,9 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
457 457
 
458 458
 // 'docker info': display system-wide information.
459 459
 func (cli *DockerCli) CmdInfo(args ...string) error {
460
-	cmd := cli.Subcmd("info", "", "Display system-wide information")
460
+	cmd := cli.Subcmd("info", "", "Display system-wide information", true)
461 461
 	cmd.Require(flag.Exact, 0)
462
-	if err := utils.ParseFlags(cmd, args, false); err != nil {
463
-		return nil
464
-	}
462
+	utils.ParseFlags(cmd, args, false)
465 463
 
466 464
 	body, _, err := readBody(cli.call("GET", "/info", nil, false))
467 465
 	if err != nil {
... ...
@@ -573,13 +561,11 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
573 573
 }
574 574
 
575 575
 func (cli *DockerCli) CmdStop(args ...string) error {
576
-	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
576
+	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period", true)
577 577
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
578 578
 	cmd.Require(flag.Min, 1)
579 579
 
580
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
581
-		return nil
582
-	}
580
+	utils.ParseFlags(cmd, args, true)
583 581
 
584 582
 	v := url.Values{}
585 583
 	v.Set("t", strconv.Itoa(*nSeconds))
... ...
@@ -598,13 +584,11 @@ func (cli *DockerCli) CmdStop(args ...string) error {
598 598
 }
599 599
 
600 600
 func (cli *DockerCli) CmdRestart(args ...string) error {
601
-	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
601
+	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container", true)
602 602
 	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.")
603 603
 	cmd.Require(flag.Min, 1)
604 604
 
605
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
606
-		return nil
607
-	}
605
+	utils.ParseFlags(cmd, args, true)
608 606
 
609 607
 	v := url.Values{}
610 608
 	v.Set("t", strconv.Itoa(*nSeconds))
... ...
@@ -653,15 +637,13 @@ func (cli *DockerCli) CmdStart(args ...string) error {
653 653
 		cErr chan error
654 654
 		tty  bool
655 655
 
656
-		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
656
+		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container", true)
657 657
 		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
658 658
 		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
659 659
 	)
660 660
 
661 661
 	cmd.Require(flag.Min, 1)
662
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
663
-		return nil
664
-	}
662
+	utils.ParseFlags(cmd, args, true)
665 663
 
666 664
 	hijacked := make(chan io.Closer)
667 665
 
... ...
@@ -763,11 +745,9 @@ func (cli *DockerCli) CmdStart(args ...string) error {
763 763
 }
764 764
 
765 765
 func (cli *DockerCli) CmdUnpause(args ...string) error {
766
-	cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container")
766
+	cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container", true)
767 767
 	cmd.Require(flag.Exact, 1)
768
-	if err := utils.ParseFlags(cmd, args, false); err != nil {
769
-		return nil
770
-	}
768
+	utils.ParseFlags(cmd, args, false)
771 769
 
772 770
 	var encounteredError error
773 771
 	for _, name := range cmd.Args() {
... ...
@@ -782,11 +762,9 @@ func (cli *DockerCli) CmdUnpause(args ...string) error {
782 782
 }
783 783
 
784 784
 func (cli *DockerCli) CmdPause(args ...string) error {
785
-	cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container")
785
+	cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container", true)
786 786
 	cmd.Require(flag.Exact, 1)
787
-	if err := utils.ParseFlags(cmd, args, false); err != nil {
788
-		return nil
789
-	}
787
+	utils.ParseFlags(cmd, args, false)
790 788
 
791 789
 	var encounteredError error
792 790
 	for _, name := range cmd.Args() {
... ...
@@ -801,13 +779,11 @@ func (cli *DockerCli) CmdPause(args ...string) error {
801 801
 }
802 802
 
803 803
 func (cli *DockerCli) CmdInspect(args ...string) error {
804
-	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
804
+	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image", true)
805 805
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
806 806
 	cmd.Require(flag.Min, 1)
807 807
 
808
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
809
-		return nil
810
-	}
808
+	utils.ParseFlags(cmd, args, true)
811 809
 
812 810
 	var tmpl *template.Template
813 811
 	if *tmplStr != "" {
... ...
@@ -879,12 +855,10 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
879 879
 }
880 880
 
881 881
 func (cli *DockerCli) CmdTop(args ...string) error {
882
-	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
882
+	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container", true)
883 883
 	cmd.Require(flag.Min, 1)
884 884
 
885
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
886
-		return nil
887
-	}
885
+	utils.ParseFlags(cmd, args, true)
888 886
 
889 887
 	val := url.Values{}
890 888
 	if cmd.NArg() > 1 {
... ...
@@ -913,11 +887,9 @@ func (cli *DockerCli) CmdTop(args ...string) error {
913 913
 }
914 914
 
915 915
 func (cli *DockerCli) CmdPort(args ...string) error {
916
-	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")
916
+	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", true)
917 917
 	cmd.Require(flag.Min, 1)
918
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
919
-		return nil
920
-	}
918
+	utils.ParseFlags(cmd, args, true)
921 919
 
922 920
 	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
923 921
 	if err != nil {
... ...
@@ -966,15 +938,13 @@ func (cli *DockerCli) CmdPort(args ...string) error {
966 966
 // 'docker rmi IMAGE' removes all images with the name IMAGE
967 967
 func (cli *DockerCli) CmdRmi(args ...string) error {
968 968
 	var (
969
-		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images")
969
+		cmd     = cli.Subcmd("rmi", "IMAGE [IMAGE...]", "Remove one or more images", true)
970 970
 		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
971 971
 		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
972 972
 	)
973 973
 	cmd.Require(flag.Min, 1)
974 974
 
975
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
976
-		return nil
977
-	}
975
+	utils.ParseFlags(cmd, args, true)
978 976
 
979 977
 	v := url.Values{}
980 978
 	if *force {
... ...
@@ -1010,14 +980,12 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
1010 1010
 }
1011 1011
 
1012 1012
 func (cli *DockerCli) CmdHistory(args ...string) error {
1013
-	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image")
1013
+	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image", true)
1014 1014
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
1015 1015
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1016 1016
 	cmd.Require(flag.Exact, 1)
1017 1017
 
1018
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1019
-		return nil
1020
-	}
1018
+	utils.ParseFlags(cmd, args, true)
1021 1019
 
1022 1020
 	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
1023 1021
 	if err != nil {
... ...
@@ -1064,15 +1032,13 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
1064 1064
 }
1065 1065
 
1066 1066
 func (cli *DockerCli) CmdRm(args ...string) error {
1067
-	cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers")
1067
+	cmd := cli.Subcmd("rm", "CONTAINER [CONTAINER...]", "Remove one or more containers", true)
1068 1068
 	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
1069 1069
 	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
1070 1070
 	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
1071 1071
 	cmd.Require(flag.Min, 1)
1072 1072
 
1073
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1074
-		return nil
1075
-	}
1073
+	utils.ParseFlags(cmd, args, true)
1076 1074
 
1077 1075
 	val := url.Values{}
1078 1076
 	if *v {
... ...
@@ -1101,13 +1067,11 @@ func (cli *DockerCli) CmdRm(args ...string) error {
1101 1101
 
1102 1102
 // 'docker kill NAME' kills a running container
1103 1103
 func (cli *DockerCli) CmdKill(args ...string) error {
1104
-	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
1104
+	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal", true)
1105 1105
 	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
1106 1106
 	cmd.Require(flag.Min, 1)
1107 1107
 
1108
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1109
-		return nil
1110
-	}
1108
+	utils.ParseFlags(cmd, args, true)
1111 1109
 
1112 1110
 	var encounteredError error
1113 1111
 	for _, name := range cmd.Args() {
... ...
@@ -1122,12 +1086,10 @@ func (cli *DockerCli) CmdKill(args ...string) error {
1122 1122
 }
1123 1123
 
1124 1124
 func (cli *DockerCli) CmdImport(args ...string) error {
1125
-	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.")
1125
+	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.", true)
1126 1126
 	cmd.Require(flag.Min, 1)
1127 1127
 
1128
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1129
-		return nil
1130
-	}
1128
+	utils.ParseFlags(cmd, args, true)
1131 1129
 
1132 1130
 	var (
1133 1131
 		v          = url.Values{}
... ...
@@ -1161,12 +1123,10 @@ func (cli *DockerCli) CmdImport(args ...string) error {
1161 1161
 }
1162 1162
 
1163 1163
 func (cli *DockerCli) CmdPush(args ...string) error {
1164
-	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
1164
+	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry", true)
1165 1165
 	cmd.Require(flag.Exact, 1)
1166 1166
 
1167
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1168
-		return nil
1169
-	}
1167
+	utils.ParseFlags(cmd, args, true)
1170 1168
 
1171 1169
 	name := cmd.Arg(0)
1172 1170
 
... ...
@@ -1224,13 +1184,11 @@ func (cli *DockerCli) CmdPush(args ...string) error {
1224 1224
 }
1225 1225
 
1226 1226
 func (cli *DockerCli) CmdPull(args ...string) error {
1227
-	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
1227
+	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry", true)
1228 1228
 	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
1229 1229
 	cmd.Require(flag.Exact, 1)
1230 1230
 
1231
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1232
-		return nil
1233
-	}
1231
+	utils.ParseFlags(cmd, args, true)
1234 1232
 
1235 1233
 	var (
1236 1234
 		v         = url.Values{}
... ...
@@ -1288,7 +1246,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
1288 1288
 }
1289 1289
 
1290 1290
 func (cli *DockerCli) CmdImages(args ...string) error {
1291
-	cmd := cli.Subcmd("images", "[REPOSITORY]", "List images")
1291
+	cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true)
1292 1292
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
1293 1293
 	all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (by default filter out the intermediate image layers)")
1294 1294
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
... ...
@@ -1300,9 +1258,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
1300 1300
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
1301 1301
 	cmd.Require(flag.Max, 1)
1302 1302
 
1303
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1304
-		return nil
1305
-	}
1303
+	utils.ParseFlags(cmd, args, true)
1306 1304
 
1307 1305
 	// Consolidate all filter flags, and sanity check them early.
1308 1306
 	// They'll get process in the daemon/server.
... ...
@@ -1528,7 +1484,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1528 1528
 		psFilterArgs = filters.Args{}
1529 1529
 		v            = url.Values{}
1530 1530
 
1531
-		cmd      = cli.Subcmd("ps", "", "List containers")
1531
+		cmd      = cli.Subcmd("ps", "", "List containers", true)
1532 1532
 		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
1533 1533
 		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
1534 1534
 		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
... ...
@@ -1543,9 +1499,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1543 1543
 
1544 1544
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
1545 1545
 
1546
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1547
-		return nil
1548
-	}
1546
+	utils.ParseFlags(cmd, args, true)
1549 1547
 	if *last == -1 && *nLatest {
1550 1548
 		*last = 1
1551 1549
 	}
... ...
@@ -1680,7 +1634,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
1680 1680
 }
1681 1681
 
1682 1682
 func (cli *DockerCli) CmdCommit(args ...string) error {
1683
-	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes")
1683
+	cmd := cli.Subcmd("commit", "CONTAINER [REPOSITORY[:TAG]]", "Create a new image from a container's changes", true)
1684 1684
 	flPause := cmd.Bool([]string{"p", "-pause"}, true, "Pause container during commit")
1685 1685
 	flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
1686 1686
 	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
... ...
@@ -1688,9 +1642,7 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
1688 1688
 	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")
1689 1689
 	cmd.Require(flag.Max, 2)
1690 1690
 	cmd.Require(flag.Min, 1)
1691
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1692
-		return nil
1693
-	}
1691
+	utils.ParseFlags(cmd, args, true)
1694 1692
 
1695 1693
 	var (
1696 1694
 		name            = cmd.Arg(0)
... ...
@@ -1738,16 +1690,14 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
1738 1738
 }
1739 1739
 
1740 1740
 func (cli *DockerCli) CmdEvents(args ...string) error {
1741
-	cmd := cli.Subcmd("events", "", "Get real time events from the server")
1741
+	cmd := cli.Subcmd("events", "", "Get real time events from the server", true)
1742 1742
 	since := cmd.String([]string{"#since", "-since"}, "", "Show all events created since timestamp")
1743 1743
 	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
1744 1744
 	flFilter := opts.NewListOpts(nil)
1745 1745
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
1746 1746
 	cmd.Require(flag.Exact, 0)
1747 1747
 
1748
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1749
-		return nil
1750
-	}
1748
+	utils.ParseFlags(cmd, args, true)
1751 1749
 
1752 1750
 	var (
1753 1751
 		v               = url.Values{}
... ...
@@ -1795,12 +1745,10 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
1795 1795
 }
1796 1796
 
1797 1797
 func (cli *DockerCli) CmdExport(args ...string) error {
1798
-	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
1798
+	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT", true)
1799 1799
 	cmd.Require(flag.Exact, 1)
1800 1800
 
1801
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1802
-		return nil
1803
-	}
1801
+	utils.ParseFlags(cmd, args, true)
1804 1802
 
1805 1803
 	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
1806 1804
 		return err
... ...
@@ -1809,12 +1757,10 @@ func (cli *DockerCli) CmdExport(args ...string) error {
1809 1809
 }
1810 1810
 
1811 1811
 func (cli *DockerCli) CmdDiff(args ...string) error {
1812
-	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
1812
+	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem", true)
1813 1813
 	cmd.Require(flag.Exact, 1)
1814 1814
 
1815
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1816
-		return nil
1817
-	}
1815
+	utils.ParseFlags(cmd, args, true)
1818 1816
 
1819 1817
 	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
1820 1818
 
... ...
@@ -1843,16 +1789,14 @@ func (cli *DockerCli) CmdDiff(args ...string) error {
1843 1843
 
1844 1844
 func (cli *DockerCli) CmdLogs(args ...string) error {
1845 1845
 	var (
1846
-		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container")
1846
+		cmd    = cli.Subcmd("logs", "CONTAINER", "Fetch the logs of a container", true)
1847 1847
 		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
1848 1848
 		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
1849 1849
 		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
1850 1850
 	)
1851 1851
 	cmd.Require(flag.Exact, 1)
1852 1852
 
1853
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1854
-		return nil
1855
-	}
1853
+	utils.ParseFlags(cmd, args, true)
1856 1854
 
1857 1855
 	name := cmd.Arg(0)
1858 1856
 
... ...
@@ -1884,15 +1828,13 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
1884 1884
 
1885 1885
 func (cli *DockerCli) CmdAttach(args ...string) error {
1886 1886
 	var (
1887
-		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container")
1887
+		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container", true)
1888 1888
 		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
1889 1889
 		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.")
1890 1890
 	)
1891 1891
 	cmd.Require(flag.Exact, 1)
1892 1892
 
1893
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1894
-		return nil
1895
-	}
1893
+	utils.ParseFlags(cmd, args, true)
1896 1894
 	name := cmd.Arg(0)
1897 1895
 
1898 1896
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
... ...
@@ -1957,16 +1899,14 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
1957 1957
 }
1958 1958
 
1959 1959
 func (cli *DockerCli) CmdSearch(args ...string) error {
1960
-	cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images")
1960
+	cmd := cli.Subcmd("search", "TERM", "Search the Docker Hub for images", true)
1961 1961
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
1962 1962
 	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
1963 1963
 	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
1964 1964
 	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
1965 1965
 	cmd.Require(flag.Exact, 1)
1966 1966
 
1967
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
1968
-		return nil
1969
-	}
1967
+	utils.ParseFlags(cmd, args, true)
1970 1968
 
1971 1969
 	v := url.Values{}
1972 1970
 	v.Set("term", cmd.Arg(0))
... ...
@@ -2010,13 +1950,11 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
2010 2010
 type ports []int
2011 2011
 
2012 2012
 func (cli *DockerCli) CmdTag(args ...string) error {
2013
-	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
2013
+	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository", true)
2014 2014
 	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
2015 2015
 	cmd.Require(flag.Exact, 2)
2016 2016
 
2017
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
2018
-		return nil
2019
-	}
2017
+	utils.ParseFlags(cmd, args, true)
2020 2018
 
2021 2019
 	var (
2022 2020
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
... ...
@@ -2177,7 +2115,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
2177 2177
 }
2178 2178
 
2179 2179
 func (cli *DockerCli) CmdCreate(args ...string) error {
2180
-	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container")
2180
+	cmd := cli.Subcmd("create", "IMAGE [COMMAND] [ARG...]", "Create a new container", true)
2181 2181
 
2182 2182
 	// These are flags not stored in Config/HostConfig
2183 2183
 	var (
... ...
@@ -2205,7 +2143,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error {
2205 2205
 
2206 2206
 func (cli *DockerCli) CmdRun(args ...string) error {
2207 2207
 	// FIXME: just use runconfig.Parse already
2208
-	cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container")
2208
+	cmd := cli.Subcmd("run", "IMAGE [COMMAND] [ARG...]", "Run a command in a new container", true)
2209 2209
 
2210 2210
 	// These are flags not stored in Config/HostConfig
2211 2211
 	var (
... ...
@@ -2221,6 +2159,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
2221 2221
 	)
2222 2222
 
2223 2223
 	config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
2224
+	// just in case the Parse does not exit
2224 2225
 	if err != nil {
2225 2226
 		return &utils.StatusError{StatusCode: 1}
2226 2227
 	}
... ...
@@ -2405,12 +2344,10 @@ func (cli *DockerCli) CmdRun(args ...string) error {
2405 2405
 }
2406 2406
 
2407 2407
 func (cli *DockerCli) CmdCp(args ...string) error {
2408
-	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
2408
+	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH", true)
2409 2409
 	cmd.Require(flag.Exact, 2)
2410 2410
 
2411
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
2412
-		return nil
2413
-	}
2411
+	utils.ParseFlags(cmd, args, true)
2414 2412
 
2415 2413
 	var copyData engine.Env
2416 2414
 	info := strings.Split(cmd.Arg(0), ":")
... ...
@@ -2442,13 +2379,11 @@ func (cli *DockerCli) CmdCp(args ...string) error {
2442 2442
 }
2443 2443
 
2444 2444
 func (cli *DockerCli) CmdSave(args ...string) error {
2445
-	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)")
2445
+	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
2446 2446
 	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
2447 2447
 	cmd.Require(flag.Min, 1)
2448 2448
 
2449
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
2450
-		return err
2451
-	}
2449
+	utils.ParseFlags(cmd, args, true)
2452 2450
 
2453 2451
 	var (
2454 2452
 		output io.Writer = cli.out
... ...
@@ -2481,13 +2416,11 @@ func (cli *DockerCli) CmdSave(args ...string) error {
2481 2481
 }
2482 2482
 
2483 2483
 func (cli *DockerCli) CmdLoad(args ...string) error {
2484
-	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
2484
+	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN", true)
2485 2485
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
2486 2486
 	cmd.Require(flag.Exact, 0)
2487 2487
 
2488
-	if err := utils.ParseFlags(cmd, args, true); err != nil {
2489
-		return err
2490
-	}
2488
+	utils.ParseFlags(cmd, args, true)
2491 2489
 
2492 2490
 	var (
2493 2491
 		input io.Reader = cli.in
... ...
@@ -2506,9 +2439,10 @@ func (cli *DockerCli) CmdLoad(args ...string) error {
2506 2506
 }
2507 2507
 
2508 2508
 func (cli *DockerCli) CmdExec(args ...string) error {
2509
-	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container")
2509
+	cmd := cli.Subcmd("exec", "CONTAINER COMMAND [ARG...]", "Run a command in a running container", true)
2510 2510
 
2511 2511
 	execConfig, err := runconfig.ParseExec(cmd, args)
2512
+	// just in case the ParseExec does not exit
2512 2513
 	if execConfig.Container == "" || err != nil {
2513 2514
 		return &utils.StatusError{StatusCode: 1}
2514 2515
 	}
... ...
@@ -8,7 +8,10 @@ import (
8 8
 )
9 9
 
10 10
 // ParseFlags is a utility function that adds a help flag if withHelp is true,
11
-// calls cmd.Parse(args) and prints a relevant error message if there are incorrect number of arguments.
11
+// calls cmd.Parse(args) and prints a relevant error message if there are
12
+// incorrect number of arguments. It returns error only if error handling is
13
+// set to ContinueOnError and parsing fails. If error handling is set to
14
+// ExitOnError, it's safe to ignore the return value.
12 15
 // TODO: move this to a better package than utils
13 16
 func ParseFlags(cmd *flag.FlagSet, args []string, withHelp bool) error {
14 17
 	var help *bool