update cli library

This commit is contained in:
Matthew Hooker 2017-03-27 23:13:26 -07:00
parent 064576fdde
commit 83bf5e67a9
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
4 changed files with 54 additions and 24 deletions

View File

@ -3,8 +3,11 @@
cli is a library for implementing powerful command-line interfaces in Go.
cli is the library that powers the CLI for
[Packer](https://github.com/mitchellh/packer),
[Serf](https://github.com/hashicorp/serf), and
[Consul](https://github.com/hashicorp/consul).
[Serf](https://github.com/hashicorp/serf),
[Consul](https://github.com/hashicorp/consul),
[Vault](https://github.com/hashicorp/vault),
[Terraform](https://github.com/hashicorp/terraform), and
[Nomad](https://github.com/hashicorp/nomad).
## Features

View File

@ -4,6 +4,7 @@ import (
"fmt"
"io"
"os"
"regexp"
"sort"
"strings"
"sync"
@ -24,7 +25,7 @@ import (
//
// * We use longest prefix matching to find a matching subcommand. This
// means if you register "foo bar" and the user executes "cli foo qux",
// the "foo" commmand will be executed with the arg "qux". It is up to
// the "foo" command will be executed with the arg "qux". It is up to
// you to handle these args. One option is to just return the special
// help return code `RunResultHelp` to display help and exit.
//
@ -119,7 +120,13 @@ func (c *CLI) Run() (int, error) {
// Just show the version and exit if instructed.
if c.IsVersion() && c.Version != "" {
c.HelpWriter.Write([]byte(c.Version + "\n"))
return 1, nil
return 0, nil
}
// Just print the help when only '-h' or '--help' is passed.
if c.IsHelp() && c.Subcommand() == "" {
c.HelpWriter.Write([]byte(c.HelpFunc(c.Commands) + "\n"))
return 0, nil
}
// Attempt to get the factory function for creating the command
@ -132,13 +139,13 @@ func (c *CLI) Run() (int, error) {
command, err := raw.(CommandFactory)()
if err != nil {
return 0, err
return 1, err
}
// If we've been instructed to just print the help, then print it
if c.IsHelp() {
c.commandHelp(command)
return 1, nil
return 0, nil
}
// If there is an invalid flag, then error
@ -249,7 +256,7 @@ func (c *CLI) init() {
c.commandTree.Walk(walkFn)
// Insert any that we're missing
for k, _ := range toInsert {
for k := range toInsert {
var f CommandFactory = func() (Command, error) {
return &MockCommand{
HelpText: "This command is accessed by using one of the subcommands below.",
@ -294,7 +301,7 @@ func (c *CLI) commandHelp(command Command) {
// Get the matching keys
subcommands := c.helpCommands(c.Subcommand())
keys := make([]string, 0, len(subcommands))
for k, _ := range subcommands {
for k := range subcommands {
keys = append(keys, k)
}
@ -311,8 +318,13 @@ func (c *CLI) commandHelp(command Command) {
// Go through and create their structures
subcommandsTpl = make([]map[string]interface{}, 0, len(subcommands))
for k, raw := range subcommands {
for _, k := range keys {
// Get the command
raw, ok := subcommands[k]
if !ok {
c.HelpWriter.Write([]byte(fmt.Sprintf(
"Error getting subcommand %q", k)))
}
sub, err := raw()
if err != nil {
c.HelpWriter.Write([]byte(fmt.Sprintf(
@ -382,17 +394,23 @@ func (c *CLI) helpCommands(prefix string) map[string]CommandFactory {
func (c *CLI) processArgs() {
for i, arg := range c.Args {
if c.subcommand == "" {
// Check for version and help flags if not in a subcommand
if arg == "-v" || arg == "-version" || arg == "--version" {
c.isVersion = true
continue
if arg == "--" {
break
}
// Check for help flags.
if arg == "-h" || arg == "-help" || arg == "--help" {
c.isHelp = true
continue
}
if c.subcommand == "" {
// Check for version flags if not in a subcommand.
if arg == "-v" || arg == "-version" || arg == "--version" {
c.isVersion = true
continue
}
if arg != "" && arg[0] == '-' {
// Record the arg...
c.topFlags = append(c.topFlags, arg)
@ -400,18 +418,26 @@ func (c *CLI) processArgs() {
}
// If we didn't find a subcommand yet and this is the first non-flag
// argument, then this is our subcommand. j
// argument, then this is our subcommand.
if c.subcommand == "" && arg != "" && arg[0] != '-' {
c.subcommand = arg
if c.commandNested {
// Nested CLI, the subcommand is actually the entire
// arg list up to a flag that is still a valid subcommand.
k, _, ok := c.commandTree.LongestPrefix(strings.Join(c.Args[i:], " "))
searchKey := strings.Join(c.Args[i:], " ")
k, _, ok := c.commandTree.LongestPrefix(searchKey)
if ok {
// k could be a prefix that doesn't contain the full
// command such as "foo" instead of "foobar", so we
// need to verify that we have an entire key. To do that,
// we look for an ending in a space or an end of string.
reVerify := regexp.MustCompile(regexp.QuoteMeta(k) + `( |$)`)
if reVerify.MatchString(searchKey) {
c.subcommand = k
i += strings.Count(k, " ")
}
}
}
// The remaining args the subcommand arguments
c.subcommandArgs = c.Args[i+1:]
@ -434,7 +460,7 @@ const defaultHelpTemplate = `
{{.Help}}{{if gt (len .Subcommands) 0}}
Subcommands:
{{ range $value := .Subcommands }}
{{- range $value := .Subcommands }}
{{ $value.NameAligned }} {{ $value.Synopsis }}{{ end }}
{{ end }}
{{- end }}
`

View File

@ -18,7 +18,7 @@ func BasicHelpFunc(app string) HelpFunc {
return func(commands map[string]CommandFactory) string {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf(
"usage: %s [--version] [--help] <command> [<args>]\n\n",
"Usage: %s [--version] [--help] <command> [<args>]\n\n",
app))
buf.WriteString("Available commands are:\n")
@ -26,7 +26,7 @@ func BasicHelpFunc(app string) HelpFunc {
// key length so they can be aligned properly.
keys := make([]string, 0, len(commands))
maxKeyLen := 0
for key, _ := range commands {
for key := range commands {
if len(key) > maxKeyLen {
maxKeyLen = len(key)
}

5
vendor/vendor.json vendored
View File

@ -596,9 +596,10 @@
"revision": "56b76bdf51f7708750eac80fa38b952bb9f32639"
},
{
"checksumSHA1": "WbXdGQiD4hQNID4Xo/RJumaimk0=",
"checksumSHA1": "UP+pXl+ic9y6qrpZA5MqDIAuGfw=",
"path": "github.com/mitchellh/cli",
"revision": "5c87c51cedf76a1737bf5ca3979e8644871598a6"
"revision": "ee8578a9c12a5bb9d55303b9665cc448772c81b8",
"revisionTime": "2017-03-28T05:23:52Z"
},
{
"checksumSHA1": "mVqDwKcibat0IKAdzAhfGIHPwI8=",