Browse Source

Merge pull request #4024 from heyitsanthony/add-command-argusage

etcdctl: member add command argusage to help
Xiang Li 10 years ago
parent
commit
2a351e62f1
35 changed files with 795 additions and 1556 deletions
  1. 2 2
      Godeps/Godeps.json
  2. 14 1
      Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
  3. 75 21
      Godeps/_workspace/src/github.com/codegangsta/cli/README.md
  4. 121 34
      Godeps/_workspace/src/github.com/codegangsta/cli/app.go
  5. 0 423
      Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
  6. 4 3
      Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
  7. 21 0
      Godeps/_workspace/src/github.com/codegangsta/cli/cli.go
  8. 0 100
      Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
  9. 96 24
      Godeps/_workspace/src/github.com/codegangsta/cli/command.go
  10. 0 49
      Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
  11. 88 15
      Godeps/_workspace/src/github.com/codegangsta/cli/context.go
  12. 0 77
      Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
  13. 184 67
      Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
  14. 0 587
      Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go
  15. 69 47
      Godeps/_workspace/src/github.com/codegangsta/cli/help.go
  16. 0 19
      Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go
  17. 8 6
      etcdctl/command/auth_commands.go
  18. 3 2
      etcdctl/command/backup_command.go
  19. 3 2
      etcdctl/command/cluster_health.go
  20. 3 2
      etcdctl/command/exec_watch_command.go
  21. 3 2
      etcdctl/command/get_command.go
  22. 3 2
      etcdctl/command/import_snap_command.go
  23. 3 2
      etcdctl/command/ls_command.go
  24. 16 12
      etcdctl/command/member_commands.go
  25. 3 2
      etcdctl/command/mk_command.go
  26. 3 2
      etcdctl/command/mkdir_command.go
  27. 3 2
      etcdctl/command/rm_command.go
  28. 3 2
      etcdctl/command/rmdir_command.go
  29. 22 16
      etcdctl/command/role_commands.go
  30. 3 2
      etcdctl/command/set_command.go
  31. 3 2
      etcdctl/command/set_dir_command.go
  32. 3 2
      etcdctl/command/update_command.go
  33. 3 2
      etcdctl/command/update_dir_command.go
  34. 30 23
      etcdctl/command/user_commands.go
  35. 3 2
      etcdctl/command/watch_command.go

+ 2 - 2
Godeps/Godeps.json

@@ -37,8 +37,8 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/codegangsta/cli",
 			"ImportPath": "github.com/codegangsta/cli",
-			"Comment": "1.2.0-26-gf7ebb76",
-			"Rev": "f7ebb761e83e21225d1d8954fde853bf8edd46c4"
+			"Comment": "1.2.0-183-gb5232bb",
+			"Rev": "b5232bb2934f606f9f27a1305f1eea224e8e8b88"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/coreos/go-semver/semver",
 			"ImportPath": "github.com/coreos/go-semver/semver",

+ 14 - 1
Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml

@@ -1,5 +1,18 @@
 language: go
 language: go
-go: 1.1
+sudo: false
+
+go:
+- 1.0.3
+- 1.1.2
+- 1.2.2
+- 1.3.3
+- 1.4.2
+- 1.5.1
+- tip
+
+matrix:
+  allow_failures:
+    - go: tip
 
 
 script:
 script:
 - go vet ./...
 - go vet ./...

+ 75 - 21
Godeps/_workspace/src/github.com/codegangsta/cli/README.md

