open-vault/Godeps/_workspace/src/github.com/mitchellh/cli/cli.go

186 lines
4.5 KiB
Go
Raw Normal View History

2015-04-27 23:19:51 +00:00
package cli
import (
"io"
"os"
"sync"
)
// CLI contains the state necessary to run subcommands and parse the
// command line arguments.
type CLI struct {
// Args is the list of command-line arguments received excluding
// the name of the app. For example, if the command "./cli foo bar"
// was invoked, then Args should be []string{"foo", "bar"}.
Args []string
// Commands is a mapping of subcommand names to a factory function
2015-06-29 22:05:44 +00:00
// for creating that Command implementation. If there is a command
// with a blank string "", then it will be used as the default command
// if no subcommand is specified.
2015-04-27 23:19:51 +00:00
Commands map[string]CommandFactory
// Name defines the name of the CLI.
Name string
// Version of the CLI.
Version string
// HelpFunc and HelpWriter are used to output help information, if
// requested.
//
// HelpFunc is the function called to generate the generic help
// text that is shown if help must be shown for the CLI that doesn't
// pertain to a specific command.
//
// HelpWriter is the Writer where the help text is outputted to. If
// not specified, it will default to Stderr.
HelpFunc HelpFunc
HelpWriter io.Writer
once sync.Once
isHelp bool
subcommand string
subcommandArgs []string
2015-06-29 22:05:44 +00:00
topFlags []string
2015-04-27 23:19:51 +00:00
isVersion bool
}
// NewClI returns a new CLI instance with sensible defaults.
func NewCLI(app, version string) *CLI {
return &CLI{
Name: app,
Version: version,
HelpFunc: BasicHelpFunc(app),
}
}
// IsHelp returns whether or not the help flag is present within the
// arguments.
func (c *CLI) IsHelp() bool {
c.once.Do(c.init)
return c.isHelp
}
// IsVersion returns whether or not the version flag is present within the
// arguments.
func (c *CLI) IsVersion() bool {
c.once.Do(c.init)
return c.isVersion
}
// Run runs the actual CLI based on the arguments given.
func (c *CLI) Run() (int, error) {
c.once.Do(c.init)
// Just show the version and exit if instructed.
if c.IsVersion() && c.Version != "" {
c.HelpWriter.Write([]byte(c.Version + "\n"))
return 1, nil
}
2015-06-29 22:05:44 +00:00
// If there is an invalid flag, then error
if len(c.topFlags) > 0 {
c.HelpWriter.Write([]byte(
"Invalid flags before the subcommand. If these flags are for\n" +
"the subcommand, please put them after the subcommand.\n\n"))
c.HelpWriter.Write([]byte(c.HelpFunc(c.Commands) + "\n"))
return 1, nil
}
2015-04-27 23:19:51 +00:00
// Attempt to get the factory function for creating the command
// implementation. If the command is invalid or blank, it is an error.
commandFunc, ok := c.Commands[c.Subcommand()]
2015-06-29 22:05:44 +00:00
if !ok {
2015-04-27 23:19:51 +00:00
c.HelpWriter.Write([]byte(c.HelpFunc(c.Commands) + "\n"))
return 1, nil
}
command, err := commandFunc()
if err != nil {
return 0, err
}
// If we've been instructed to just print the help, then print it
if c.IsHelp() {
c.HelpWriter.Write([]byte(command.Help() + "\n"))
return 1, nil
}
return command.Run(c.SubcommandArgs()), nil
}
// Subcommand returns the subcommand that the CLI would execute. For
// example, a CLI from "--version version --help" would return a Subcommand
// of "version"
func (c *CLI) Subcommand() string {
c.once.Do(c.init)
return c.subcommand
}
// SubcommandArgs returns the arguments that will be passed to the
// subcommand.
func (c *CLI) SubcommandArgs() []string {
c.once.Do(c.init)
return c.subcommandArgs
}
func (c *CLI) init() {
if c.HelpFunc == nil {
c.HelpFunc = BasicHelpFunc("app")
if c.Name != "" {
c.HelpFunc = BasicHelpFunc(c.Name)
}
}
if c.HelpWriter == nil {
c.HelpWriter = os.Stderr
}
c.processArgs()
}
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 == "-h" || arg == "-help" || arg == "--help" {
c.isHelp = true
continue
}
2015-06-29 22:05:44 +00:00
if arg != "" && arg[0] == '-' {
// Record the arg...
c.topFlags = append(c.topFlags, arg)
}
2015-04-27 23:19:51 +00:00
}
// If we didn't find a subcommand yet and this is the first non-flag
// argument, then this is our subcommand. j
2015-06-29 22:05:44 +00:00
if c.subcommand == "" && arg != "" && arg[0] != '-' {
2015-04-27 23:19:51 +00:00
c.subcommand = arg
// The remaining args the subcommand arguments
c.subcommandArgs = c.Args[i+1:]
}
}
2015-06-29 22:05:44 +00:00
// If we never found a subcommand and support a default command, then
// switch to using that.
if c.subcommand == "" {
if _, ok := c.Commands[""]; ok {
args := c.topFlags
args = append(args, c.subcommandArgs...)
c.topFlags = nil
c.subcommandArgs = args
}
}
2015-04-27 23:19:51 +00:00
}