Преглед на файлове

refactor redundant code around calls to cmd.Parse

Signed-off-by: Tibor Vass <teabee89@gmail.com>
Tibor Vass преди 10 години
родител
ревизия
41be2f73c7
променени са 5 файла, в които са добавени 184 реда и са изтрити 345 реда
  1. 76 279
      api/client/commands.go
  2. 68 46
      pkg/mflag/flag.go
  3. 3 10
      runconfig/exec.go
  4. 3 10
      runconfig/parse.go
  5. 34 0
      utils/flags.go

+ 76 - 279
api/client/commands.go

@@ -85,18 +85,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
 	rm := cmd.Bool([]string{"#rm", "-rm"}, true, "Remove intermediate containers after a successful build")
 	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
 	forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers, even after unsuccessful builds")
 	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
 	pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	var (
 	var (
 		context  archive.Archive
 		context  archive.Archive
@@ -255,22 +248,18 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 // 'docker login': login / register a user to registry service.
 // 'docker login': login / register a user to registry service.
 func (cli *DockerCli) CmdLogin(args ...string) error {
 func (cli *DockerCli) CmdLogin(args ...string) error {
 	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
 	cmd := cli.Subcmd("login", "[SERVER]", "Register or log in to a Docker registry server, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
+	cmd.Require(flag.Max, 1)
 
 
 	var username, password, email string
 	var username, password, email string
 
 
 	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
 	cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
 	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
 	cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
 	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
 	cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 
-	err := cmd.Parse(args)
-	if err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
+
 	serverAddress := registry.IndexServerAddress()
 	serverAddress := registry.IndexServerAddress()
 	if len(cmd.Args()) > 0 {
 	if len(cmd.Args()) > 0 {
 		serverAddress = cmd.Arg(0)
 		serverAddress = cmd.Arg(0)
@@ -377,8 +366,9 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
 // log out from a Docker registry
 // log out from a Docker registry
 func (cli *DockerCli) CmdLogout(args ...string) error {
 func (cli *DockerCli) CmdLogout(args ...string) error {
 	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
 	cmd := cli.Subcmd("logout", "[SERVER]", "Log out from a Docker registry, if no server is specified \""+registry.IndexServerAddress()+"\" is the default.")
+	cmd.Require(flag.Max, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, false); err != nil {
 		return nil
 		return nil
 	}
 	}
 	serverAddress := registry.IndexServerAddress()
 	serverAddress := registry.IndexServerAddress()
@@ -403,18 +393,12 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
 // 'docker wait': block until a container stops
 // 'docker wait': block until a container stops
 func (cli *DockerCli) CmdWait(args ...string) error {
 func (cli *DockerCli) CmdWait(args ...string) error {
 	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
 	cmd := cli.Subcmd("wait", "CONTAINER [CONTAINER...]", "Block until a container stops, then print its exit code.")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
+
 	var encounteredError error
 	var encounteredError error
 	for _, name := range cmd.Args() {
 	for _, name := range cmd.Args() {
 		status, err := waitForExit(cli, name)
 		status, err := waitForExit(cli, name)
@@ -431,12 +415,12 @@ func (cli *DockerCli) CmdWait(args ...string) error {
 // 'docker version': show version information
 // 'docker version': show version information
 func (cli *DockerCli) CmdVersion(args ...string) error {
 func (cli *DockerCli) CmdVersion(args ...string) error {
 	cmd := cli.Subcmd("version", "", "Show the Docker version information.")
 	cmd := cli.Subcmd("version", "", "Show the Docker version information.")
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Exact, 0)
+
+	if err := utils.ParseFlags(cmd, args, false); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 0) {
-		os.Exit(1)
-	}
+
 	if dockerversion.VERSION != "" {
 	if dockerversion.VERSION != "" {
 		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
 		fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
 	}
 	}
@@ -475,12 +459,10 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
 // 'docker info': display system-wide information.
 // 'docker info': display system-wide information.
 func (cli *DockerCli) CmdInfo(args ...string) error {
 func (cli *DockerCli) CmdInfo(args ...string) error {
 	cmd := cli.Subcmd("info", "", "Display system-wide information")
 	cmd := cli.Subcmd("info", "", "Display system-wide information")
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Exact, 0)
+	if err := utils.ParseFlags(cmd, args, false); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 0) {
-		os.Exit(1)
-	}
 
 
 	body, _, err := readBody(cli.call("GET", "/info", nil, false))
 	body, _, err := readBody(cli.call("GET", "/info", nil, false))
 	if err != nil {
 	if err != nil {
@@ -594,18 +576,11 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
 func (cli *DockerCli) CmdStop(args ...string) error {
 func (cli *DockerCli) CmdStop(args ...string) error {
 	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
 	cmd := cli.Subcmd("stop", "CONTAINER [CONTAINER...]", "Stop a running container by sending SIGTERM and then SIGKILL after a grace period")
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
 	nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("t", strconv.Itoa(*nSeconds))
 	v.Set("t", strconv.Itoa(*nSeconds))
@@ -626,18 +601,11 @@ func (cli *DockerCli) CmdStop(args ...string) error {
 func (cli *DockerCli) CmdRestart(args ...string) error {
 func (cli *DockerCli) CmdRestart(args ...string) error {
 	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
 	cmd := cli.Subcmd("restart", "CONTAINER [CONTAINER...]", "Restart a running container")
 	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.")
 	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.")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("t", strconv.Itoa(*nSeconds))
 	v.Set("t", strconv.Itoa(*nSeconds))
@@ -689,19 +657,12 @@ func (cli *DockerCli) CmdStart(args ...string) error {
 		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
 		cmd       = cli.Subcmd("start", "CONTAINER [CONTAINER...]", "Restart a stopped container")
 		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
 		attach    = cmd.Bool([]string{"a", "-attach"}, false, "Attach container's STDOUT and STDERR and forward all signals to the process")
 		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
 		openStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
-		help      = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 	)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	cmd.Require(flag.Min, 1)
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	hijacked := make(chan io.Closer)
 	hijacked := make(chan io.Closer)
 
 
@@ -804,12 +765,10 @@ func (cli *DockerCli) CmdStart(args ...string) error {
 
 
 func (cli *DockerCli) CmdUnpause(args ...string) error {
 func (cli *DockerCli) CmdUnpause(args ...string) error {
 	cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container")
 	cmd := cli.Subcmd("unpause", "CONTAINER", "Unpause all processes within a container")
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Exact, 1)
+	if err := utils.ParseFlags(cmd, args, false); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	var encounteredError error
 	var encounteredError error
 	for _, name := range cmd.Args() {
 	for _, name := range cmd.Args() {
@@ -825,12 +784,10 @@ func (cli *DockerCli) CmdUnpause(args ...string) error {
 
 
 func (cli *DockerCli) CmdPause(args ...string) error {
 func (cli *DockerCli) CmdPause(args ...string) error {
 	cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container")
 	cmd := cli.Subcmd("pause", "CONTAINER", "Pause all processes within a container")
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Exact, 1)
+	if err := utils.ParseFlags(cmd, args, false); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	var encounteredError error
 	var encounteredError error
 	for _, name := range cmd.Args() {
 	for _, name := range cmd.Args() {
@@ -847,18 +804,11 @@ func (cli *DockerCli) CmdPause(args ...string) error {
 func (cli *DockerCli) CmdInspect(args ...string) error {
 func (cli *DockerCli) CmdInspect(args ...string) error {
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
 	cmd := cli.Subcmd("inspect", "CONTAINER|IMAGE [CONTAINER|IMAGE...]", "Return low-level information on a container or image")
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
 	tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template.")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	var tmpl *template.Template
 	var tmpl *template.Template
 	if *tmplStr != "" {
 	if *tmplStr != "" {
@@ -931,18 +881,12 @@ func (cli *DockerCli) CmdInspect(args ...string) error {
 
 
 func (cli *DockerCli) CmdTop(args ...string) error {
 func (cli *DockerCli) CmdTop(args ...string) error {
 	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
 	cmd := cli.Subcmd("top", "CONTAINER [ps OPTIONS]", "Display the running processes of a container")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
+
 	val := url.Values{}
 	val := url.Values{}
 	if cmd.NArg() > 1 {
 	if cmd.NArg() > 1 {
 		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
 		val.Set("ps_args", strings.Join(cmd.Args()[1:], " "))
@@ -971,17 +915,10 @@ func (cli *DockerCli) CmdTop(args ...string) error {
 
 
 func (cli *DockerCli) CmdPort(args ...string) error {
 func (cli *DockerCli) CmdPort(args ...string) error {
 	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")
 	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")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Min, 1)
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
 	stream, _, err := cli.call("GET", "/containers/"+cmd.Arg(0)+"/json", nil, false)
 	if err != nil {
 	if err != nil {
@@ -1034,18 +971,11 @@ func (cli *DockerCli) CmdRmi(args ...string) error {
 		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
 		force   = cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
 		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
 		noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
 	)
 	)
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	v := url.Values{}
 	v := url.Values{}
 	if *force {
 	if *force {
@@ -1084,18 +1014,11 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
 	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image")
 	cmd := cli.Subcmd("history", "IMAGE", "Show the history of an image")
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
 	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
 	body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, false))
 	if err != nil {
 	if err != nil {
@@ -1146,18 +1069,11 @@ func (cli *DockerCli) CmdRm(args ...string) error {
 	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
 	v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
 	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
 	link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
 	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
 	force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	val := url.Values{}
 	val := url.Values{}
 	if *v {
 	if *v {
@@ -1188,18 +1104,11 @@ func (cli *DockerCli) CmdRm(args ...string) error {
 func (cli *DockerCli) CmdKill(args ...string) error {
 func (cli *DockerCli) CmdKill(args ...string) error {
 	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
 	cmd := cli.Subcmd("kill", "CONTAINER [CONTAINER...]", "Kill a running container using SIGKILL or a specified signal")
 	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
 	signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	var encounteredError error
 	var encounteredError error
 	for _, name := range cmd.Args() {
 	for _, name := range cmd.Args() {
@@ -1215,18 +1124,12 @@ func (cli *DockerCli) CmdKill(args ...string) error {
 
 
 func (cli *DockerCli) CmdImport(args ...string) error {
 func (cli *DockerCli) CmdImport(args ...string) error {
 	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.")
 	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.")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
+
 	var (
 	var (
 		v          = url.Values{}
 		v          = url.Values{}
 		src        = cmd.Arg(0)
 		src        = cmd.Arg(0)
@@ -1260,18 +1163,12 @@ func (cli *DockerCli) CmdImport(args ...string) error {
 
 
 func (cli *DockerCli) CmdPush(args ...string) error {
 func (cli *DockerCli) CmdPush(args ...string) error {
 	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
 	cmd := cli.Subcmd("push", "NAME[:TAG]", "Push an image or a repository to the registry")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
+
 	name := cmd.Arg(0)
 	name := cmd.Arg(0)
 
 
 	cli.LoadConfigFile()
 	cli.LoadConfigFile()
@@ -1330,19 +1227,12 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 func (cli *DockerCli) CmdPull(args ...string) error {
 func (cli *DockerCli) CmdPull(args ...string) error {
 	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
 	cmd := cli.Subcmd("pull", "NAME[:TAG]", "Pull an image or a repository from the registry")
 	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
 	allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
 
 
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 	var (
 	var (
 		v         = url.Values{}
 		v         = url.Values{}
 		remote    = cmd.Arg(0)
 		remote    = cmd.Arg(0)
@@ -1406,21 +1296,14 @@ func (cli *DockerCli) CmdImages(args ...string) error {
 	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
 	// FIXME: --viz and --tree are deprecated. Remove them in a future version.
 	flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
 	flViz := cmd.Bool([]string{"#v", "#viz", "#-viz"}, false, "Output graph in graphviz format")
 	flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
 	flTree := cmd.Bool([]string{"#t", "#tree", "#-tree"}, false, "Output graph in tree format")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 
 
 	flFilter := opts.NewListOpts(nil)
 	flFilter := opts.NewListOpts(nil)
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
+	cmd.Require(flag.Max, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Max, 1) {
-		os.Exit(1)
-	}
 
 
 	// Consolidate all filter flags, and sanity check them early.
 	// Consolidate all filter flags, and sanity check them early.
 	// They'll get process in the daemon/server.
 	// They'll get process in the daemon/server.
@@ -1650,7 +1533,6 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
 		quiet    = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
 		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
 		size     = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
 		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
 		all      = cmd.Bool([]string{"a", "-all"}, false, "Show all containers. Only running containers are shown by default.")
-		help     = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
 		noTrunc  = cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
 		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
 		nLatest  = cmd.Bool([]string{"l", "-latest"}, false, "Show only the latest created container, include non-running ones.")
 		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
 		since    = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show only containers created since Id or Name, include non-running ones.")
@@ -1658,14 +1540,11 @@ func (cli *DockerCli) CmdPs(args ...string) error {
 		last     = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
 		last     = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running ones.")
 		flFilter = opts.NewListOpts(nil)
 		flFilter = opts.NewListOpts(nil)
 	)
 	)
+	cmd.Require(flag.Exact, 0)
 
 
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values. Valid filters:\nexited=<int> - containers with exit code of <int>\nstatus=(restarting|running|paused|exited)")
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
 	if *last == -1 && *nLatest {
 	if *last == -1 && *nLatest {
@@ -1808,22 +1687,11 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
 	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
 	flAuthor := cmd.String([]string{"a", "#author", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
 	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
 	// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
 	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")
 	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")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Max, 2)
+	cmd.Require(flag.Min, 1)
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-
-	if cmd.BadArgs(flag.Max, 2) {
-		os.Exit(1)
-	}
-
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	var (
 	var (
 		name            = cmd.Arg(0)
 		name            = cmd.Arg(0)
@@ -1876,18 +1744,11 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
 	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
 	until := cmd.String([]string{"-until"}, "", "Stream events until this timestamp")
 	flFilter := opts.NewListOpts(nil)
 	flFilter := opts.NewListOpts(nil)
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
 	cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'event=stop')")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 0)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 0) {
-		os.Exit(1)
-	}
 
 
 	var (
 	var (
 		v               = url.Values{}
 		v               = url.Values{}
@@ -1936,18 +1797,11 @@ func (cli *DockerCli) CmdEvents(args ...string) error {
 
 
 func (cli *DockerCli) CmdExport(args ...string) error {
 func (cli *DockerCli) CmdExport(args ...string) error {
 	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
 	cmd := cli.Subcmd("export", "CONTAINER", "Export the contents of a filesystem as a tar archive to STDOUT")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
 	if err := cli.stream("GET", "/containers/"+cmd.Arg(0)+"/export", nil, cli.out, nil); err != nil {
 		return err
 		return err
@@ -1957,18 +1811,11 @@ func (cli *DockerCli) CmdExport(args ...string) error {
 
 
 func (cli *DockerCli) CmdDiff(args ...string) error {
 func (cli *DockerCli) CmdDiff(args ...string) error {
 	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
 	cmd := cli.Subcmd("diff", "CONTAINER", "Inspect changes on a container's filesystem")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
 	body, _, err := readBody(cli.call("GET", "/containers/"+cmd.Arg(0)+"/changes", nil, false))
 
 
@@ -2001,20 +1848,13 @@ func (cli *DockerCli) CmdLogs(args ...string) error {
 		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
 		follow = cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
 		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
 		times  = cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
 		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
 		tail   = cmd.String([]string{"-tail"}, "all", "Output the specified number of lines at the end of logs (defaults to all logs)")
-		help   = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 	)
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
 
 
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 	name := cmd.Arg(0)
 	name := cmd.Arg(0)
 
 
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
@@ -2048,19 +1888,12 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
 		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container")
 		cmd     = cli.Subcmd("attach", "CONTAINER", "Attach to a running container")
 		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
 		noStdin = cmd.Bool([]string{"#nostdin", "-no-stdin"}, false, "Do not attach STDIN")
 		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.")
 		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.")
-		help    = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 	)
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 	name := cmd.Arg(0)
 	name := cmd.Arg(0)
 
 
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
 	stream, _, err := cli.call("GET", "/containers/"+name+"/json", nil, false)
@@ -2130,18 +1963,11 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
 	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
 	trusted := cmd.Bool([]string{"#t", "#trusted", "#-trusted"}, false, "Only show trusted builds")
 	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
 	automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
 	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
 	stars := cmd.Int([]string{"s", "#stars", "-stars"}, 0, "Only displays with at least x stars")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 1) {
-		os.Exit(1)
-	}
 
 
 	v := url.Values{}
 	v := url.Values{}
 	v.Set("term", cmd.Arg(0))
 	v.Set("term", cmd.Arg(0))
@@ -2187,18 +2013,11 @@ type ports []int
 func (cli *DockerCli) CmdTag(args ...string) error {
 func (cli *DockerCli) CmdTag(args ...string) error {
 	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
 	cmd := cli.Subcmd("tag", "IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]", "Tag an image into a repository")
 	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
 	force := cmd.Bool([]string{"f", "#force", "-force"}, false, "Force")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 2)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 2) {
-		os.Exit(1)
-	}
 
 
 	var (
 	var (
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
 		repository, tag = parsers.ParseRepositoryTag(cmd.Arg(1))
@@ -2588,18 +2407,11 @@ func (cli *DockerCli) CmdRun(args ...string) error {
 
 
 func (cli *DockerCli) CmdCp(args ...string) error {
 func (cli *DockerCli) CmdCp(args ...string) error {
 	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
 	cmd := cli.Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 2)
 
 
-	if err := cmd.Parse(args); err != nil {
-		return nil
-	}
-	if *help {
-		cmd.Usage()
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil
 		return nil
 	}
 	}
-	if cmd.BadArgs(flag.Exact, 2) {
-		os.Exit(1)
-	}
 
 
 	var copyData engine.Env
 	var copyData engine.Env
 	info := strings.Split(cmd.Arg(0), ":")
 	info := strings.Split(cmd.Arg(0), ":")
@@ -2632,21 +2444,13 @@ func (cli *DockerCli) CmdCp(args ...string) error {
 
 
 func (cli *DockerCli) CmdSave(args ...string) error {
 func (cli *DockerCli) CmdSave(args ...string) error {
 	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)")
 	cmd := cli.Subcmd("save", "IMAGE [IMAGE...]", "Save an image(s) to a tar archive (streamed to STDOUT by default)")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
 	outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
+	cmd.Require(flag.Min, 1)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
-
 	var (
 	var (
 		output io.Writer = cli.out
 		output io.Writer = cli.out
 		err    error
 		err    error
@@ -2680,18 +2484,11 @@ func (cli *DockerCli) CmdSave(args ...string) error {
 func (cli *DockerCli) CmdLoad(args ...string) error {
 func (cli *DockerCli) CmdLoad(args ...string) error {
 	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
 	cmd := cli.Subcmd("load", "", "Load an image from a tar archive on STDIN")
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
 	infile := cmd.String([]string{"i", "-input"}, "", "Read from a tar archive file, instead of STDIN")
-	help := cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	cmd.Require(flag.Exact, 0)
 
 
-	if err := cmd.Parse(args); err != nil {
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return err
 		return err
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil
-	}
-	if cmd.BadArgs(flag.Exact, 0) {
-		os.Exit(1)
-	}
 
 
 	var (
 	var (
 		input io.Reader = cli.in
 		input io.Reader = cli.in

+ 68 - 46
pkg/mflag/flag.go

@@ -284,13 +284,14 @@ type FlagSet struct {
 	// a custom error handler.
 	// a custom error handler.
 	Usage func()
 	Usage func()
 
 
-	name          string
-	parsed        bool
-	actual        map[string]*Flag
-	formal        map[string]*Flag
-	args          []string // arguments after flags
-	errorHandling ErrorHandling
-	output        io.Writer // nil means stderr; use out() accessor
+	name             string
+	parsed           bool
+	actual           map[string]*Flag
+	formal           map[string]*Flag
+	args             []string // arguments after flags
+	errorHandling    ErrorHandling
+	output           io.Writer // nil means stderr; use Out() accessor
+	nArgRequirements []nArgRequirement
 }
 }
 
 
 // A Flag represents the state of a flag.
 // A Flag represents the state of a flag.
@@ -348,7 +349,13 @@ func sortFlags(flags map[string]*Flag) []*Flag {
 	return result
 	return result
 }
 }
 
 
-func (f *FlagSet) out() io.Writer {
+// Name returns the name of the FlagSet.
+func (f *FlagSet) Name() string {
+	return f.name
+}
+
+// Out returns the destination for usage and error messages.
+func (f *FlagSet) Out() io.Writer {
 	if f.output == nil {
 	if f.output == nil {
 		return os.Stderr
 		return os.Stderr
 	}
 	}
@@ -410,45 +417,60 @@ func IsSet(name string) bool {
 	return CommandLine.IsSet(name)
 	return CommandLine.IsSet(name)
 }
 }
 
 
+type nArgRequirementType int
+
 // Indicator used to pass to BadArgs function
 // Indicator used to pass to BadArgs function
 const (
 const (
-	Exact = 1
-	Max   = 2
-	Min   = 3
+	Exact nArgRequirementType = iota
+	Max
+	Min
 )
 )
 
 
-// Bad Args takes two arguments.
-// The first one indicates whether the number of arguments should, be
-// A Minimal number of arguments, a maximum number of arguments or
-// The exact number of arguments required
-// If the actuall number of arguments is not valid and error message
-// prints and true is returned, otherwise false is returned
-func (f *FlagSet) BadArgs(arg_type, nargs int) bool {
-	if arg_type == Max && f.NArg() > nargs {
-		if nargs == 1 {
-			fmt.Fprintf(f.out(), "docker: '%s' requires a maximum of 1 argument. See 'docker %s --help'.\n", f.name, f.name)
+type nArgRequirement struct {
+	Type nArgRequirementType
+	N    int
+}
+
+// Require adds a requirement about the number of arguments for the FlagSet.
+// The first parameter can be Exact, Max, or Min to respectively specify the exact,
+// the maximum, or the minimal number of arguments required.
+// The actual check is done in FlagSet.CheckArgs().
+func (f *FlagSet) Require(nArgRequirementType nArgRequirementType, nArg int) {
+	f.nArgRequirements = append(f.nArgRequirements, nArgRequirement{nArgRequirementType, nArg})
+}
+
+// CheckArgs uses the requirements set by FlagSet.Require() to validate
+// the number of arguments. If the requirements are not met,
+// an error message string is returned.
+func (f *FlagSet) CheckArgs() (message string) {
+	for _, req := range f.nArgRequirements {
+		var arguments string
+		if req.N == 1 {
+			arguments = "1 argument"
 		} else {
 		} else {
-			fmt.Fprintf(f.out(), "docker: '%s' requires a maximum of %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
+			arguments = fmt.Sprintf("%d arguments", req.N)
 		}
 		}
-		return true
-	}
-	if arg_type == Exact && f.NArg() != nargs {
-		if nargs == 1 {
-			fmt.Fprintf(f.out(), "docker: '%s' requires 1 argument. See 'docker %s --help'.\n", f.name, f.name)
-		} else {
-			fmt.Fprintf(f.out(), "docker: '%s' requires %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
+
+		str := func(kind string) string {
+			return fmt.Sprintf("%q requires %s%s", f.name, kind, arguments)
 		}
 		}
-		return true
-	}
-	if arg_type == Min && f.NArg() < nargs {
-		if nargs == 1 {
-			fmt.Fprintf(f.out(), "docker: '%s' requires a minimum of 1 argument. See 'docker %s --help'.\n", f.name, f.name)
-		} else {
-			fmt.Fprintf(f.out(), "docker: '%s' requires a minimum of %d arguments. See 'docker %s --help'.\n", f.name, nargs, f.name)
+
+		switch req.Type {
+		case Exact:
+			if f.NArg() != req.N {
+				return str("")
+			}
+		case Max:
+			if f.NArg() > req.N {
+				return str("a maximum of ")
+			}
+		case Min:
+			if f.NArg() < req.N {
+				return str("a minimum of ")
+			}
 		}
 		}
-		return true
 	}
 	}
-	return false
+	return ""
 }
 }
 
 
 // Set sets the value of the named flag.
 // Set sets the value of the named flag.
@@ -476,7 +498,7 @@ func Set(name, value string) error {
 // PrintDefaults prints, to standard error unless configured
 // PrintDefaults prints, to standard error unless configured
 // otherwise, the default values of all defined flags in the set.
 // otherwise, the default values of all defined flags in the set.
 func (f *FlagSet) PrintDefaults() {
 func (f *FlagSet) PrintDefaults() {
-	writer := tabwriter.NewWriter(f.out(), 20, 1, 3, ' ', 0)
+	writer := tabwriter.NewWriter(f.Out(), 20, 1, 3, ' ', 0)
 	f.VisitAll(func(flag *Flag) {
 	f.VisitAll(func(flag *Flag) {
 		format := "  -%s=%s"
 		format := "  -%s=%s"
 		if _, ok := flag.Value.(*stringValue); ok {
 		if _, ok := flag.Value.(*stringValue); ok {
@@ -510,9 +532,9 @@ func PrintDefaults() {
 // defaultUsage is the default function to print a usage message.
 // defaultUsage is the default function to print a usage message.
 func defaultUsage(f *FlagSet) {
 func defaultUsage(f *FlagSet) {
 	if f.name == "" {
 	if f.name == "" {
-		fmt.Fprintf(f.out(), "Usage:\n")
+		fmt.Fprintf(f.Out(), "Usage:\n")
 	} else {
 	} else {
-		fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
+		fmt.Fprintf(f.Out(), "Usage of %s:\n", f.name)
 	}
 	}
 	f.PrintDefaults()
 	f.PrintDefaults()
 }
 }
@@ -805,7 +827,7 @@ func (f *FlagSet) Var(value Value, names []string, usage string) {
 			} else {
 			} else {
 				msg = fmt.Sprintf("%s flag redefined: %s", f.name, name)
 				msg = fmt.Sprintf("%s flag redefined: %s", f.name, name)
 			}
 			}
-			fmt.Fprintln(f.out(), msg)
+			fmt.Fprintln(f.Out(), msg)
 			panic(msg) // Happens only if flags are declared with identical names
 			panic(msg) // Happens only if flags are declared with identical names
 		}
 		}
 		if f.formal == nil {
 		if f.formal == nil {
@@ -829,8 +851,8 @@ func Var(value Value, names []string, usage string) {
 // returns the error.
 // returns the error.
 func (f *FlagSet) failf(format string, a ...interface{}) error {
 func (f *FlagSet) failf(format string, a ...interface{}) error {
 	err := fmt.Errorf(format, a...)
 	err := fmt.Errorf(format, a...)
-	fmt.Fprintln(f.out(), err)
-	fmt.Fprintf(f.out(), "See 'docker %s --help'.\n", f.name)
+	fmt.Fprintln(f.Out(), err)
+	fmt.Fprintf(f.Out(), "See 'docker %s --help'.\n", f.name)
 	return err
 	return err
 }
 }
 
 
@@ -956,9 +978,9 @@ func (f *FlagSet) parseOne() (bool, string, error) {
 				}
 				}
 			}
 			}
 			if replacement != "" {
 			if replacement != "" {
-				fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement)
+				fmt.Fprintf(f.Out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement)
 			} else {
 			} else {
-				fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name)
+				fmt.Fprintf(f.Out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name)
 			}
 			}
 		}
 		}
 	}
 	}

+ 3 - 10
runconfig/exec.go

@@ -5,7 +5,7 @@ import (
 
 
 	"github.com/docker/docker/engine"
 	"github.com/docker/docker/engine"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
-	"os"
+	"github.com/docker/docker/utils"
 )
 )
 
 
 type ExecConfig struct {
 type ExecConfig struct {
@@ -46,20 +46,13 @@ func ParseExec(cmd *flag.FlagSet, args []string) (*ExecConfig, error) {
 		flStdin   = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
 		flStdin   = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
 		flTty     = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
 		flTty     = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
 		flDetach  = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
 		flDetach  = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
-		help      = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 		execCmd   []string
 		execCmd   []string
 		container string
 		container string
 	)
 	)
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Min, 2)
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil, nil
-	}
-	if cmd.BadArgs(flag.Min, 2) {
-		os.Exit(1)
-	}
 	container = cmd.Arg(0)
 	container = cmd.Arg(0)
 	parsedArgs := cmd.Args()
 	parsedArgs := cmd.Args()
 	execCmd = parsedArgs[1:]
 	execCmd = parsedArgs[1:]

+ 3 - 10
runconfig/parse.go

@@ -2,7 +2,6 @@ package runconfig
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"os"
 	"path"
 	"path"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -62,7 +61,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 		flMacAddress      = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
 		flMacAddress      = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
 		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.")
 		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.")
 		flRestartPolicy   = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
 		flRestartPolicy   = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
-		help              = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
 	)
 	)
 
 
 	cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
 	cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
@@ -85,16 +83,11 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 	cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
 	cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capabilities")
 	cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options")
 	cmd.Var(&flSecurityOpt, []string{"-security-opt"}, "Security Options")
 
 
-	if err := cmd.Parse(args); err != nil {
+	cmd.Require(flag.Min, 1)
+
+	if err := utils.ParseFlags(cmd, args, true); err != nil {
 		return nil, nil, cmd, err
 		return nil, nil, cmd, err
 	}
 	}
-	if *help {
-		cmd.Usage()
-		return nil, nil, cmd, nil
-	}
-	if cmd.BadArgs(flag.Min, 1) {
-		os.Exit(1)
-	}
 
 
 	// Validate input params
 	// Validate input params
 	if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
 	if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {

+ 34 - 0
utils/flags.go

@@ -0,0 +1,34 @@
+package utils
+
+import (
+	"fmt"
+	"os"
+
+	flag "github.com/docker/docker/pkg/mflag"
+)
+
+// ParseFlags is a utility function that adds a help flag if withHelp is true,
+// calls cmd.Parse(args) and prints a relevant error message if there are incorrect number of arguments.
+// TODO: move this to a better package than utils
+func ParseFlags(cmd *flag.FlagSet, args []string, withHelp bool) error {
+	var help *bool
+	if withHelp {
+		help = cmd.Bool([]string{"#help", "-help"}, false, "Print usage")
+	}
+	if err := cmd.Parse(args); err != nil {
+		return err
+	}
+	if help != nil && *help {
+		cmd.Usage()
+		// just in case Usage does not exit
+		os.Exit(0)
+	}
+	if str := cmd.CheckArgs(); str != "" {
+		if withHelp {
+			str += ". See 'docker " + cmd.Name() + " --help'"
+		}
+		fmt.Fprintf(cmd.Out(), "docker: %s.\n", str)
+		os.Exit(1)
+	}
+	return nil
+}