@@ -1,18 +1,17 @@
+[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli)
 [![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
 [![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
+[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli)
 
 
 # cli.go
 # cli.go
-cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
-
-You can view the API docs here:
-http://godoc.org/github.com/codegangsta/cli
+`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
 
 
 ## Overview
 ## Overview
 Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
 Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
 
 
-**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive!
+**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive!
 
 
 ## Installation
 ## Installation
-Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html).
+Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html).
 
 
 To install `cli.go`, simply run:
 To install `cli.go`, simply run:
 ```
 ```
@@ -25,7 +24,7 @@ export PATH=$PATH:$GOPATH/bin
 ```
 ```
 
 
 ## Getting Started
 ## Getting Started
-One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`. 
+One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`. 
 
 
 ``` go
 ``` go
 package main
 package main
@@ -68,8 +67,9 @@ Running this already gives you a ton of functionality, plus support for things l
 
 
 Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
 Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
 
 
+Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it:
+
 ``` go
 ``` go
-/* greet.go */
 package main
 package main
 
 
 import (
 import (
@@ -84,7 +84,7 @@ func main() {
   app.Action = func(c *cli.Context) {
   app.Action = func(c *cli.Context) {
     println("Hello friend!")
     println("Hello friend!")
   }
   }
-  
+
   app.Run(os.Args)
   app.Run(os.Args)
 }
 }
 ```
 ```
@@ -102,7 +102,8 @@ $ greet
 Hello friend!
 Hello friend!
 ```
 ```
 
 
-cli.go also generates some bitchass help text:
+`cli.go` also generates neat help text:
+
 ```
 ```
 $ greet help
 $ greet help
 NAME:
 NAME:
@@ -157,6 +158,34 @@ app.Action = func(c *cli.Context) {
 ...
 ...
 ```
 ```
 
 
+You can also set a destination variable for a flag, to which the content will be scanned.
+``` go
+...
+var language string
+app.Flags = []cli.Flag {
+  cli.StringFlag{
+    Name:        "lang",
+    Value:       "english",
+    Usage:       "language for the greeting",
+    Destination: &language,
+  },
+}
+app.Action = func(c *cli.Context) {
+  name := "someone"
+  if len(c.Args()) > 0 {
+    name = c.Args()[0]
+  }
+  if language == "spanish" {
+    println("Hola", name)
+  } else {
+    println("Hello", name)
+  }
+}
+...
+```
+
+See full list of flags at http://godoc.org/github.com/codegangsta/cli
+
 #### Alternate Names
 #### Alternate Names
 
 
 You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
 You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
@@ -171,6 +200,8 @@ app.Flags = []cli.Flag {
 }
 }
 ```
 ```
 
 
+That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
+
 #### Values from the Environment
 #### Values from the Environment
 
 
 You can also have the default value set from the environment via `EnvVar`.  e.g.
 You can also have the default value set from the environment via `EnvVar`.  e.g.
@@ -186,7 +217,18 @@ app.Flags = []cli.Flag {
 }
 }
 ```
 ```
 
 
-That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
+The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
+
+``` go
+app.Flags = []cli.Flag {
+  cli.StringFlag{
+    Name: "lang, l",
+    Value: "english",
+    Usage: "language for the greeting",
+    EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
+  },
+}
+```
 
 
 ### Subcommands
 ### Subcommands
 
 
@@ -196,7 +238,7 @@ Subcommands can be defined for a more git-like command line app.
 app.Commands = []cli.Command{
 app.Commands = []cli.Command{
   {
   {
     Name:      "add",
     Name:      "add",
-    ShortName: "a",
+    Aliases:     []string{"a"},
     Usage:     "add a task to the list",
     Usage:     "add a task to the list",
     Action: func(c *cli.Context) {
     Action: func(c *cli.Context) {
       println("added task: ", c.Args().First())
       println("added task: ", c.Args().First())
@@ -204,7 +246,7 @@ app.Commands = []cli.Command{
   },
   },
   {
   {
     Name:      "complete",
     Name:      "complete",
-    ShortName: "c",
+    Aliases:     []string{"c"},
     Usage:     "complete a task on the list",
     Usage:     "complete a task on the list",
     Action: func(c *cli.Context) {
     Action: func(c *cli.Context) {
       println("completed task: ", c.Args().First())
       println("completed task: ", c.Args().First())
@@ -212,7 +254,7 @@ app.Commands = []cli.Command{
   },
   },
   {
   {
     Name:      "template",
     Name:      "template",
-    ShortName: "r",
+    Aliases:     []string{"r"},
     Usage:     "options for task templates",
     Usage:     "options for task templates",
     Subcommands: []cli.Command{
     Subcommands: []cli.Command{
       {
       {
@@ -230,7 +272,7 @@ app.Commands = []cli.Command{
         },
         },
       },
       },
     },
     },
-  },     
+  },
 }
 }
 ...
 ...
 ```
 ```
@@ -248,8 +290,8 @@ app := cli.NewApp()
 app.EnableBashCompletion = true
 app.EnableBashCompletion = true
 app.Commands = []cli.Command{
 app.Commands = []cli.Command{
   {
   {
-    Name: "complete",
-    ShortName: "c",
+    Name:  "complete",
+    Aliases: []string{"c"},
     Usage: "complete a task on the list",
     Usage: "complete a task on the list",
     Action: func(c *cli.Context) {
     Action: func(c *cli.Context) {
        println("completed task: ", c.Args().First())
        println("completed task: ", c.Args().First())
@@ -275,13 +317,25 @@ setting the `PROG` variable to the name of your program:
 
 
 `PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
 `PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
 
 
+#### To Distribute
+
+Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
+it to the name of the program you wish to add autocomplete support for (or
+automatically install it there if you are distributing a package). Don't forget
+to source the file to make it active in the current shell.
+
+```
+   sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
+   source /etc/bash_completion.d/<myprogram>
+```
+
+Alternatively, you can just document that users should source the generic
+`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
+to the name of their program (as above).
 
 
 ## Contribution Guidelines
 ## Contribution Guidelines
 Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
 Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
 
 
-If you are have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
+If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
 
 
 If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
 If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
-
-## About
-cli.go is written by none other than the [Code Gangsta](http://codegangsta.io)

+ 121 - 34
Godeps/_workspace/src/github.com/codegangsta/cli/app.go

@@ -2,18 +2,23 @@ package cli
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"time"
 	"time"
 )
 )
 
 
 // App is the main structure of a cli application. It is recomended that
 // App is the main structure of a cli application. It is recomended that
-// and app be created with the cli.NewApp() function
+// an app be created with the cli.NewApp() function
 type App struct {
 type App struct {
 	// The name of the program. Defaults to os.Args[0]
 	// The name of the program. Defaults to os.Args[0]
 	Name string
 	Name string
+	// Full name of command for help, defaults to Name
+	HelpName string
 	// Description of the program.
 	// Description of the program.
 	Usage string
 	Usage string
+	// Description of the program argument format.
+	ArgsUsage string
 	// Version of the program
 	// Version of the program
 	Version string
 	Version string
 	// List of commands to execute
 	// List of commands to execute
@@ -24,21 +29,32 @@ type App struct {
 	EnableBashCompletion bool
 	EnableBashCompletion bool
 	// Boolean to hide built-in help command
 	// Boolean to hide built-in help command
 	HideHelp bool
 	HideHelp bool
+	// Boolean to hide built-in version flag
+	HideVersion bool
 	// An action to execute when the bash-completion flag is set
 	// An action to execute when the bash-completion flag is set
 	BashComplete func(context *Context)
 	BashComplete func(context *Context)
 	// An action to execute before any subcommands are run, but after the context is ready
 	// An action to execute before any subcommands are run, but after the context is ready
 	// If a non-nil error is returned, no subcommands are run
 	// If a non-nil error is returned, no subcommands are run
 	Before func(context *Context) error
 	Before func(context *Context) error
+	// An action to execute after any subcommands are run, but after the subcommand has finished
+	// It is run even if Action() panics
+	After func(context *Context) error
 	// The action to execute when no subcommands are specified
 	// The action to execute when no subcommands are specified
 	Action func(context *Context)
 	Action func(context *Context)
 	// Execute this function if the proper command cannot be found
 	// Execute this function if the proper command cannot be found
 	CommandNotFound func(context *Context, command string)
 	CommandNotFound func(context *Context, command string)
 	// Compilation date
 	// Compilation date
 	Compiled time.Time
 	Compiled time.Time
-	// Author
+	// List of all authors who contributed
+	Authors []Author
+	// Copyright of the binary if any
+	Copyright string
+	// Name of Author (Note: Use App.Authors, this is deprecated)
 	Author string
 	Author string
-	// Author e-mail
+	// Email of Author (Note: Use App.Authors, this is deprecated)
 	Email string
 	Email string
+	// Writer writer to write output to
+	Writer io.Writer
 }
 }
 
 
 // Tries to find out when this binary was compiled.
 // Tries to find out when this binary was compiled.
@@ -55,59 +71,93 @@ func compileTime() time.Time {
 func NewApp() *App {
 func NewApp() *App {
 	return &App{
 	return &App{
 		Name:         os.Args[0],
 		Name:         os.Args[0],
+		HelpName:     os.Args[0],
 		Usage:        "A new cli application",
 		Usage:        "A new cli application",
 		Version:      "0.0.0",
 		Version:      "0.0.0",
 		BashComplete: DefaultAppComplete,
 		BashComplete: DefaultAppComplete,
 		Action:       helpCommand.Action,
 		Action:       helpCommand.Action,
 		Compiled:     compileTime(),
 		Compiled:     compileTime(),
+		Writer:       os.Stdout,
 	}
 	}
 }
 }
 
 
 // Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
 // Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
-func (a *App) Run(arguments []string) error {
+func (a *App) Run(arguments []string) (err error) {
+	if a.Author != "" || a.Email != "" {
+		a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
+	}
+
+	newCmds := []Command{}
+	for _, c := range a.Commands {
+		if c.HelpName == "" {
+			c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
+		}
+		newCmds = append(newCmds, c)
+	}
+	a.Commands = newCmds
+
 	// append help to commands
 	// append help to commands
 	if a.Command(helpCommand.Name) == nil && !a.HideHelp {
 	if a.Command(helpCommand.Name) == nil && !a.HideHelp {
 		a.Commands = append(a.Commands, helpCommand)
 		a.Commands = append(a.Commands, helpCommand)
-		a.appendFlag(HelpFlag)
+		if (HelpFlag != BoolFlag{}) {
+			a.appendFlag(HelpFlag)
+		}
 	}
 	}
 
 
 	//append version/help flags
 	//append version/help flags
 	if a.EnableBashCompletion {
 	if a.EnableBashCompletion {
 		a.appendFlag(BashCompletionFlag)
 		a.appendFlag(BashCompletionFlag)
 	}
 	}
-	a.appendFlag(VersionFlag)
+
+	if !a.HideVersion {
+		a.appendFlag(VersionFlag)
+	}
 
 
 	// parse flags
 	// parse flags
 	set := flagSet(a.Name, a.Flags)
 	set := flagSet(a.Name, a.Flags)
 	set.SetOutput(ioutil.Discard)
 	set.SetOutput(ioutil.Discard)
-	err := set.Parse(arguments[1:])
+	err = set.Parse(arguments[1:])
 	nerr := normalizeFlags(a.Flags, set)
 	nerr := normalizeFlags(a.Flags, set)
 	if nerr != nil {
 	if nerr != nil {
-		fmt.Println(nerr)
-		context := NewContext(a, set, set)
+		fmt.Fprintln(a.Writer, nerr)
+		context := NewContext(a, set, nil)
 		ShowAppHelp(context)
 		ShowAppHelp(context)
-		fmt.Println("")
 		return nerr
 		return nerr
 	}
 	}
-	context := NewContext(a, set, set)
+	context := NewContext(a, set, nil)
+
+	if checkCompletions(context) {
+		return nil
+	}
 
 
 	if err != nil {
 	if err != nil {
-		fmt.Printf("Incorrect Usage.\n\n")
+		fmt.Fprintln(a.Writer, "Incorrect Usage.")
+		fmt.Fprintln(a.Writer)
 		ShowAppHelp(context)
 		ShowAppHelp(context)
-		fmt.Println("")
 		return err
 		return err
 	}
 	}
 
 
-	if checkCompletions(context) {
+	if !a.HideHelp && checkHelp(context) {
+		ShowAppHelp(context)
 		return nil
 		return nil
 	}
 	}
 
 
-	if checkHelp(context) {
+	if !a.HideVersion && checkVersion(context) {
+		ShowVersion(context)
 		return nil
 		return nil
 	}
 	}
 
 
-	if checkVersion(context) {
-		return nil
+	if a.After != nil {
+		defer func() {
+			afterErr := a.After(context)
+			if afterErr != nil {
+				if err != nil {
+					err = NewMultiError(err, afterErr)
+				} else {
+					err = afterErr
+				}
+			}
+		}()
 	}
 	}
 
 
 	if a.Before != nil {
 	if a.Before != nil {
@@ -134,20 +184,31 @@ func (a *App) Run(arguments []string) error {
 // Another entry point to the cli app, takes care of passing arguments and error handling
 // Another entry point to the cli app, takes care of passing arguments and error handling
 func (a *App) RunAndExitOnError() {
 func (a *App) RunAndExitOnError() {
 	if err := a.Run(os.Args); err != nil {
 	if err := a.Run(os.Args); err != nil {
-		os.Stderr.WriteString(fmt.Sprintln(err))
+		fmt.Fprintln(os.Stderr, err)
 		os.Exit(1)
 		os.Exit(1)
 	}
 	}
 }
 }
 
 
 // Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
 // Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
-func (a *App) RunAsSubcommand(ctx *Context) error {
+func (a *App) RunAsSubcommand(ctx *Context) (err error) {
 	// append help to commands
 	// append help to commands
 	if len(a.Commands) > 0 {
 	if len(a.Commands) > 0 {
 		if a.Command(helpCommand.Name) == nil && !a.HideHelp {
 		if a.Command(helpCommand.Name) == nil && !a.HideHelp {
 			a.Commands = append(a.Commands, helpCommand)
 			a.Commands = append(a.Commands, helpCommand)
-			a.appendFlag(HelpFlag)
+			if (HelpFlag != BoolFlag{}) {
+				a.appendFlag(HelpFlag)
+			}
+		}
+	}
+
+	newCmds := []Command{}
+	for _, c := range a.Commands {
+		if c.HelpName == "" {
+			c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
 		}
 		}
+		newCmds = append(newCmds, c)
 	}
 	}
+	a.Commands = newCmds
 
 
 	// append flags
 	// append flags
 	if a.EnableBashCompletion {
 	if a.EnableBashCompletion {
@@ -157,31 +218,32 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
 	// parse flags
 	// parse flags
 	set := flagSet(a.Name, a.Flags)
 	set := flagSet(a.Name, a.Flags)
 	set.SetOutput(ioutil.Discard)
 	set.SetOutput(ioutil.Discard)
-	err := set.Parse(ctx.Args().Tail())
+	err = set.Parse(ctx.Args().Tail())
 	nerr := normalizeFlags(a.Flags, set)
 	nerr := normalizeFlags(a.Flags, set)
-	context := NewContext(a, set, ctx.globalSet)
+	context := NewContext(a, set, ctx)
 
 
 	if nerr != nil {
 	if nerr != nil {
-		fmt.Println(nerr)
+		fmt.Fprintln(a.Writer, nerr)
+		fmt.Fprintln(a.Writer)
 		if len(a.Commands) > 0 {
 		if len(a.Commands) > 0 {
 			ShowSubcommandHelp(context)
 			ShowSubcommandHelp(context)
 		} else {
 		} else {
 			ShowCommandHelp(ctx, context.Args().First())
 			ShowCommandHelp(ctx, context.Args().First())
 		}
 		}
-		fmt.Println("")
 		return nerr
 		return nerr
 	}
 	}
 
 
+	if checkCompletions(context) {
+		return nil
+	}
+
 	if err != nil {
 	if err != nil {
-		fmt.Printf("Incorrect Usage.\n\n")
+		fmt.Fprintln(a.Writer, "Incorrect Usage.")
+		fmt.Fprintln(a.Writer)
 		ShowSubcommandHelp(context)
 		ShowSubcommandHelp(context)
 		return err
 		return err
 	}
 	}
 
 
-	if checkCompletions(context) {
-		return nil
-	}
-
 	if len(a.Commands) > 0 {
 	if len(a.Commands) > 0 {
 		if checkSubcommandHelp(context) {
 		if checkSubcommandHelp(context) {
 			return nil
 			return nil
@@ -192,6 +254,19 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
 		}
 		}
 	}
 	}
 
 
+	if a.After != nil {
+		defer func() {
+			afterErr := a.After(context)
+			if afterErr != nil {
+				if err != nil {
+					err = NewMultiError(err, afterErr)
+				} else {
+					err = afterErr
+				}
+			}
+		}()
+	}
+
 	if a.Before != nil {
 	if a.Before != nil {
 		err := a.Before(context)
 		err := a.Before(context)
 		if err != nil {
 		if err != nil {
@@ -209,11 +284,7 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
 	}
 	}
 
 
 	// Run default Action
 	// Run default Action
-	if len(a.Commands) > 0 {
-		a.Action(context)
-	} else {
-		a.Action(ctx)
-	}
+	a.Action(context)
 
 
 	return nil
 	return nil
 }
 }
@@ -244,3 +315,19 @@ func (a *App) appendFlag(flag Flag) {
 		a.Flags = append(a.Flags, flag)
 		a.Flags = append(a.Flags, flag)
 	}
 	}
 }
 }
+
+// Author represents someone who has contributed to a cli project.
+type Author struct {
+	Name  string // The Authors name
+	Email string // The Authors email
+}
+
+// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
+func (a Author) String() string {
+	e := ""
+	if a.Email != "" {
+		e = "<" + a.Email + "> "
+	}
+
+	return fmt.Sprintf("%v %v", a.Name, e)
+}

+ 0 - 423
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go

@@ -1,423 +0,0 @@
-package cli_test
-
-import (
-	"fmt"
-	"os"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
-)
-
-func ExampleApp() {
-	// set args for examples sake
-	os.Args = []string{"greet", "--name", "Jeremy"}
-
-	app := cli.NewApp()
-	app.Name = "greet"
-	app.Flags = []cli.Flag{
-		cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
-	}
-	app.Action = func(c *cli.Context) {
-		fmt.Printf("Hello %v\n", c.String("name"))
-	}
-	app.Run(os.Args)
-	// Output:
-	// Hello Jeremy
-}
-
-func ExampleAppSubcommand() {
-	// set args for examples sake
-	os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
-	app := cli.NewApp()
-	app.Name = "say"
-	app.Commands = []cli.Command{
-		{
-			Name:        "hello",
-			ShortName:   "hi",
-			Usage:       "use it to see a description",
-			Description: "This is how we describe hello the function",
-			Subcommands: []cli.Command{
-				{
-					Name:        "english",
-					ShortName:   "en",
-					Usage:       "sends a greeting in english",
-					Description: "greets someone in english",
-					Flags: []cli.Flag{
-						cli.StringFlag{
-							Name:  "name",
-							Value: "Bob",
-							Usage: "Name of the person to greet",
-						},
-					},
-					Action: func(c *cli.Context) {
-						fmt.Println("Hello,", c.String("name"))
-					},
-				},
-			},
-		},
-	}
-
-	app.Run(os.Args)
-	// Output:
-	// Hello, Jeremy
-}
-
-func ExampleAppHelp() {
-	// set args for examples sake
-	os.Args = []string{"greet", "h", "describeit"}
-
-	app := cli.NewApp()
-	app.Name = "greet"
-	app.Flags = []cli.Flag{
-		cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
-	}
-	app.Commands = []cli.Command{
-		{
-			Name:        "describeit",
-			ShortName:   "d",
-			Usage:       "use it to see a description",
-			Description: "This is how we describe describeit the function",
-			Action: func(c *cli.Context) {
-				fmt.Printf("i like to describe things")
-			},
-		},
-	}
-	app.Run(os.Args)
-	// Output:
-	// NAME:
-	//    describeit - use it to see a description
-	//
-	// USAGE:
-	//    command describeit [arguments...]
-	//
-	// DESCRIPTION:
-	//    This is how we describe describeit the function
-}
-
-func ExampleAppBashComplete() {
-	// set args for examples sake
-	os.Args = []string{"greet", "--generate-bash-completion"}
-
-	app := cli.NewApp()
-	app.Name = "greet"
-	app.EnableBashCompletion = true
-	app.Commands = []cli.Command{
-		{
-			Name:        "describeit",
-			ShortName:   "d",
-			Usage:       "use it to see a description",
-			Description: "This is how we describe describeit the function",
-			Action: func(c *cli.Context) {
-				fmt.Printf("i like to describe things")
-			},
-		}, {
-			Name:        "next",
-			Usage:       "next example",
-			Description: "more stuff to see when generating bash completion",
-			Action: func(c *cli.Context) {
-				fmt.Printf("the next example")
-			},
-		},
-	}
-
-	app.Run(os.Args)
-	// Output:
-	// describeit
-	// d
-	// next
-	// help
-	// h
-}
-
-func TestApp_Run(t *testing.T) {
-	s := ""
-
-	app := cli.NewApp()
-	app.Action = func(c *cli.Context) {
-		s = s + c.Args().First()
-	}
-
-	err := app.Run([]string{"command", "foo"})
-	expect(t, err, nil)
-	err = app.Run([]string{"command", "bar"})
-	expect(t, err, nil)
-	expect(t, s, "foobar")
-}
-
-var commandAppTests = []struct {
-	name     string
-	expected bool
-}{
-	{"foobar", true},
-	{"batbaz", true},
-	{"b", true},
-	{"f", true},
-	{"bat", false},
-	{"nothing", false},
-}
-
-func TestApp_Command(t *testing.T) {
-	app := cli.NewApp()
-	fooCommand := cli.Command{Name: "foobar", ShortName: "f"}
-	batCommand := cli.Command{Name: "batbaz", ShortName: "b"}
-	app.Commands = []cli.Command{
-		fooCommand,
-		batCommand,
-	}
-
-	for _, test := range commandAppTests {
-		expect(t, app.Command(test.name) != nil, test.expected)
-	}
-}
-
-func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
-	var parsedOption, firstArg string
-
-	app := cli.NewApp()
-	command := cli.Command{
-		Name: "cmd",
-		Flags: []cli.Flag{
-			cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
-		},
-		Action: func(c *cli.Context) {
-			parsedOption = c.String("option")
-			firstArg = c.Args().First()
-		},
-	}
-	app.Commands = []cli.Command{command}
-
-	app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
-
-	expect(t, parsedOption, "my-option")
-	expect(t, firstArg, "my-arg")
-}
-
-func TestApp_Float64Flag(t *testing.T) {
-	var meters float64
-
-	app := cli.NewApp()
-	app.Flags = []cli.Flag{
-		cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
-	}
-	app.Action = func(c *cli.Context) {
-		meters = c.Float64("height")
-	}
-
-	app.Run([]string{"", "--height", "1.93"})
-	expect(t, meters, 1.93)
-}
-
-func TestApp_ParseSliceFlags(t *testing.T) {
-	var parsedOption, firstArg string
-	var parsedIntSlice []int
-	var parsedStringSlice []string
-
-	app := cli.NewApp()
-	command := cli.Command{
-		Name: "cmd",
-		Flags: []cli.Flag{
-			cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
-			cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
-		},
-		Action: func(c *cli.Context) {
-			parsedIntSlice = c.IntSlice("p")
-			parsedStringSlice = c.StringSlice("ip")
-			parsedOption = c.String("option")
-			firstArg = c.Args().First()
-		},
-	}
-	app.Commands = []cli.Command{command}
-
-	app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
-
-	IntsEquals := func(a, b []int) bool {
-		if len(a) != len(b) {
-			return false
-		}
-		for i, v := range a {
-			if v != b[i] {
-				return false
-			}
-		}
-		return true
-	}
-
-	StrsEquals := func(a, b []string) bool {
-		if len(a) != len(b) {
-			return false
-		}
-		for i, v := range a {
-			if v != b[i] {
-				return false
-			}
-		}
-		return true
-	}
-	var expectedIntSlice = []int{22, 80}
-	var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
-
-	if !IntsEquals(parsedIntSlice, expectedIntSlice) {
-		t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
-	}
-
-	if !StrsEquals(parsedStringSlice, expectedStringSlice) {
-		t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
-	}
-}
-
-func TestApp_BeforeFunc(t *testing.T) {
-	beforeRun, subcommandRun := false, false
-	beforeError := fmt.Errorf("fail")
-	var err error
-
-	app := cli.NewApp()
-
-	app.Before = func(c *cli.Context) error {
-		beforeRun = true
-		s := c.String("opt")
-		if s == "fail" {
-			return beforeError
-		}
-
-		return nil
-	}
-
-	app.Commands = []cli.Command{
-		cli.Command{
-			Name: "sub",
-			Action: func(c *cli.Context) {
-				subcommandRun = true
-			},
-		},
-	}
-
-	app.Flags = []cli.Flag{
-		cli.StringFlag{Name: "opt"},
-	}
-
-	// run with the Before() func succeeding
-	err = app.Run([]string{"command", "--opt", "succeed", "sub"})
-
-	if err != nil {
-		t.Fatalf("Run error: %s", err)
-	}
-
-	if beforeRun == false {
-		t.Errorf("Before() not executed when expected")
-	}
-
-	if subcommandRun == false {
-		t.Errorf("Subcommand not executed when expected")
-	}
-
-	// reset
-	beforeRun, subcommandRun = false, false
-
-	// run with the Before() func failing
-	err = app.Run([]string{"command", "--opt", "fail", "sub"})
-
-	// should be the same error produced by the Before func
-	if err != beforeError {
-		t.Errorf("Run error expected, but not received")
-	}
-
-	if beforeRun == false {
-		t.Errorf("Before() not executed when expected")
-	}
-
-	if subcommandRun == true {
-		t.Errorf("Subcommand executed when NOT expected")
-	}
-
-}
-
-func TestAppHelpPrinter(t *testing.T) {
-	oldPrinter := cli.HelpPrinter
-	defer func() {
-		cli.HelpPrinter = oldPrinter
-	}()
-
-	var wasCalled = false
-	cli.HelpPrinter = func(template string, data interface{}) {
-		wasCalled = true
-	}
-
-	app := cli.NewApp()
-	app.Run([]string{"-h"})
-
-	if wasCalled == false {
-		t.Errorf("Help printer expected to be called, but was not")
-	}
-}
-
-func TestAppVersionPrinter(t *testing.T) {
-	oldPrinter := cli.VersionPrinter
-	defer func() {
-		cli.VersionPrinter = oldPrinter
-	}()
-
-	var wasCalled = false
-	cli.VersionPrinter = func(c *cli.Context) {
-		wasCalled = true
-	}
-
-	app := cli.NewApp()
-	ctx := cli.NewContext(app, nil, nil)
-	cli.ShowVersion(ctx)
-
-	if wasCalled == false {
-		t.Errorf("Version printer expected to be called, but was not")
-	}
-}
-
-func TestAppCommandNotFound(t *testing.T) {
-	beforeRun, subcommandRun := false, false
-	app := cli.NewApp()
-
-	app.CommandNotFound = func(c *cli.Context, command string) {
-		beforeRun = true
-	}
-
-	app.Commands = []cli.Command{
-		cli.Command{
-			Name: "bar",
-			Action: func(c *cli.Context) {
-				subcommandRun = true
-			},
-		},
-	}
-
-	app.Run([]string{"command", "foo"})
-
-	expect(t, beforeRun, true)
-	expect(t, subcommandRun, false)
-}
-
-func TestGlobalFlagsInSubcommands(t *testing.T) {
-	subcommandRun := false
-	app := cli.NewApp()
-
-	app.Flags = []cli.Flag{
-		cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
-	}
-
-	app.Commands = []cli.Command{
-		cli.Command{
-			Name: "foo",
-			Subcommands: []cli.Command{
-				{
-					Name: "bar",
-					Action: func(c *cli.Context) {
-						if c.GlobalBool("debug") {
-							subcommandRun = true
-						}
-					},
-				},
-			},
-		},
-	}
-
-	app.Run([]string{"command", "-d", "foo", "bar"})
-
-	expect(t, subcommandRun, true)
-}

+ 4 - 3
Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete

@@ -1,13 +1,14 @@
 #! /bin/bash
 #! /bin/bash
 
 
+: ${PROG:=$(basename ${BASH_SOURCE})}
+
 _cli_bash_autocomplete() {
 _cli_bash_autocomplete() {
-     local cur prev opts base
+     local cur opts base
      COMPREPLY=()
      COMPREPLY=()
      cur="${COMP_WORDS[COMP_CWORD]}"
      cur="${COMP_WORDS[COMP_CWORD]}"
-     prev="${COMP_WORDS[COMP_CWORD-1]}"
      opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
      opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
      COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
      COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
      return 0
      return 0
  }
  }
   
   
- complete -F _cli_bash_autocomplete $PROG
+ complete -F _cli_bash_autocomplete $PROG

+ 21 - 0
Godeps/_workspace/src/github.com/codegangsta/cli/cli.go

@@ -17,3 +17,24 @@
 //     app.Run(os.Args)
 //     app.Run(os.Args)
 //   }
 //   }
 package cli
 package cli
+
+import (
+	"strings"
+)
+
+type MultiError struct {
+	Errors []error
+}
+
+func NewMultiError(err ...error) MultiError {
+	return MultiError{Errors: err}
+}
+
+func (m MultiError) Error() string {
+	errs := make([]string, len(m.Errors))
+	for i, err := range m.Errors {
+		errs[i] = err.Error()
+	}
+
+	return strings.Join(errs, "\n")
+}

+ 0 - 100
Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go

@@ -1,100 +0,0 @@
-package cli_test
-
-import (
-	"os"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
-)
-
-func Example() {
-	app := cli.NewApp()
-	app.Name = "todo"
-	app.Usage = "task list on the command line"
-	app.Commands = []cli.Command{
-		{
-			Name:      "add",
-			ShortName: "a",
-			Usage:     "add a task to the list",
-			Action: func(c *cli.Context) {
-				println("added task: ", c.Args().First())
-			},
-		},
-		{
-			Name:      "complete",
-			ShortName: "c",
-			Usage:     "complete a task on the list",
-			Action: func(c *cli.Context) {
-				println("completed task: ", c.Args().First())
-			},
-		},
-	}
-
-	app.Run(os.Args)
-}
-
-func ExampleSubcommand() {
-	app := cli.NewApp()
-	app.Name = "say"
-	app.Commands = []cli.Command{
-		{
-			Name:        "hello",
-			ShortName:   "hi",
-			Usage:       "use it to see a description",
-			Description: "This is how we describe hello the function",
-			Subcommands: []cli.Command{
-				{
-					Name:        "english",
-					ShortName:   "en",
-					Usage:       "sends a greeting in english",
-					Description: "greets someone in english",
-					Flags: []cli.Flag{
-						cli.StringFlag{
-							Name:  "name",
-							Value: "Bob",
-							Usage: "Name of the person to greet",
-						},
-					},
-					Action: func(c *cli.Context) {
-						println("Hello, ", c.String("name"))
-					},
-				}, {
-					Name:      "spanish",
-					ShortName: "sp",
-					Usage:     "sends a greeting in spanish",
-					Flags: []cli.Flag{
-						cli.StringFlag{
-							Name:  "surname",
-							Value: "Jones",
-							Usage: "Surname of the person to greet",
-						},
-					},
-					Action: func(c *cli.Context) {
-						println("Hola, ", c.String("surname"))
-					},
-				}, {
-					Name:      "french",
-					ShortName: "fr",
-					Usage:     "sends a greeting in french",
-					Flags: []cli.Flag{
-						cli.StringFlag{
-							Name:  "nickname",
-							Value: "Stevie",
-							Usage: "Nickname of the person to greet",
-						},
-					},
-					Action: func(c *cli.Context) {
-						println("Bonjour, ", c.String("nickname"))
-					},
-				},
-			},
-		}, {
-			Name:  "bye",
-			Usage: "says goodbye",
-			Action: func(c *cli.Context) {
-				println("bye")
-			},
-		},
-	}
-
-	app.Run(os.Args)
-}

+ 96 - 24
Godeps/_workspace/src/github.com/codegangsta/cli/command.go

@@ -10,17 +10,24 @@ import (
 type Command struct {
 type Command struct {
 	// The name of the command
 	// The name of the command
 	Name string
 	Name string
-	// short name of the command. Typically one character
+	// short name of the command. Typically one character (deprecated, use `Aliases`)
 	ShortName string
 	ShortName string
+	// A list of aliases for the command
+	Aliases []string
 	// A short description of the usage of this command
 	// A short description of the usage of this command
 	Usage string
 	Usage string
 	// A longer explanation of how the command works
 	// A longer explanation of how the command works
 	Description string
 	Description string
+	// A short description of the arguments of this command
+	ArgsUsage string
 	// The function to call when checking for bash command completions
 	// The function to call when checking for bash command completions
 	BashComplete func(context *Context)
 	BashComplete func(context *Context)
 	// An action to execute before any sub-subcommands are run, but after the context is ready
 	// An action to execute before any sub-subcommands are run, but after the context is ready
 	// If a non-nil error is returned, no sub-subcommands are run
 	// If a non-nil error is returned, no sub-subcommands are run
 	Before func(context *Context) error
 	Before func(context *Context) error
+	// An action to execute after any subcommands are run, but after the subcommand has finished
+	// It is run even if Action() panics
+	After func(context *Context) error
 	// The function to call when this command is invoked
 	// The function to call when this command is invoked
 	Action func(context *Context)
 	Action func(context *Context)
 	// List of child commands
 	// List of child commands
@@ -31,16 +38,28 @@ type Command struct {
 	SkipFlagParsing bool
 	SkipFlagParsing bool
 	// Boolean to hide built-in help command
 	// Boolean to hide built-in help command
 	HideHelp bool
 	HideHelp bool
+
+	// Full name of command for help, defaults to full command name, including parent commands.
+	HelpName        string
+	commandNamePath []string
+}
+
+// Returns the full name of the command.
+// For subcommands this ensures that parent commands are part of the command path
+func (c Command) FullName() string {
+	if c.commandNamePath == nil {
+		return c.Name
+	}
+	return strings.Join(c.commandNamePath, " ")
 }
 }
 
 
 // Invokes the command given the context, parses ctx.Args() to generate command-specific flags
 // Invokes the command given the context, parses ctx.Args() to generate command-specific flags
 func (c Command) Run(ctx *Context) error {
 func (c Command) Run(ctx *Context) error {
-
-	if len(c.Subcommands) > 0 || c.Before != nil {
+	if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
 		return c.startApp(ctx)
 		return c.startApp(ctx)
 	}
 	}
 
 
-	if !c.HideHelp {
+	if !c.HideHelp && (HelpFlag != BoolFlag{}) {
 		// append help to flags
 		// append help to flags
 		c.Flags = append(
 		c.Flags = append(
 			c.Flags,
 			c.Flags,
@@ -55,40 +74,57 @@ func (c Command) Run(ctx *Context) error {
 	set := flagSet(c.Name, c.Flags)
 	set := flagSet(c.Name, c.Flags)
 	set.SetOutput(ioutil.Discard)
 	set.SetOutput(ioutil.Discard)
 
 
-	firstFlagIndex := -1
-	for index, arg := range ctx.Args() {
-		if strings.HasPrefix(arg, "-") {
-			firstFlagIndex = index
-			break
+	var err error
+	if !c.SkipFlagParsing {
+		firstFlagIndex := -1
+		terminatorIndex := -1
+		for index, arg := range ctx.Args() {
+			if arg == "--" {
+				terminatorIndex = index
+				break
+			} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
+				firstFlagIndex = index
+			}
 		}
 		}
-	}
 
 
-	var err error
-	if firstFlagIndex > -1 && !c.SkipFlagParsing {
-		args := ctx.Args()
-		regularArgs := args[1:firstFlagIndex]
-		flagArgs := args[firstFlagIndex:]
-		err = set.Parse(append(flagArgs, regularArgs...))
+		if firstFlagIndex > -1 {
+			args := ctx.Args()
+			regularArgs := make([]string, len(args[1:firstFlagIndex]))
+			copy(regularArgs, args[1:firstFlagIndex])
+
+			var flagArgs []string
+			if terminatorIndex > -1 {
+				flagArgs = args[firstFlagIndex:terminatorIndex]
+				regularArgs = append(regularArgs, args[terminatorIndex:]...)
+			} else {
+				flagArgs = args[firstFlagIndex:]
+			}
+
+			err = set.Parse(append(flagArgs, regularArgs...))
+		} else {
+			err = set.Parse(ctx.Args().Tail())
+		}
 	} else {
 	} else {
-		err = set.Parse(ctx.Args().Tail())
+		if c.SkipFlagParsing {
+			err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))
+		}
 	}
 	}
 
 
 	if err != nil {
 	if err != nil {
-		fmt.Printf("Incorrect Usage.\n\n")
+		fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
+		fmt.Fprintln(ctx.App.Writer)
 		ShowCommandHelp(ctx, c.Name)
 		ShowCommandHelp(ctx, c.Name)
-		fmt.Println("")
 		return err
 		return err
 	}
 	}
 
 
 	nerr := normalizeFlags(c.Flags, set)
 	nerr := normalizeFlags(c.Flags, set)
 	if nerr != nil {
 	if nerr != nil {
-		fmt.Println(nerr)
-		fmt.Println("")
+		fmt.Fprintln(ctx.App.Writer, nerr)
+		fmt.Fprintln(ctx.App.Writer)
 		ShowCommandHelp(ctx, c.Name)
 		ShowCommandHelp(ctx, c.Name)
-		fmt.Println("")
 		return nerr
 		return nerr
 	}
 	}
-	context := NewContext(ctx.App, set, ctx.globalSet)
+	context := NewContext(ctx.App, set, ctx)
 
 
 	if checkCommandCompletions(context, c.Name) {
 	if checkCommandCompletions(context, c.Name) {
 		return nil
 		return nil
@@ -102,9 +138,24 @@ func (c Command) Run(ctx *Context) error {
 	return nil
 	return nil
 }
 }
 
 
+func (c Command) Names() []string {
+	names := []string{c.Name}
+
+	if c.ShortName != "" {
+		names = append(names, c.ShortName)
+	}
+
+	return append(names, c.Aliases...)
+}
+
 // Returns true if Command.Name or Command.ShortName matches given name
 // Returns true if Command.Name or Command.ShortName matches given name
 func (c Command) HasName(name string) bool {
 func (c Command) HasName(name string) bool {
-	return c.Name == name || c.ShortName == name
+	for _, n := range c.Names() {
+		if n == name {
+			return true
+		}
+	}
+	return false
 }
 }
 
 
 func (c Command) startApp(ctx *Context) error {
 func (c Command) startApp(ctx *Context) error {
@@ -112,6 +163,12 @@ func (c Command) startApp(ctx *Context) error {
 
 
 	// set the name and usage
 	// set the name and usage
 	app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
 	app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
+	if c.HelpName == "" {
+		app.HelpName = c.HelpName
+	} else {
+		app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
+	}
+
 	if c.Description != "" {
 	if c.Description != "" {
 		app.Usage = c.Description
 		app.Usage = c.Description
 	} else {
 	} else {
@@ -126,6 +183,13 @@ func (c Command) startApp(ctx *Context) error {
 	app.Flags = c.Flags
 	app.Flags = c.Flags
 	app.HideHelp = c.HideHelp
 	app.HideHelp = c.HideHelp
 
 
+	app.Version = ctx.App.Version
+	app.HideVersion = ctx.App.HideVersion
+	app.Compiled = ctx.App.Compiled
+	app.Author = ctx.App.Author
+	app.Email = ctx.App.Email
+	app.Writer = ctx.App.Writer
+
 	// bash completion
 	// bash completion
 	app.EnableBashCompletion = ctx.App.EnableBashCompletion
 	app.EnableBashCompletion = ctx.App.EnableBashCompletion
 	if c.BashComplete != nil {
 	if c.BashComplete != nil {
@@ -134,11 +198,19 @@ func (c Command) startApp(ctx *Context) error {
 
 
 	// set the actions
 	// set the actions
 	app.Before = c.Before
 	app.Before = c.Before
+	app.After = c.After
 	if c.Action != nil {
 	if c.Action != nil {
 		app.Action = c.Action
 		app.Action = c.Action
 	} else {
 	} else {
 		app.Action = helpSubcommand.Action
 		app.Action = helpSubcommand.Action
 	}
 	}
 
 
+	var newCmds []Command
+	for _, cc := range app.Commands {
+		cc.commandNamePath = []string{c.Name, cc.Name}
+		newCmds = append(newCmds, cc)
+	}
+	app.Commands = newCmds
+
 	return app.RunAsSubcommand(ctx)
 	return app.RunAsSubcommand(ctx)
 }
 }

+ 0 - 49
Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go

@@ -1,49 +0,0 @@
-package cli_test
-
-import (
-	"flag"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
-)
-
-func TestCommandDoNotIgnoreFlags(t *testing.T) {
-	app := cli.NewApp()
-	set := flag.NewFlagSet("test", 0)
-	test := []string{"blah", "blah", "-break"}
-	set.Parse(test)
-
-	c := cli.NewContext(app, set, set)
-
-	command := cli.Command{
-		Name:        "test-cmd",
-		ShortName:   "tc",
-		Usage:       "this is for testing",
-		Description: "testing",
-		Action:      func(_ *cli.Context) {},
-	}
-	err := command.Run(c)
-
-	expect(t, err.Error(), "flag provided but not defined: -break")
-}
-
-func TestCommandIgnoreFlags(t *testing.T) {
-	app := cli.NewApp()
-	set := flag.NewFlagSet("test", 0)
-	test := []string{"blah", "blah"}
-	set.Parse(test)
-
-	c := cli.NewContext(app, set, set)
-
-	command := cli.Command{
-		Name:            "test-cmd",
-		ShortName:       "tc",
-		Usage:           "this is for testing",
-		Description:     "testing",
-		Action:          func(_ *cli.Context) {},
-		SkipFlagParsing: true,
-	}
-	err := command.Run(c)
-
-	expect(t, err, nil)
-}

+ 88 - 15
Godeps/_workspace/src/github.com/codegangsta/cli/context.go

@@ -13,16 +13,17 @@ import (
 // can be used to retrieve context-specific Args and
 // can be used to retrieve context-specific Args and
 // parsed command-line options.
 // parsed command-line options.
 type Context struct {
 type Context struct {
-	App       *App
-	Command   Command
-	flagSet   *flag.FlagSet
-	globalSet *flag.FlagSet
-	setFlags  map[string]bool
+	App            *App
+	Command        Command
+	flagSet        *flag.FlagSet
+	setFlags       map[string]bool
+	globalSetFlags map[string]bool
+	parentContext  *Context
 }
 }
 
 
 // Creates a new context. For use in when invoking an App or Command action.
 // Creates a new context. For use in when invoking an App or Command action.
-func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
-	return &Context{App: app, flagSet: set, globalSet: globalSet}
+func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
+	return &Context{App: app, flagSet: set, parentContext: parentCtx}
 }
 }
 
 
 // Looks up the value of a local int flag, returns 0 if no int flag exists
 // Looks up the value of a local int flag, returns 0 if no int flag exists
@@ -72,40 +73,66 @@ func (c *Context) Generic(name string) interface{} {
 
 
 // Looks up the value of a global int flag, returns 0 if no int flag exists
 // Looks up the value of a global int flag, returns 0 if no int flag exists
 func (c *Context) GlobalInt(name string) int {
 func (c *Context) GlobalInt(name string) int {
-	return lookupInt(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupInt(name, fs)
+	}
+	return 0
 }
 }
 
 
 // Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
 // Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
 func (c *Context) GlobalDuration(name string) time.Duration {
 func (c *Context) GlobalDuration(name string) time.Duration {
-	return lookupDuration(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupDuration(name, fs)
+	}
+	return 0
 }
 }
 
 
 // Looks up the value of a global bool flag, returns false if no bool flag exists
 // Looks up the value of a global bool flag, returns false if no bool flag exists
 func (c *Context) GlobalBool(name string) bool {
 func (c *Context) GlobalBool(name string) bool {
-	return lookupBool(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupBool(name, fs)
+	}
+	return false
 }
 }
 
 
 // Looks up the value of a global string flag, returns "" if no string flag exists
 // Looks up the value of a global string flag, returns "" if no string flag exists
 func (c *Context) GlobalString(name string) string {
 func (c *Context) GlobalString(name string) string {
-	return lookupString(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupString(name, fs)
+	}
+	return ""
 }
 }
 
 
 // Looks up the value of a global string slice flag, returns nil if no string slice flag exists
 // Looks up the value of a global string slice flag, returns nil if no string slice flag exists
 func (c *Context) GlobalStringSlice(name string) []string {
 func (c *Context) GlobalStringSlice(name string) []string {
-	return lookupStringSlice(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupStringSlice(name, fs)
+	}
+	return nil
 }
 }
 
 
 // Looks up the value of a global int slice flag, returns nil if no int slice flag exists
 // Looks up the value of a global int slice flag, returns nil if no int slice flag exists
 func (c *Context) GlobalIntSlice(name string) []int {
 func (c *Context) GlobalIntSlice(name string) []int {
-	return lookupIntSlice(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupIntSlice(name, fs)
+	}
+	return nil
 }
 }
 
 
 // Looks up the value of a global generic flag, returns nil if no generic flag exists
 // Looks up the value of a global generic flag, returns nil if no generic flag exists
 func (c *Context) GlobalGeneric(name string) interface{} {
 func (c *Context) GlobalGeneric(name string) interface{} {
-	return lookupGeneric(name, c.globalSet)
+	if fs := lookupGlobalFlagSet(name, c); fs != nil {
+		return lookupGeneric(name, fs)
+	}
+	return nil
 }
 }
 
 
-// Determines if the flag was actually set exists
+// Returns the number of flags set
+func (c *Context) NumFlags() int {
+	return c.flagSet.NFlag()
+}
+
+// Determines if the flag was actually set
 func (c *Context) IsSet(name string) bool {
 func (c *Context) IsSet(name string) bool {
 	if c.setFlags == nil {
 	if c.setFlags == nil {
 		c.setFlags = make(map[string]bool)
 		c.setFlags = make(map[string]bool)
@@ -116,6 +143,23 @@ func (c *Context) IsSet(name string) bool {
 	return c.setFlags[name] == true
 	return c.setFlags[name] == true
 }
 }
 
 
+// Determines if the global flag was actually set
+func (c *Context) GlobalIsSet(name string) bool {
+	if c.globalSetFlags == nil {
+		c.globalSetFlags = make(map[string]bool)
+		ctx := c
+		if ctx.parentContext != nil {
+			ctx = ctx.parentContext
+		}
+		for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
+			ctx.flagSet.Visit(func(f *flag.Flag) {
+				c.globalSetFlags[f.Name] = true
+			})
+		}
+	}
+	return c.globalSetFlags[name]
+}
+
 // Returns a slice of flag names used in this context.
 // Returns a slice of flag names used in this context.
 func (c *Context) FlagNames() (names []string) {
 func (c *Context) FlagNames() (names []string) {
 	for _, flag := range c.Command.Flags {
 	for _, flag := range c.Command.Flags {
@@ -128,6 +172,23 @@ func (c *Context) FlagNames() (names []string) {
 	return
 	return
 }
 }
 
 
+// Returns a slice of global flag names used by the app.
+func (c *Context) GlobalFlagNames() (names []string) {
+	for _, flag := range c.App.Flags {
+		name := strings.Split(flag.getName(), ",")[0]
+		if name == "help" || name == "version" {
+			continue
+		}
+		names = append(names, name)
+	}
+	return
+}
+
+// Returns the parent context, if any
+func (c *Context) Parent() *Context {
+	return c.parentContext
+}
+
 type Args []string
 type Args []string
 
 
 // Returns the command line arguments associated with the context.
 // Returns the command line arguments associated with the context.
@@ -172,6 +233,18 @@ func (a Args) Swap(from, to int) error {
 	return nil
 	return nil
 }
 }
 
 
+func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
+	if ctx.parentContext != nil {
+		ctx = ctx.parentContext
+	}
+	for ; ctx != nil; ctx = ctx.parentContext {
+		if f := ctx.flagSet.Lookup(name); f != nil {
+			return ctx.flagSet
+		}
+	}
+	return nil
+}
+
 func lookupInt(name string, set *flag.FlagSet) int {
 func lookupInt(name string, set *flag.FlagSet) int {
 	f := set.Lookup(name)
 	f := set.Lookup(name)
 	if f != nil {
 	if f != nil {

+ 0 - 77
Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go

@@ -1,77 +0,0 @@
-package cli_test
-
-import (
-	"flag"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
-)
-
-func TestNewContext(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Int("myflag", 12, "doc")
-	globalSet := flag.NewFlagSet("test", 0)
-	globalSet.Int("myflag", 42, "doc")
-	command := cli.Command{Name: "mycommand"}
-	c := cli.NewContext(nil, set, globalSet)
-	c.Command = command
-	expect(t, c.Int("myflag"), 12)
-	expect(t, c.GlobalInt("myflag"), 42)
-	expect(t, c.Command.Name, "mycommand")
-}
-
-func TestContext_Int(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Int("myflag", 12, "doc")
-	c := cli.NewContext(nil, set, set)
-	expect(t, c.Int("myflag"), 12)
-}
-
-func TestContext_Duration(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Duration("myflag", time.Duration(12*time.Second), "doc")
-	c := cli.NewContext(nil, set, set)
-	expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
-}
-
-func TestContext_String(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.String("myflag", "hello world", "doc")
-	c := cli.NewContext(nil, set, set)
-	expect(t, c.String("myflag"), "hello world")
-}
-
-func TestContext_Bool(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Bool("myflag", false, "doc")
-	c := cli.NewContext(nil, set, set)
-	expect(t, c.Bool("myflag"), false)
-}
-
-func TestContext_BoolT(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Bool("myflag", true, "doc")
-	c := cli.NewContext(nil, set, set)
-	expect(t, c.BoolT("myflag"), true)
-}
-
-func TestContext_Args(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Bool("myflag", false, "doc")
-	c := cli.NewContext(nil, set, set)
-	set.Parse([]string{"--myflag", "bat", "baz"})
-	expect(t, len(c.Args()), 2)
-	expect(t, c.Bool("myflag"), true)
-}
-
-func TestContext_IsSet(t *testing.T) {
-	set := flag.NewFlagSet("test", 0)
-	set.Bool("myflag", false, "doc")
-	set.String("otherflag", "hello world", "doc")
-	c := cli.NewContext(nil, set, set)
-	set.Parse([]string{"--myflag", "bat", "baz"})
-	expect(t, c.IsSet("myflag"), true)
-	expect(t, c.IsSet("otherflag"), false)
-	expect(t, c.IsSet("bogusflag"), false)
-}

+ 184 - 67
Godeps/_workspace/src/github.com/codegangsta/cli/flag.go

@@ -21,6 +21,8 @@ var VersionFlag = BoolFlag{
 }
 }
 
 
 // This flag prints the help for all commands and subcommands
 // This flag prints the help for all commands and subcommands
+// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
+// unless HideHelp is set to true)
 var HelpFlag = BoolFlag{
 var HelpFlag = BoolFlag{
 	Name:  "help, h",
 	Name:  "help, h",
 	Usage: "show help",
 	Usage: "show help",
@@ -67,15 +69,24 @@ type GenericFlag struct {
 	EnvVar string
 	EnvVar string
 }
 }
 
 
+// String returns the string representation of the generic flag to display the
+// help text to the user (uses the String() method of the generic flag to show
+// the value)
 func (f GenericFlag) String() string {
 func (f GenericFlag) String() string {
-	return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage))
+	return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
 }
 }
 
 
+// Apply takes the flagset and calls Set on the generic flag with the value
+// provided by the user for parsing by the flag
 func (f GenericFlag) Apply(set *flag.FlagSet) {
 func (f GenericFlag) Apply(set *flag.FlagSet) {
 	val := f.Value
 	val := f.Value
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			val.Set(envVal)
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				val.Set(envVal)
+				break
+			}
 		}
 		}
 	}
 	}
 
 
@@ -88,21 +99,27 @@ func (f GenericFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// StringSlice is an opaque type for []string to satisfy flag.Value
 type StringSlice []string
 type StringSlice []string
 
 
+// Set appends the string value to the list of values
 func (f *StringSlice) Set(value string) error {
 func (f *StringSlice) Set(value string) error {
 	*f = append(*f, value)
 	*f = append(*f, value)
 	return nil
 	return nil
 }
 }
 
 
+// String returns a readable representation of this value (for usage defaults)
 func (f *StringSlice) String() string {
 func (f *StringSlice) String() string {
 	return fmt.Sprintf("%s", *f)
 	return fmt.Sprintf("%s", *f)
 }
 }
 
 
+// Value returns the slice of strings set by this flag
 func (f *StringSlice) Value() []string {
 func (f *StringSlice) Value() []string {
 	return *f
 	return *f
 }
 }
 
 
+// StringSlice is a string flag that can be specified multiple times on the
+// command-line
 type StringSliceFlag struct {
 type StringSliceFlag struct {
 	Name   string
 	Name   string
 	Value  *StringSlice
 	Value  *StringSlice
@@ -110,24 +127,34 @@ type StringSliceFlag struct {
 	EnvVar string
 	EnvVar string
 }
 }
 
 
+// String returns the usage
 func (f StringSliceFlag) String() string {
 func (f StringSliceFlag) String() string {
 	firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
 	firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
 	pref := prefixFor(firstName)
 	pref := prefixFor(firstName)
-	return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
+	return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f StringSliceFlag) Apply(set *flag.FlagSet) {
 func (f StringSliceFlag) Apply(set *flag.FlagSet) {
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			newVal := &StringSlice{}
-			for _, s := range strings.Split(envVal, ",") {
-				newVal.Set(s)
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				newVal := &StringSlice{}
+				for _, s := range strings.Split(envVal, ",") {
+					s = strings.TrimSpace(s)
+					newVal.Set(s)
+				}
+				f.Value = newVal
+				break
 			}
 			}
-			f.Value = newVal
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Value == nil {
+			f.Value = &StringSlice{}
+		}
 		set.Var(f.Value, name, f.Usage)
 		set.Var(f.Value, name, f.Usage)
 	})
 	})
 }
 }
@@ -136,10 +163,11 @@ func (f StringSliceFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// StringSlice is an opaque type for []int to satisfy flag.Value
 type IntSlice []int
 type IntSlice []int
 
 
+// Set parses the value into an integer and appends it to the list of values
 func (f *IntSlice) Set(value string) error {
 func (f *IntSlice) Set(value string) error {
-
 	tmp, err := strconv.Atoi(value)
 	tmp, err := strconv.Atoi(value)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -149,14 +177,18 @@ func (f *IntSlice) Set(value string) error {
 	return nil
 	return nil
 }
 }
 
 
+// String returns a readable representation of this value (for usage defaults)
 func (f *IntSlice) String() string {
 func (f *IntSlice) String() string {
 	return fmt.Sprintf("%d", *f)
 	return fmt.Sprintf("%d", *f)
 }
 }
 
 
+// Value returns the slice of ints set by this flag
 func (f *IntSlice) Value() []int {
 func (f *IntSlice) Value() []int {
 	return *f
 	return *f
 }
 }
 
 
+// IntSliceFlag is an int flag that can be specified multiple times on the
+// command-line
 type IntSliceFlag struct {
 type IntSliceFlag struct {
 	Name   string
 	Name   string
 	Value  *IntSlice
 	Value  *IntSlice
@@ -164,27 +196,37 @@ type IntSliceFlag struct {
 	EnvVar string
 	EnvVar string
 }
 }
 
 
+// String returns the usage
 func (f IntSliceFlag) String() string {
 func (f IntSliceFlag) String() string {
 	firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
 	firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
 	pref := prefixFor(firstName)
 	pref := prefixFor(firstName)
-	return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
+	return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f IntSliceFlag) Apply(set *flag.FlagSet) {
 func (f IntSliceFlag) Apply(set *flag.FlagSet) {
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			newVal := &IntSlice{}
-			for _, s := range strings.Split(envVal, ",") {
-				err := newVal.Set(s)
-				if err != nil {
-					fmt.Fprintf(os.Stderr, err.Error())
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				newVal := &IntSlice{}
+				for _, s := range strings.Split(envVal, ",") {
+					s = strings.TrimSpace(s)
+					err := newVal.Set(s)
+					if err != nil {
+						fmt.Fprintf(os.Stderr, err.Error())
+					}
 				}
 				}
+				f.Value = newVal
+				break
 			}
 			}
-			f.Value = newVal
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Value == nil {
+			f.Value = &IntSlice{}
+		}
 		set.Var(f.Value, name, f.Usage)
 		set.Var(f.Value, name, f.Usage)
 	})
 	})
 }
 }
@@ -193,28 +235,40 @@ func (f IntSliceFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// BoolFlag is a switch that defaults to false
 type BoolFlag struct {
 type BoolFlag struct {
-	Name   string
-	Usage  string
-	EnvVar string
+	Name        string
+	Usage       string
+	EnvVar      string
+	Destination *bool
 }
 }
 
 
+// String returns a readable representation of this value (for usage defaults)
 func (f BoolFlag) String() string {
 func (f BoolFlag) String() string {
 	return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
 	return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f BoolFlag) Apply(set *flag.FlagSet) {
 func (f BoolFlag) Apply(set *flag.FlagSet) {
 	val := false
 	val := false
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			envValBool, err := strconv.ParseBool(envVal)
-			if err == nil {
-				val = envValBool
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				envValBool, err := strconv.ParseBool(envVal)
+				if err == nil {
+					val = envValBool
+				}
+				break
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Destination != nil {
+			set.BoolVar(f.Destination, name, val, f.Usage)
+			return
+		}
 		set.Bool(name, val, f.Usage)
 		set.Bool(name, val, f.Usage)
 	})
 	})
 }
 }
@@ -223,28 +277,41 @@ func (f BoolFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// BoolTFlag this represents a boolean flag that is true by default, but can
+// still be set to false by --some-flag=false
 type BoolTFlag struct {
 type BoolTFlag struct {
-	Name   string
-	Usage  string
-	EnvVar string
+	Name        string
+	Usage       string
+	EnvVar      string
+	Destination *bool
 }
 }
 
 
+// String returns a readable representation of this value (for usage defaults)
 func (f BoolTFlag) String() string {
 func (f BoolTFlag) String() string {
 	return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
 	return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f BoolTFlag) Apply(set *flag.FlagSet) {
 func (f BoolTFlag) Apply(set *flag.FlagSet) {
 	val := true
 	val := true
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			envValBool, err := strconv.ParseBool(envVal)
-			if err == nil {
-				val = envValBool
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				envValBool, err := strconv.ParseBool(envVal)
+				if err == nil {
+					val = envValBool
+					break
+				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Destination != nil {
+			set.BoolVar(f.Destination, name, val, f.Usage)
+			return
+		}
 		set.Bool(name, val, f.Usage)
 		set.Bool(name, val, f.Usage)
 	})
 	})
 }
 }
@@ -253,19 +320,22 @@ func (f BoolTFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// StringFlag represents a flag that takes as string value
 type StringFlag struct {
 type StringFlag struct {
-	Name   string
-	Value  string
-	Usage  string
-	EnvVar string
+	Name        string
+	Value       string
+	Usage       string
+	EnvVar      string
+	Destination *string
 }
 }
 
 
+// String returns the usage
 func (f StringFlag) String() string {
 func (f StringFlag) String() string {
 	var fmtString string
 	var fmtString string
 	fmtString = "%s %v\t%v"
 	fmtString = "%s %v\t%v"
 
 
 	if len(f.Value) > 0 {
 	if len(f.Value) > 0 {
-		fmtString = "%s '%v'\t%v"
+		fmtString = "%s \"%v\"\t%v"
 	} else {
 	} else {
 		fmtString = "%s %v\t%v"
 		fmtString = "%s %v\t%v"
 	}
 	}
@@ -273,14 +343,23 @@ func (f StringFlag) String() string {
 	return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
 	return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f StringFlag) Apply(set *flag.FlagSet) {
 func (f StringFlag) Apply(set *flag.FlagSet) {
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			f.Value = envVal
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				f.Value = envVal
+				break
+			}
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Destination != nil {
+			set.StringVar(f.Destination, name, f.Value, f.Usage)
+			return
+		}
 		set.String(name, f.Value, f.Usage)
 		set.String(name, f.Value, f.Usage)
 	})
 	})
 }
 }
@@ -289,28 +368,41 @@ func (f StringFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// IntFlag is a flag that takes an integer
+// Errors if the value provided cannot be parsed
 type IntFlag struct {
 type IntFlag struct {
-	Name   string
-	Value  int
-	Usage  string
-	EnvVar string
+	Name        string
+	Value       int
+	Usage       string
+	EnvVar      string
+	Destination *int
 }
 }
 
 
+// String returns the usage
 func (f IntFlag) String() string {
 func (f IntFlag) String() string {
-	return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage))
+	return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f IntFlag) Apply(set *flag.FlagSet) {
 func (f IntFlag) Apply(set *flag.FlagSet) {
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			envValInt, err := strconv.ParseUint(envVal, 10, 64)
-			if err == nil {
-				f.Value = int(envValInt)
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				envValInt, err := strconv.ParseInt(envVal, 0, 64)
+				if err == nil {
+					f.Value = int(envValInt)
+					break
+				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Destination != nil {
+			set.IntVar(f.Destination, name, f.Value, f.Usage)
+			return
+		}
 		set.Int(name, f.Value, f.Usage)
 		set.Int(name, f.Value, f.Usage)
 	})
 	})
 }
 }
@@ -319,28 +411,41 @@ func (f IntFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// DurationFlag is a flag that takes a duration specified in Go's duration
+// format: https://golang.org/pkg/time/#ParseDuration
 type DurationFlag struct {
 type DurationFlag struct {
-	Name   string
-	Value  time.Duration
-	Usage  string
-	EnvVar string
+	Name        string
+	Value       time.Duration
+	Usage       string
+	EnvVar      string
+	Destination *time.Duration
 }
 }
 
 
+// String returns a readable representation of this value (for usage defaults)
 func (f DurationFlag) String() string {
 func (f DurationFlag) String() string {
-	return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage))
+	return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f DurationFlag) Apply(set *flag.FlagSet) {
 func (f DurationFlag) Apply(set *flag.FlagSet) {
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			envValDuration, err := time.ParseDuration(envVal)
-			if err == nil {
-				f.Value = envValDuration
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				envValDuration, err := time.ParseDuration(envVal)
+				if err == nil {
+					f.Value = envValDuration
+					break
+				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Destination != nil {
+			set.DurationVar(f.Destination, name, f.Value, f.Usage)
+			return
+		}
 		set.Duration(name, f.Value, f.Usage)
 		set.Duration(name, f.Value, f.Usage)
 	})
 	})
 }
 }
@@ -349,28 +454,40 @@ func (f DurationFlag) getName() string {
 	return f.Name
 	return f.Name
 }
 }
 
 
+// Float64Flag is a flag that takes an float value
+// Errors if the value provided cannot be parsed
 type Float64Flag struct {
 type Float64Flag struct {
-	Name   string
-	Value  float64
-	Usage  string
-	EnvVar string
+	Name        string
+	Value       float64
+	Usage       string
+	EnvVar      string
+	Destination *float64
 }
 }
 
 
+// String returns the usage
 func (f Float64Flag) String() string {
 func (f Float64Flag) String() string {
-	return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage))
+	return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
 }
 }
 
 
+// Apply populates the flag given the flag set and environment
 func (f Float64Flag) Apply(set *flag.FlagSet) {
 func (f Float64Flag) Apply(set *flag.FlagSet) {
 	if f.EnvVar != "" {
 	if f.EnvVar != "" {
-		if envVal := os.Getenv(f.EnvVar); envVal != "" {
-			envValFloat, err := strconv.ParseFloat(envVal, 10)
-			if err == nil {
-				f.Value = float64(envValFloat)
+		for _, envVar := range strings.Split(f.EnvVar, ",") {
+			envVar = strings.TrimSpace(envVar)
+			if envVal := os.Getenv(envVar); envVal != "" {
+				envValFloat, err := strconv.ParseFloat(envVal, 10)
+				if err == nil {
+					f.Value = float64(envValFloat)
+				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	eachName(f.Name, func(name string) {
 	eachName(f.Name, func(name string) {
+		if f.Destination != nil {
+			set.Float64Var(f.Destination, name, f.Value, f.Usage)
+			return
+		}
 		set.Float64(name, f.Value, f.Usage)
 		set.Float64(name, f.Value, f.Usage)
 	})
 	})
 }
 }
@@ -404,7 +521,7 @@ func prefixedNames(fullName string) (prefixed string) {
 func withEnvHint(envVar, str string) string {
 func withEnvHint(envVar, str string) string {
 	envText := ""
 	envText := ""
 	if envVar != "" {
 	if envVar != "" {
-		envText = fmt.Sprintf(" [$%s]", envVar)
+		envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
 	}
 	}
 	return str + envText
 	return str + envText
 }
 }

+ 0 - 587
Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go

@@ -1,587 +0,0 @@
-package cli_test
-
-import (
-	"fmt"
-	"os"
-	"reflect"
-	"strings"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/codegangsta/cli"
-)
-
-var boolFlagTests = []struct {
-	name     string
-	expected string
-}{
-	{"help", "--help\t"},
-	{"h", "-h\t"},
-}
-
-func TestBoolFlagHelpOutput(t *testing.T) {
-
-	for _, test := range boolFlagTests {
-		flag := cli.BoolFlag{Name: test.name}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%s does not match %s", output, test.expected)
-		}
-	}
-}
-
-var stringFlagTests = []struct {
-	name     string
-	value    string
-	expected string
-}{
-	{"help", "", "--help \t"},
-	{"h", "", "-h \t"},
-	{"h", "", "-h \t"},
-	{"test", "Something", "--test 'Something'\t"},
-}
-
-func TestStringFlagHelpOutput(t *testing.T) {
-
-	for _, test := range stringFlagTests {
-		flag := cli.StringFlag{Name: test.name, Value: test.value}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%s does not match %s", output, test.expected)
-		}
-	}
-}
-
-func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_FOO", "derp")
-	for _, test := range stringFlagTests {
-		flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_FOO]") {
-			t.Errorf("%s does not end with [$APP_FOO]", output)
-		}
-	}
-}
-
-var stringSliceFlagTests = []struct {
-	name     string
-	value    *cli.StringSlice
-	expected string
-}{
-	{"help", func() *cli.StringSlice {
-		s := &cli.StringSlice{}
-		s.Set("")
-		return s
-	}(), "--help '--help option --help option'\t"},
-	{"h", func() *cli.StringSlice {
-		s := &cli.StringSlice{}
-		s.Set("")
-		return s
-	}(), "-h '-h option -h option'\t"},
-	{"h", func() *cli.StringSlice {
-		s := &cli.StringSlice{}
-		s.Set("")
-		return s
-	}(), "-h '-h option -h option'\t"},
-	{"test", func() *cli.StringSlice {
-		s := &cli.StringSlice{}
-		s.Set("Something")
-		return s
-	}(), "--test '--test option --test option'\t"},
-}
-
-func TestStringSliceFlagHelpOutput(t *testing.T) {
-
-	for _, test := range stringSliceFlagTests {
-		flag := cli.StringSliceFlag{Name: test.name, Value: test.value}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%q does not match %q", output, test.expected)
-		}
-	}
-}
-
-func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_QWWX", "11,4")
-	for _, test := range stringSliceFlagTests {
-		flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_QWWX]") {
-			t.Errorf("%q does not end with [$APP_QWWX]", output)
-		}
-	}
-}
-
-var intFlagTests = []struct {
-	name     string
-	expected string
-}{
-	{"help", "--help '0'\t"},
-	{"h", "-h '0'\t"},
-}
-
-func TestIntFlagHelpOutput(t *testing.T) {
-
-	for _, test := range intFlagTests {
-		flag := cli.IntFlag{Name: test.name}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%s does not match %s", output, test.expected)
-		}
-	}
-}
-
-func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_BAR", "2")
-	for _, test := range intFlagTests {
-		flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_BAR]") {
-			t.Errorf("%s does not end with [$APP_BAR]", output)
-		}
-	}
-}
-
-var durationFlagTests = []struct {
-	name     string
-	expected string
-}{
-	{"help", "--help '0'\t"},
-	{"h", "-h '0'\t"},
-}
-
-func TestDurationFlagHelpOutput(t *testing.T) {
-
-	for _, test := range durationFlagTests {
-		flag := cli.DurationFlag{Name: test.name}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%s does not match %s", output, test.expected)
-		}
-	}
-}
-
-func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_BAR", "2h3m6s")
-	for _, test := range durationFlagTests {
-		flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_BAR]") {
-			t.Errorf("%s does not end with [$APP_BAR]", output)
-		}
-	}
-}
-
-var intSliceFlagTests = []struct {
-	name     string
-	value    *cli.IntSlice
-	expected string
-}{
-	{"help", &cli.IntSlice{}, "--help '--help option --help option'\t"},
-	{"h", &cli.IntSlice{}, "-h '-h option -h option'\t"},
-	{"h", &cli.IntSlice{}, "-h '-h option -h option'\t"},
-	{"test", func() *cli.IntSlice {
-		i := &cli.IntSlice{}
-		i.Set("9")
-		return i
-	}(), "--test '--test option --test option'\t"},
-}
-
-func TestIntSliceFlagHelpOutput(t *testing.T) {
-
-	for _, test := range intSliceFlagTests {
-		flag := cli.IntSliceFlag{Name: test.name, Value: test.value}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%q does not match %q", output, test.expected)
-		}
-	}
-}
-
-func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_SMURF", "42,3")
-	for _, test := range intSliceFlagTests {
-		flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_SMURF]") {
-			t.Errorf("%q does not end with [$APP_SMURF]", output)
-		}
-	}
-}
-
-var float64FlagTests = []struct {
-	name     string
-	expected string
-}{
-	{"help", "--help '0'\t"},
-	{"h", "-h '0'\t"},
-}
-
-func TestFloat64FlagHelpOutput(t *testing.T) {
-
-	for _, test := range float64FlagTests {
-		flag := cli.Float64Flag{Name: test.name}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%s does not match %s", output, test.expected)
-		}
-	}
-}
-
-func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_BAZ", "99.4")
-	for _, test := range float64FlagTests {
-		flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_BAZ]") {
-			t.Errorf("%s does not end with [$APP_BAZ]", output)
-		}
-	}
-}
-
-var genericFlagTests = []struct {
-	name     string
-	value    cli.Generic
-	expected string
-}{
-	{"help", &Parser{}, "--help <nil>\t`-help option -help option` "},
-	{"h", &Parser{}, "-h <nil>\t`-h option -h option` "},
-	{"test", &Parser{}, "--test <nil>\t`-test option -test option` "},
-}
-
-func TestGenericFlagHelpOutput(t *testing.T) {
-
-	for _, test := range genericFlagTests {
-		flag := cli.GenericFlag{Name: test.name}
-		output := flag.String()
-
-		if output != test.expected {
-			t.Errorf("%q does not match %q", output, test.expected)
-		}
-	}
-}
-
-func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
-
-	os.Setenv("APP_ZAP", "3")
-	for _, test := range genericFlagTests {
-		flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
-		output := flag.String()
-
-		if !strings.HasSuffix(output, " [$APP_ZAP]") {
-			t.Errorf("%s does not end with [$APP_ZAP]", output)
-		}
-	}
-}
-
-func TestParseMultiString(t *testing.T) {
-	(&cli.App{
-		Flags: []cli.Flag{
-			cli.StringFlag{Name: "serve, s"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.String("serve") != "10" {
-				t.Errorf("main name not set")
-			}
-			if ctx.String("s") != "10" {
-				t.Errorf("short name not set")
-			}
-		},
-	}).Run([]string{"run", "-s", "10"})
-}
-
-func TestParseMultiStringFromEnv(t *testing.T) {
-	os.Setenv("APP_COUNT", "20")
-	(&cli.App{
-		Flags: []cli.Flag{
-			cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.String("count") != "20" {
-				t.Errorf("main name not set")
-			}
-			if ctx.String("c") != "20" {
-				t.Errorf("short name not set")
-			}
-		},
-	}).Run([]string{"run"})
-}
-
-func TestParseMultiStringSlice(t *testing.T) {
-	(&cli.App{
-		Flags: []cli.Flag{
-			cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}},
-		},
-		Action: func(ctx *cli.Context) {
-			if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
-				t.Errorf("main name not set")
-			}
-			if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
-				t.Errorf("short name not set")
-			}
-		},
-	}).Run([]string{"run", "-s", "10", "-s", "20"})
-}
-
-func TestParseMultiStringSliceFromEnv(t *testing.T) {
-	os.Setenv("APP_INTERVALS", "20,30,40")
-
-	(&cli.App{
-		Flags: []cli.Flag{
-			cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"},
-		},
-		Action: func(ctx *cli.Context) {
-			if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
-				t.Errorf("main name not set from env")
-			}
-			if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
-				t.Errorf("short name not set from env")
-			}
-		},
-	}).Run([]string{"run"})
-}
-
-func TestParseMultiInt(t *testing.T) {
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.IntFlag{Name: "serve, s"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.Int("serve") != 10 {
-				t.Errorf("main name not set")
-			}
-			if ctx.Int("s") != 10 {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run", "-s", "10"})
-}
-
-func TestParseMultiIntFromEnv(t *testing.T) {
-	os.Setenv("APP_TIMEOUT_SECONDS", "10")
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.Int("timeout") != 10 {
-				t.Errorf("main name not set")
-			}
-			if ctx.Int("t") != 10 {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run"})
-}
-
-func TestParseMultiIntSlice(t *testing.T) {
-	(&cli.App{
-		Flags: []cli.Flag{
-			cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}},
-		},
-		Action: func(ctx *cli.Context) {
-			if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
-				t.Errorf("main name not set")
-			}
-			if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
-				t.Errorf("short name not set")
-			}
-		},
-	}).Run([]string{"run", "-s", "10", "-s", "20"})
-}
-
-func TestParseMultiIntSliceFromEnv(t *testing.T) {
-	os.Setenv("APP_INTERVALS", "20,30,40")
-
-	(&cli.App{
-		Flags: []cli.Flag{
-			cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"},
-		},
-		Action: func(ctx *cli.Context) {
-			if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
-				t.Errorf("main name not set from env")
-			}
-			if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
-				t.Errorf("short name not set from env")
-			}
-		},
-	}).Run([]string{"run"})
-}
-
-func TestParseMultiFloat64(t *testing.T) {
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.Float64Flag{Name: "serve, s"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.Float64("serve") != 10.2 {
-				t.Errorf("main name not set")
-			}
-			if ctx.Float64("s") != 10.2 {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run", "-s", "10.2"})
-}
-
-func TestParseMultiFloat64FromEnv(t *testing.T) {
-	os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.Float64("timeout") != 15.5 {
-				t.Errorf("main name not set")
-			}
-			if ctx.Float64("t") != 15.5 {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run"})
-}
-
-func TestParseMultiBool(t *testing.T) {
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.BoolFlag{Name: "serve, s"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.Bool("serve") != true {
-				t.Errorf("main name not set")
-			}
-			if ctx.Bool("s") != true {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run", "--serve"})
-}
-
-func TestParseMultiBoolFromEnv(t *testing.T) {
-	os.Setenv("APP_DEBUG", "1")
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.Bool("debug") != true {
-				t.Errorf("main name not set from env")
-			}
-			if ctx.Bool("d") != true {
-				t.Errorf("short name not set from env")
-			}
-		},
-	}
-	a.Run([]string{"run"})
-}
-
-func TestParseMultiBoolT(t *testing.T) {
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.BoolTFlag{Name: "serve, s"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.BoolT("serve") != true {
-				t.Errorf("main name not set")
-			}
-			if ctx.BoolT("s") != true {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run", "--serve"})
-}
-
-func TestParseMultiBoolTFromEnv(t *testing.T) {
-	os.Setenv("APP_DEBUG", "0")
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
-		},
-		Action: func(ctx *cli.Context) {
-			if ctx.BoolT("debug") != false {
-				t.Errorf("main name not set from env")
-			}
-			if ctx.BoolT("d") != false {
-				t.Errorf("short name not set from env")
-			}
-		},
-	}
-	a.Run([]string{"run"})
-}
-
-type Parser [2]string
-
-func (p *Parser) Set(value string) error {
-	parts := strings.Split(value, ",")
-	if len(parts) != 2 {
-		return fmt.Errorf("invalid format")
-	}
-
-	(*p)[0] = parts[0]
-	(*p)[1] = parts[1]
-
-	return nil
-}
-
-func (p *Parser) String() string {
-	return fmt.Sprintf("%s,%s", p[0], p[1])
-}
-
-func TestParseGeneric(t *testing.T) {
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.GenericFlag{Name: "serve, s", Value: &Parser{}},
-		},
-		Action: func(ctx *cli.Context) {
-			if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
-				t.Errorf("main name not set")
-			}
-			if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
-				t.Errorf("short name not set")
-			}
-		},
-	}
-	a.Run([]string{"run", "-s", "10,20"})
-}
-
-func TestParseGenericFromEnv(t *testing.T) {
-	os.Setenv("APP_SERVE", "20,30")
-	a := cli.App{
-		Flags: []cli.Flag{
-			cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
-		},
-		Action: func(ctx *cli.Context) {
-			if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
-				t.Errorf("main name not set from env")
-			}
-			if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
-				t.Errorf("short name not set from env")
-			}
-		},
-	}
-	a.Run([]string{"run"})
-}

+ 69 - 47
Godeps/_workspace/src/github.com/codegangsta/cli/help.go

@@ -2,7 +2,8 @@ package cli
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"os"
+	"io"
+	"strings"
 	"text/tabwriter"
 	"text/tabwriter"
 	"text/template"
 	"text/template"
 )
 )
@@ -14,31 +15,33 @@ var AppHelpTemplate = `NAME:
    {{.Name}} - {{.Usage}}
    {{.Name}} - {{.Usage}}
 
 
 USAGE:
 USAGE:
-   {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
-
+   {{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
+   {{if .Version}}
 VERSION:
 VERSION:
-   {{.Version}}{{if or .Author .Email}}
-
-AUTHOR:{{if .Author}}
-  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
-  {{.Email}}{{end}}{{end}}
-
+   {{.Version}}
+   {{end}}{{if len .Authors}}
+AUTHOR(S):
+   {{range .Authors}}{{ . }}{{end}}
+   {{end}}{{if .Commands}}
 COMMANDS:
 COMMANDS:
-   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
-   {{end}}{{if .Flags}}
+   {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
+   {{end}}{{end}}{{if .Flags}}
 GLOBAL OPTIONS:
 GLOBAL OPTIONS:
    {{range .Flags}}{{.}}
    {{range .Flags}}{{.}}
-   {{end}}{{end}}
+   {{end}}{{end}}{{if .Copyright }}
+COPYRIGHT:
+   {{.Copyright}}
+   {{end}}
 `
 `
 
 
 // The text template for the command help topic.
 // The text template for the command help topic.
 // cli.go uses text/template to render templates. You can
 // cli.go uses text/template to render templates. You can
 // render custom help text by setting this variable.
 // render custom help text by setting this variable.
 var CommandHelpTemplate = `NAME:
 var CommandHelpTemplate = `NAME:
-   {{.Name}} - {{.Usage}}
+   {{.HelpName}} - {{.Usage}}
 
 
 USAGE:
 USAGE:
-   command {{.Name}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}}
+   {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}}
 
 
 DESCRIPTION:
 DESCRIPTION:
    {{.Description}}{{end}}{{if .Flags}}
    {{.Description}}{{end}}{{if .Flags}}
@@ -52,13 +55,13 @@ OPTIONS:
 // cli.go uses text/template to render templates. You can
 // cli.go uses text/template to render templates. You can
 // render custom help text by setting this variable.
 // render custom help text by setting this variable.
 var SubcommandHelpTemplate = `NAME:
 var SubcommandHelpTemplate = `NAME:
-   {{.Name}} - {{.Usage}}
+   {{.HelpName}} - {{.Usage}}
 
 
 USAGE:
 USAGE:
-   {{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
+   {{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
 
 
 COMMANDS:
 COMMANDS:
-   {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
+   {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
    {{end}}{{if .Flags}}
    {{end}}{{if .Flags}}
 OPTIONS:
 OPTIONS:
    {{range .Flags}}{{.}}
    {{range .Flags}}{{.}}
@@ -67,8 +70,9 @@ OPTIONS:
 
 
 var helpCommand = Command{
 var helpCommand = Command{
 	Name:      "help",
 	Name:      "help",
-	ShortName: "h",
+	Aliases:   []string{"h"},
 	Usage:     "Shows a list of commands or help for one command",
 	Usage:     "Shows a list of commands or help for one command",
+	ArgsUsage: "[command]",
 	Action: func(c *Context) {
 	Action: func(c *Context) {
 		args := c.Args()
 		args := c.Args()
 		if args.Present() {
 		if args.Present() {
@@ -81,8 +85,9 @@ var helpCommand = Command{
 
 
 var helpSubcommand = Command{
 var helpSubcommand = Command{
 	Name:      "help",
 	Name:      "help",
-	ShortName: "h",
+	Aliases:   []string{"h"},
 	Usage:     "Shows a list of commands or help for one command",
 	Usage:     "Shows a list of commands or help for one command",
+	ArgsUsage: "[command]",
 	Action: func(c *Context) {
 	Action: func(c *Context) {
 		args := c.Args()
 		args := c.Args()
 		if args.Present() {
 		if args.Present() {
@@ -93,45 +98,52 @@ var helpSubcommand = Command{
 	},
 	},
 }
 }
 
 
-// Prints help for the App
-var HelpPrinter = printHelp
+// Prints help for the App or Command
+type helpPrinter func(w io.Writer, templ string, data interface{})
+
+var HelpPrinter helpPrinter = printHelp
 
 
 // Prints version for the App
 // Prints version for the App
 var VersionPrinter = printVersion
 var VersionPrinter = printVersion
 
 
 func ShowAppHelp(c *Context) {
 func ShowAppHelp(c *Context) {
-	HelpPrinter(AppHelpTemplate, c.App)
+	HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
 }
 }
 
 
 // Prints the list of subcommands as the default app completion method
 // Prints the list of subcommands as the default app completion method
 func DefaultAppComplete(c *Context) {
 func DefaultAppComplete(c *Context) {
 	for _, command := range c.App.Commands {
 	for _, command := range c.App.Commands {
-		fmt.Println(command.Name)
-		if command.ShortName != "" {
-			fmt.Println(command.ShortName)
+		for _, name := range command.Names() {
+			fmt.Fprintln(c.App.Writer, name)
 		}
 		}
 	}
 	}
 }
 }
 
 
 // Prints help for the given command
 // Prints help for the given command
-func ShowCommandHelp(c *Context, command string) {
-	for _, c := range c.App.Commands {
+func ShowCommandHelp(ctx *Context, command string) {
+	// show the subcommand help for a command with subcommands
+	if command == "" {
+		HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
+		return
+	}
+
+	for _, c := range ctx.App.Commands {
 		if c.HasName(command) {
 		if c.HasName(command) {
-			HelpPrinter(CommandHelpTemplate, c)
+			HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
 			return
 			return
 		}
 		}
 	}
 	}
 
 
-	if c.App.CommandNotFound != nil {
-		c.App.CommandNotFound(c, command)
+	if ctx.App.CommandNotFound != nil {
+		ctx.App.CommandNotFound(ctx, command)
 	} else {
 	} else {
-		fmt.Printf("No help topic for '%v'\n", command)
+		fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command)
 	}
 	}
 }
 }
 
 
 // Prints help for the given subcommand
 // Prints help for the given subcommand
 func ShowSubcommandHelp(c *Context) {
 func ShowSubcommandHelp(c *Context) {
-	HelpPrinter(SubcommandHelpTemplate, c.App)
+	ShowCommandHelp(c, c.Command.Name)
 }
 }
 
 
 // Prints the version number of the App
 // Prints the version number of the App
@@ -140,7 +152,7 @@ func ShowVersion(c *Context) {
 }
 }
 
 
 func printVersion(c *Context) {
 func printVersion(c *Context) {
-	fmt.Printf("%v version %v\n", c.App.Name, c.App.Version)
+	fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
 }
 }
 
 
 // Prints the lists of commands within a given context
 // Prints the lists of commands within a given context
@@ -159,9 +171,13 @@ func ShowCommandCompletions(ctx *Context, command string) {
 	}
 	}
 }
 }
 
 
-func printHelp(templ string, data interface{}) {
-	w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
-	t := template.Must(template.New("help").Parse(templ))
+func printHelp(out io.Writer, templ string, data interface{}) {
+	funcMap := template.FuncMap{
+		"join": strings.Join,
+	}
+
+	w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
+	t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
 	err := t.Execute(w, data)
 	err := t.Execute(w, data)
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
@@ -170,21 +186,27 @@ func printHelp(templ string, data interface{}) {
 }
 }
 
 
 func checkVersion(c *Context) bool {
 func checkVersion(c *Context) bool {
-	if c.GlobalBool("version") {
-		ShowVersion(c)
-		return true
+	found := false
+	if VersionFlag.Name != "" {
+		eachName(VersionFlag.Name, func(name string) {
+			if c.GlobalBool(name) || c.Bool(name) {
+				found = true
+			}
+		})
 	}
 	}
-
-	return false
+	return found
 }
 }
 
 
 func checkHelp(c *Context) bool {
 func checkHelp(c *Context) bool {
-	if c.GlobalBool("h") || c.GlobalBool("help") {
-		ShowAppHelp(c)
-		return true
+	found := false
+	if HelpFlag.Name != "" {
+		eachName(HelpFlag.Name, func(name string) {
+			if c.GlobalBool(name) || c.Bool(name) {
+				found = true
+			}
+		})
 	}
 	}
-
-	return false
+	return found
 }
 }
 
 
 func checkCommandHelp(c *Context, name string) bool {
 func checkCommandHelp(c *Context, name string) bool {
@@ -206,7 +228,7 @@ func checkSubcommandHelp(c *Context) bool {
 }
 }
 
 
 func checkCompletions(c *Context) bool {
 func checkCompletions(c *Context) bool {
-	if c.GlobalBool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
+	if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
 		ShowCompletions(c)
 		ShowCompletions(c)
 		return true
 		return true
 	}
 	}

+ 0 - 19
Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go

@@ -1,19 +0,0 @@
-package cli_test
-
-import (
-	"reflect"
-	"testing"
-)
-
-/* Test Helpers */
-func expect(t *testing.T, a interface{}, b interface{}) {
-	if a != b {
-		t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
-	}
-}
-
-func refute(t *testing.T, a interface{}, b interface{}) {
-	if a == b {
-		t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
-	}
-}

+ 8 - 6
etcdctl/command/auth_commands.go

@@ -29,14 +29,16 @@ func NewAuthCommands() cli.Command {
 		Usage: "overall auth controls",
 		Usage: "overall auth controls",
 		Subcommands: []cli.Command{
 		Subcommands: []cli.Command{
 			{
 			{
-				Name:   "enable",
-				Usage:  "enable auth access controls",
-				Action: actionAuthEnable,
+				Name:      "enable",
+				Usage:     "enable auth access controls",
+				ArgsUsage: " ",
+				Action:    actionAuthEnable,
 			},
 			},
 			{
 			{
-				Name:   "disable",
-				Usage:  "disable auth access controls",
-				Action: actionAuthDisable,
+				Name:      "disable",
+				Usage:     "disable auth access controls",
+				ArgsUsage: " ",
+				Action:    actionAuthDisable,
 			},
 			},
 		},
 		},
 	}
 	}

+ 3 - 2
etcdctl/command/backup_command.go

@@ -32,8 +32,9 @@ import (
 
 
 func NewBackupCommand() cli.Command {
 func NewBackupCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "backup",
-		Usage: "backup an etcd directory",
+		Name:      "backup",
+		Usage:     "backup an etcd directory",
+		ArgsUsage: " ",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.StringFlag{Name: "data-dir", Value: "", Usage: "Path to the etcd data dir"},
 			cli.StringFlag{Name: "data-dir", Value: "", Usage: "Path to the etcd data dir"},
 			cli.StringFlag{Name: "backup-dir", Value: "", Usage: "Path to the backup dir"},
 			cli.StringFlag{Name: "backup-dir", Value: "", Usage: "Path to the backup dir"},

+ 3 - 2
etcdctl/command/cluster_health.go

@@ -30,8 +30,9 @@ import (
 
 
 func NewClusterHealthCommand() cli.Command {
 func NewClusterHealthCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "cluster-health",
-		Usage: "check the health of the etcd cluster",
+		Name:      "cluster-health",
+		Usage:     "check the health of the etcd cluster",
+		ArgsUsage: " ",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.BoolFlag{Name: "forever", Usage: "forever check the health every 10 second until CTRL+C"},
 			cli.BoolFlag{Name: "forever", Usage: "forever check the health every 10 second until CTRL+C"},
 		},
 		},

+ 3 - 2
etcdctl/command/exec_watch_command.go

@@ -30,8 +30,9 @@ import (
 // NewExecWatchCommand returns the CLI command for "exec-watch".
 // NewExecWatchCommand returns the CLI command for "exec-watch".
 func NewExecWatchCommand() cli.Command {
 func NewExecWatchCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "exec-watch",
-		Usage: "watch a key for changes and exec an executable",
+		Name:      "exec-watch",
+		Usage:     "watch a key for changes and exec an executable",
+		ArgsUsage: "<key> <command> [args...]",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
 			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
 			cli.BoolFlag{Name: "recursive", Usage: "watch all values for key and child keys"},
 			cli.BoolFlag{Name: "recursive", Usage: "watch all values for key and child keys"},

+ 3 - 2
etcdctl/command/get_command.go

@@ -26,8 +26,9 @@ import (
 // NewGetCommand returns the CLI command for "get".
 // NewGetCommand returns the CLI command for "get".
 func NewGetCommand() cli.Command {
 func NewGetCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "get",
-		Usage: "retrieve the value of a key",
+		Name:      "get",
+		Usage:     "retrieve the value of a key",
+		ArgsUsage: "<key>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.BoolFlag{Name: "sort", Usage: "returns result in sorted order"},
 			cli.BoolFlag{Name: "sort", Usage: "returns result in sorted order"},
 			cli.BoolFlag{Name: "quorum", Usage: "require quorum for get request"},
 			cli.BoolFlag{Name: "quorum", Usage: "require quorum for get request"},

+ 3 - 2
etcdctl/command/import_snap_command.go

@@ -36,8 +36,9 @@ type set struct {
 
 
 func NewImportSnapCommand() cli.Command {
 func NewImportSnapCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "import",
-		Usage: "import a snapshot to a cluster",
+		Name:      "import",
+		Usage:     "import a snapshot to a cluster",
+		ArgsUsage: " ",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.StringFlag{Name: "snap", Value: "", Usage: "Path to the valid etcd 0.4.x snapshot."},
 			cli.StringFlag{Name: "snap", Value: "", Usage: "Path to the valid etcd 0.4.x snapshot."},
 			cli.StringSliceFlag{Name: "hidden", Value: new(cli.StringSlice), Usage: "Hidden key spaces to import from snapshot"},
 			cli.StringSliceFlag{Name: "hidden", Value: new(cli.StringSlice), Usage: "Hidden key spaces to import from snapshot"},

+ 3 - 2
etcdctl/command/ls_command.go

@@ -23,8 +23,9 @@ import (
 
 
 func NewLsCommand() cli.Command {
 func NewLsCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "ls",
-		Usage: "retrieve a directory",
+		Name:      "ls",
+		Usage:     "retrieve a directory",
+		ArgsUsage: "[key]",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.BoolFlag{Name: "sort", Usage: "returns result in sorted order"},
 			cli.BoolFlag{Name: "sort", Usage: "returns result in sorted order"},
 			cli.BoolFlag{Name: "recursive", Usage: "returns all key names recursively for the given path"},
 			cli.BoolFlag{Name: "recursive", Usage: "returns all key names recursively for the given path"},

+ 16 - 12
etcdctl/command/member_commands.go

@@ -28,24 +28,28 @@ func NewMemberCommand() cli.Command {
 		Usage: "member add, remove and list subcommands",
 		Usage: "member add, remove and list subcommands",
 		Subcommands: []cli.Command{
 		Subcommands: []cli.Command{
 			{
 			{
-				Name:   "list",
-				Usage:  "enumerate existing cluster members",
-				Action: actionMemberList,
+				Name:      "list",
+				Usage:     "enumerate existing cluster members",
+				ArgsUsage: " ",
+				Action:    actionMemberList,
 			},
 			},
 			{
 			{
-				Name:   "add",
-				Usage:  "add a new member to the etcd cluster",
-				Action: actionMemberAdd,
+				Name:      "add",
+				Usage:     "add a new member to the etcd cluster",
+				ArgsUsage: "<name> <peerURL>",
+				Action:    actionMemberAdd,
 			},
 			},
 			{
 			{
-				Name:   "remove",
-				Usage:  "remove an existing member from the etcd cluster",
-				Action: actionMemberRemove,
+				Name:      "remove",
+				Usage:     "remove an existing member from the etcd cluster",
+				ArgsUsage: "<memberID>",
+				Action:    actionMemberRemove,
 			},
 			},
 			{
 			{
-				Name:   "update",
-				Usage:  "update an existing member in the etcd cluster",
-				Action: actionMemberUpdate,
+				Name:      "update",
+				Usage:     "update an existing member in the etcd cluster",
+				ArgsUsage: "<memberID> <peerURLs>",
+				Action:    actionMemberUpdate,
 			},
 			},
 		},
 		},
 	}
 	}

+ 3 - 2
etcdctl/command/mk_command.go

@@ -26,8 +26,9 @@ import (
 // NewMakeCommand returns the CLI command for "mk".
 // NewMakeCommand returns the CLI command for "mk".
 func NewMakeCommand() cli.Command {
 func NewMakeCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "mk",
-		Usage: "make a new key with a given value",
+		Name:      "mk",
+		Usage:     "make a new key with a given value",
+		ArgsUsage: "<key> <value>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 		},
 		},

+ 3 - 2
etcdctl/command/mkdir_command.go

@@ -25,8 +25,9 @@ import (
 // NewMakeDirCommand returns the CLI command for "mkdir".
 // NewMakeDirCommand returns the CLI command for "mkdir".
 func NewMakeDirCommand() cli.Command {
 func NewMakeDirCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "mkdir",
-		Usage: "make a new directory",
+		Name:      "mkdir",
+		Usage:     "make a new directory",
+		ArgsUsage: "<key>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 		},
 		},

+ 3 - 2
etcdctl/command/rm_command.go

@@ -24,8 +24,9 @@ import (
 // NewRemoveCommand returns the CLI command for "rm".
 // NewRemoveCommand returns the CLI command for "rm".
 func NewRemoveCommand() cli.Command {
 func NewRemoveCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "rm",
-		Usage: "remove a key or a directory",
+		Name:      "rm",
+		Usage:     "remove a key or a directory",
+		ArgsUsage: "<key>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.BoolFlag{Name: "dir", Usage: "removes the key if it is an empty directory or a key-value pair"},
 			cli.BoolFlag{Name: "dir", Usage: "removes the key if it is an empty directory or a key-value pair"},
 			cli.BoolFlag{Name: "recursive", Usage: "removes the key and all child keys(if it is a directory)"},
 			cli.BoolFlag{Name: "recursive", Usage: "removes the key and all child keys(if it is a directory)"},

+ 3 - 2
etcdctl/command/rmdir_command.go

@@ -24,8 +24,9 @@ import (
 // NewRemoveCommand returns the CLI command for "rmdir".
 // NewRemoveCommand returns the CLI command for "rmdir".
 func NewRemoveDirCommand() cli.Command {
 func NewRemoveDirCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "rmdir",
-		Usage: "removes the key if it is an empty directory or a key-value pair",
+		Name:      "rmdir",
+		Usage:     "removes the key if it is an empty directory or a key-value pair",
+		ArgsUsage: "<key>",
 		Action: func(c *cli.Context) {
 		Action: func(c *cli.Context) {
 			rmdirCommandFunc(c, mustNewKeyAPI(c))
 			rmdirCommandFunc(c, mustNewKeyAPI(c))
 		},
 		},

+ 22 - 16
etcdctl/command/role_commands.go

@@ -31,28 +31,33 @@ func NewRoleCommands() cli.Command {
 		Usage: "role add, grant and revoke subcommands",
 		Usage: "role add, grant and revoke subcommands",
 		Subcommands: []cli.Command{
 		Subcommands: []cli.Command{
 			{
 			{
-				Name:   "add",
-				Usage:  "add a new role for the etcd cluster",
-				Action: actionRoleAdd,
+				Name:      "add",
+				Usage:     "add a new role for the etcd cluster",
+				ArgsUsage: "<role> ",
+				Action:    actionRoleAdd,
 			},
 			},
 			{
 			{
-				Name:   "get",
-				Usage:  "get details for a role",
-				Action: actionRoleGet,
+				Name:      "get",
+				Usage:     "get details for a role",
+				ArgsUsage: "<role>",
+				Action:    actionRoleGet,
 			},
 			},
 			{
 			{
-				Name:   "list",
-				Usage:  "list all roles",
-				Action: actionRoleList,
+				Name:      "list",
+				Usage:     "list all roles",
+				ArgsUsage: " ",
+				Action:    actionRoleList,
 			},
 			},
 			{
 			{
-				Name:   "remove",
-				Usage:  "remove a role from the etcd cluster",
-				Action: actionRoleRemove,
+				Name:      "remove",
+				Usage:     "remove a role from the etcd cluster",
+				ArgsUsage: "<role>",
+				Action:    actionRoleRemove,
 			},
 			},
 			{
 			{
-				Name:  "grant",
-				Usage: "grant path matches to an etcd role",
+				Name:      "grant",
+				Usage:     "grant path matches to an etcd role",
+				ArgsUsage: "<role>",
 				Flags: []cli.Flag{
 				Flags: []cli.Flag{
 					cli.StringFlag{Name: "path", Value: "", Usage: "Path granted for the role to access"},
 					cli.StringFlag{Name: "path", Value: "", Usage: "Path granted for the role to access"},
 					cli.BoolFlag{Name: "read", Usage: "Grant read-only access"},
 					cli.BoolFlag{Name: "read", Usage: "Grant read-only access"},
@@ -62,8 +67,9 @@ func NewRoleCommands() cli.Command {
 				Action: actionRoleGrant,
 				Action: actionRoleGrant,
 			},
 			},
 			{
 			{
-				Name:  "revoke",
-				Usage: "revoke path matches for an etcd role",
+				Name:      "revoke",
+				Usage:     "revoke path matches for an etcd role",
+				ArgsUsage: "<role>",
 				Flags: []cli.Flag{
 				Flags: []cli.Flag{
 					cli.StringFlag{Name: "path", Value: "", Usage: "Path revoked for the role to access"},
 					cli.StringFlag{Name: "path", Value: "", Usage: "Path revoked for the role to access"},
 					cli.BoolFlag{Name: "read", Usage: "Revoke read access"},
 					cli.BoolFlag{Name: "read", Usage: "Revoke read access"},

+ 3 - 2
etcdctl/command/set_command.go

@@ -26,8 +26,9 @@ import (
 // NewSetCommand returns the CLI command for "set".
 // NewSetCommand returns the CLI command for "set".
 func NewSetCommand() cli.Command {
 func NewSetCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "set",
-		Usage: "set the value of a key",
+		Name:      "set",
+		Usage:     "set the value of a key",
+		ArgsUsage: "<key> <value>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.StringFlag{Name: "swap-with-value", Value: "", Usage: "previous value"},
 			cli.StringFlag{Name: "swap-with-value", Value: "", Usage: "previous value"},

+ 3 - 2
etcdctl/command/set_dir_command.go

@@ -22,8 +22,9 @@ import (
 // NewSetDirCommand returns the CLI command for "setDir".
 // NewSetDirCommand returns the CLI command for "setDir".
 func NewSetDirCommand() cli.Command {
 func NewSetDirCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "setdir",
-		Usage: "create a new or existing directory",
+		Name:      "setdir",
+		Usage:     "create a new or existing directory",
+		ArgsUsage: "<key>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 		},
 		},

+ 3 - 2
etcdctl/command/update_command.go

@@ -26,8 +26,9 @@ import (
 // NewUpdateCommand returns the CLI command for "update".
 // NewUpdateCommand returns the CLI command for "update".
 func NewUpdateCommand() cli.Command {
 func NewUpdateCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "update",
-		Usage: "update an existing key with a given value",
+		Name:      "update",
+		Usage:     "update an existing key with a given value",
+		ArgsUsage: "<key> <value>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 		},
 		},

+ 3 - 2
etcdctl/command/update_dir_command.go

@@ -26,8 +26,9 @@ import (
 // NewUpdateDirCommand returns the CLI command for "updatedir".
 // NewUpdateDirCommand returns the CLI command for "updatedir".
 func NewUpdateDirCommand() cli.Command {
 func NewUpdateDirCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "updatedir",
-		Usage: "update an existing directory",
+		Name:      "updatedir",
+		Usage:     "update an existing directory",
+		ArgsUsage: "<key> <value>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live"},
 		},
 		},

+ 30 - 23
etcdctl/command/user_commands.go

@@ -32,41 +32,48 @@ func NewUserCommands() cli.Command {
 		Usage: "user add, grant and revoke subcommands",
 		Usage: "user add, grant and revoke subcommands",
 		Subcommands: []cli.Command{
 		Subcommands: []cli.Command{
 			{
 			{
-				Name:   "add",
-				Usage:  "add a new user for the etcd cluster",
-				Action: actionUserAdd,
+				Name:      "add",
+				Usage:     "add a new user for the etcd cluster",
+				ArgsUsage: "<user>",
+				Action:    actionUserAdd,
 			},
 			},
 			{
 			{
-				Name:   "get",
-				Usage:  "get details for a user",
-				Action: actionUserGet,
+				Name:      "get",
+				Usage:     "get details for a user",
+				ArgsUsage: "<user>",
+				Action:    actionUserGet,
 			},
 			},
 			{
 			{
-				Name:   "list",
-				Usage:  "list all current users",
-				Action: actionUserList,
+				Name:      "list",
+				Usage:     "list all current users",
+				ArgsUsage: "<user>",
+				Action:    actionUserList,
 			},
 			},
 			{
 			{
-				Name:   "remove",
-				Usage:  "remove a user for the etcd cluster",
-				Action: actionUserRemove,
+				Name:      "remove",
+				Usage:     "remove a user for the etcd cluster",
+				ArgsUsage: "<user>",
+				Action:    actionUserRemove,
 			},
 			},
 			{
 			{
-				Name:   "grant",
-				Usage:  "grant roles to an etcd user",
-				Flags:  []cli.Flag{cli.StringSliceFlag{Name: "roles", Value: new(cli.StringSlice), Usage: "List of roles to grant or revoke"}},
-				Action: actionUserGrant,
+				Name:      "grant",
+				Usage:     "grant roles to an etcd user",
+				ArgsUsage: "<user>",
+				Flags:     []cli.Flag{cli.StringSliceFlag{Name: "roles", Value: new(cli.StringSlice), Usage: "List of roles to grant or revoke"}},
+				Action:    actionUserGrant,
 			},
 			},
 			{
 			{
-				Name:   "revoke",
-				Usage:  "revoke roles for an etcd user",
-				Flags:  []cli.Flag{cli.StringSliceFlag{Name: "roles", Value: new(cli.StringSlice), Usage: "List of roles to grant or revoke"}},
-				Action: actionUserRevoke,
+				Name:      "revoke",
+				Usage:     "revoke roles for an etcd user",
+				ArgsUsage: "<user>",
+				Flags:     []cli.Flag{cli.StringSliceFlag{Name: "roles", Value: new(cli.StringSlice), Usage: "List of roles to grant or revoke"}},
+				Action:    actionUserRevoke,
 			},
 			},
 			{
 			{
-				Name:   "passwd",
-				Usage:  "change password for a user",
-				Action: actionUserPasswd,
+				Name:      "passwd",
+				Usage:     "change password for a user",
+				ArgsUsage: "<user>",
+				Action:    actionUserPasswd,
 			},
 			},
 		},
 		},
 	}
 	}

+ 3 - 2
etcdctl/command/watch_command.go

@@ -28,8 +28,9 @@ import (
 // NewWatchCommand returns the CLI command for "watch".
 // NewWatchCommand returns the CLI command for "watch".
 func NewWatchCommand() cli.Command {
 func NewWatchCommand() cli.Command {
 	return cli.Command{
 	return cli.Command{
-		Name:  "watch",
-		Usage: "watch a key for changes",
+		Name:      "watch",
+		Usage:     "watch a key for changes",
+		ArgsUsage: "<key>",
 		Flags: []cli.Flag{
 		Flags: []cli.Flag{
 			cli.BoolFlag{Name: "forever", Usage: "forever watch a key until CTRL+C"},
 			cli.BoolFlag{Name: "forever", Usage: "forever watch a key until CTRL+C"},
 			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},
 			cli.IntFlag{Name: "after-index", Value: 0, Usage: "watch after the given index"},