Documentation
¶
Overview ¶
Package clicommand provides CLI applications with subcommand/api-style interfaces and option/parameter handling
The clicommand library makes the creation of Go CLI applications using a subcommand interface easier. The subcommand interface is structured as a parent/child tree so the application can mimic an api, with edges of the tree running custom Handler functions and the tree providing a structured way of grouping commands, attaching option arguments and finding additional parameters.
Command Tree ¶
Command objects are chained together to build a tree which has arbitrary depth, providing it follows the tree rules:
Each parent Command object within the tree may have any number of children. Each child Command object within the tree has a single parent. Every child Command object within the tree can have its own children, except when it has a Handler function.
CLI Application Pseudo Example ¶
This allows building a CLI application which can mimic an API, e.g.:
./clicommand // parent, has children ./clicommand http // child of clicommand, has children itself ./clicommand http get => Handler() // child of clicommand->http, calls Handler() when run. // Cannot have children. ./clicommand http post => Handler() // child of clicommand->http, calls Handler() when run. // Cannot have children.
CLI Options ¶
Options can be attached to the tree at any point and these are inherited along the tree, so child commands also have options from their parent commands. Options are defined as either having or not having parameters, options with parameters use double dashes and options without parameters use single dashes as selectors.
CLI Parameters ¶
Anything the parser doesnt recognise is stored as a parameter, alloowing applications to accept things as a simple parameter, rather than requiring its specified as an option.
Autogenerated Help ¶
As each command and option is added to the tree with a name and description, the parser can automatically construct help information and display it when the program is run without parameters, or the 'help' command is used. The following example uses the sample helloworld program from https://git.io/vNDug
[golang@908222b2e8aa helloworld]$ ./helloworld help helloworld - Sample hello world program helloworld [-u] [-lower] helloworld options: -u Uppercase output -lower Lowercase output Available subcommands: hello Says hello world say Says something For help information run: 'helloworld help' .. 'helloworld <commands>* help' .. 'helloworld [commands]* help [subcommand]*'
Sample Program ¶
This is a sample program built using this module.
Example ¶
This is an example hello world program built using https://github.com/leehuk/go-clicommand It creates a program with a subcommand "hello", which has two subcommands "world" and "say". Both commands have shared options "-u" to uppercase the output, and "-lower" to lowercase the output.
package main /* This program could be called with the following examples: ./command hello world Outputs: "Hello, world!" ./command hello -u world Outputs: "HELLO, WORLD!" ./command hello world -lower Outputs : "hello, world!" ./command hello say -u --say "This is a test" Outputs: "THIS IS A TEST" ./command ./command help ./command hello help ./command hello world help Outputs: Autogenerated help information ./command hello Returns error as no subcommand specified. ./command hello say Returns error as "--say" option not specified. ./command -u hello world Returns error as "-u" option is not in global scope */ import ( "fmt" "os" "strings" "github.com/leehuk/go-clicommand" ) // getTextWithOptions is a simple helper function, that uses data.Options["u"] // as a control to uppercase the string, data.Options["lower"] as a control // to lowercase the string, or otherwise returns the string as-is func getTextWithOptions(text string, data *clicommand.Data) string { if _, ok := data.Options["u"]; ok { return strings.ToUpper(text) } else if _, ok := data.Options["lower"]; ok { return strings.ToLower(text) } return text } // sayHelloWorld Handler function for "hello" -> "world" command. Says // "Hello, world!" func sayHelloWorld(data *clicommand.Data) error { var text = getTextWithOptions("Hello, world!", data) fmt.Printf("%s\n", text) return nil } // sayHelloSomething Handler function for "hello" -> "say" command. Says // whatever is specified in data.Options["say"] func sayHelloSomething(data *clicommand.Data) error { var text = getTextWithOptions(data.Options["say"], data) fmt.Printf("%s\n", text) return nil } // This is an example hello world program built using https://github.com/leehuk/go-clicommand // It creates a program with a subcommand "hello", which has two subcommands "world" // and "say". Both commands have shared options "-u" to uppercase the output, and // "-lower" to lowercase the output. func main() { // Our root command for the tree. handler is specified as nil, as this // will have children. cliRoot := clicommand.NewCommand("hw", "Sample hello world program", nil) // Create a hello command off our root object cliHello := cliRoot.NewCommand("hello", "Hello saying options", nil) // These options are available to all subcommands of hello cliHello.NewOption("u", "Uppercase output", false) cliHello.NewOption("lower", "Lowercase output", false) // Create child of hello, world cliHello.NewCommand("world", "Says hello world", sayHelloWorld) // Create child command of hello, say cliHelloSomething := cliHello.NewCommand("say", "Says something", sayHelloSomething) // Create a required option to hello say, with a parameter cliHelloSomething.NewOption("say", "Thing to say", true).SetRequired() if error := cliRoot.Parse(); error != nil { fmt.Printf("%v\n", error) os.Exit(1) } }
Output:
Index ¶
- type Command
- func (c *Command) BindCallback(handler Handler)
- func (c *Command) BindCallbackPre(handler Handler)
- func (c *Command) BindCommand(cmdv ...*Command)
- func (c *Command) BindOption(optionv ...*Option)
- func (c *Command) GetCommand(name string) *Command
- func (c *Command) GetNameChain() string
- func (c *Command) GetNameTop() string
- func (c *Command) GetOption(name string, param bool) *Option
- func (c *Command) NewCommand(name string, desc string, handler Handler) *Command
- func (c *Command) NewOption(name string, desc string, param bool) *Option
- func (c *Command) Parse() error
- func (c *Command) UnbindOption(optionv ...*Option)
- type Data
- type ErrCallback
- type ErrCallbackPre
- type ErrCommandError
- type ErrCommandInvalid
- type ErrCommandMissing
- type ErrOptionMissing
- type ErrOptionMissingParam
- type ErrOptionUnknown
- type Handler
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Command ¶
type Command struct { // Name Name of subcommand Name string // Desc Description of subcommand Desc string // Handler Handler function subcommand calls, nil for subcommands with children Handler Handler // Parent Command object thats the parent of this one Parent *Command // Children Command objects that are children of this one Children []*Command // Options Option arguments Options []*Option // Callbackspre Callbacks to run pre-verification Callbackspre []Handler // Callbacks Callbacks to run as part of verification Callbacks []Handler }
A Command represents a command of the cli program. These are chained into a tree with links in both child and parent directions
Each child can itself be a parent, but only leaf nodes (children with no children) can have handler functions, e.g.
clicommand --> clicommand api --> clicommand api get ==> handler clicommand api delete ==> handler
func NewCommand ¶
NewCommand creates a new command, unbound to parents. This is generally only used for creating the root object as after that, the func (c *Command) NewCommand() variant is easier, as it automatically binds the child Command.
handler must be nil if this command will have its own children.
func (*Command) BindCallback ¶
BindCallback binds a validation callback, that can be used to add extra validation around commands and options.
Callbacks are processed starting at the leaf, moving up to the root. Only callbacks directly along that path are executed.
func (*Command) BindCallbackPre ¶
BindCallbackPre binds a pre-validation callback, that can be used to alter the user-provided options and Command tree prior to validation. This can be useful for things like translating environment variables into options, or making options required/not-required for certain commands.
Callbacks are processed starting at the leaf, moving up to the root. Only callbacks directly on that path are executed.
func (*Command) BindCommand ¶
BindCommand binds a series of subcommands as children. Links are placed in both directions, from parent -> child and child -> parent.
If the parent already has a handler set, this will panic.
func (*Command) BindOption ¶
BindOption binds an Option as a child.
func (*Command) GetCommand ¶
GetCommand finds a child Command with the given name, or nil if not found. name matches are case-insensitive.
func (*Command) GetNameChain ¶
GetNameChain builds a space separated string of all Command names from itself up to the root.
func (*Command) GetNameTop ¶
GetNameTop finds the name of the root Command.
func (*Command) GetOption ¶
GetOption finds an child Option with the given name and the same parameter, searching the entire way up the tree to the root if necessary.
func (*Command) NewCommand ¶
NewCommand creates a new Command and automatically binds it as a child.
If the new Command will also have its own children, handler must be set to nil. If the parent already has a handler set, this will panic.
func (*Command) Parse ¶
Parse parses the command line from os.Args under the supplied command tree, then acts accordingly based on the results.
Everything specified on the command line is either a subcommand, option or a generic parameter.
Once parsing is complete, pre callbacks are made, then we either proceed to display internal help information if requested, or we perform internal verification, then call the validation callbacks, then finally if everything is ok call the wanted Handler.
The parsing will steal the arg "help" if it detects it as the first unknown parameter, allowing for easy access to the available commands and options.
If parsing is not ok, it will return one of several internal error types.
func (*Command) UnbindOption ¶
UnbindOption unbinds an Option so it is no longer a child.
type Data ¶
type Data struct { // Cmd is a pointer to the Command object which has triggered the Handler // to be called. // // If the Handler is a registered callback, the pointer is to the Command // object that is about to be executed. Cmd *Command // Options is a map of options supplied to the command. The key is the // option selected by the user, with the value being the parameter supplied // to that option. // // For Option objects which do not take parameters, the value is an empty // string. // // E.g.: // ./clicommand ... --foo bar ... -q ... // Becomes: // Options["foo"] = "bar" // Options["q"] = "" // // Callbacks may modify the Options directly, the parser then sees these // as if they were directly supplied by the user. Callbacks of this type // should generally be bound via BindCallbackPre(), allowing verification // to be performed as normal within standard callbacks. Options map[string]string // Params is an array of additional parameters the parser did not recognise. // Effectively, when the parser finds a non-option argument which doesnt // match any more commands, the remaining non-option fields become // parameters. Params []string }
The Data structure is passed to all Handler functions called as a result of a given Command being run. This structure is also passed to any registered callbacks during the parsing stage.
type ErrCallback ¶
type ErrCallback struct {
// contains filtered or unexported fields
}
ErrCallback Error type for when a callback has failed.
func (*ErrCallback) Error ¶
func (e *ErrCallback) Error() string
type ErrCallbackPre ¶
type ErrCallbackPre struct {
// contains filtered or unexported fields
}
ErrCallbackPre Error type for when a pre-validation callback has failed.
func (*ErrCallbackPre) Error ¶
func (e *ErrCallbackPre) Error() string
type ErrCommandError ¶
type ErrCommandError struct {
// contains filtered or unexported fields
}
ErrCommandError Error type for when a command has returned an error.
func (*ErrCommandError) Error ¶
func (e *ErrCommandError) Error() string
type ErrCommandInvalid ¶
type ErrCommandInvalid struct {
// contains filtered or unexported fields
}
ErrCommandInvalid Error type for when the command line uses a subcommand that does not exist.
func (*ErrCommandInvalid) Error ¶
func (e *ErrCommandInvalid) Error() string
type ErrCommandMissing ¶
type ErrCommandMissing struct{}
ErrCommandMissing Error type for when the command line has ended with a parent command with no handler, meaning one of its children needed to be chosen instead.
func (*ErrCommandMissing) Error ¶
func (e *ErrCommandMissing) Error() string
type ErrOptionMissing ¶
type ErrOptionMissing struct {
// contains filtered or unexported fields
}
ErrOptionMissing Error type for when a required option is missing.
func (*ErrOptionMissing) Error ¶
func (e *ErrOptionMissing) Error() string
type ErrOptionMissingParam ¶
type ErrOptionMissingParam struct {
// contains filtered or unexported fields
}
ErrOptionMissingParam Error type for when the command line contains an option that requires a parameter, but one is not specified
func (*ErrOptionMissingParam) Error ¶
func (e *ErrOptionMissingParam) Error() string
type ErrOptionUnknown ¶
type ErrOptionUnknown struct {
// contains filtered or unexported fields
}
ErrOptionUnknown Error type for when the command line contains an option, that is not defined in the command tree.
func (*ErrOptionUnknown) Error ¶
func (e *ErrOptionUnknown) Error() string
type Handler ¶
A Handler represents a function to be called when a particular Command is selected, or a callback is required. The Handler function must be defined as:
func myHandlerFunc(data *Data) error { // your code goes here }
The Data parameter contains a pointer to the selected Command, a map of supplied options and an array of the supplied parameters.
If the Handler function encounters an error it should return this as an error and it will automatically be sent to stderr. The Handler function should return nil on success.
type Option ¶
type Option struct { // name Name of option, stored without its dashes prefix. Name string // desc Description of option Desc string // param Controls whether this option takes parameters or not. // // For simplicity, all options that take parameters have a double dash // prefix, whilst options without parameters have a single dash prefix. // E.g. // --option1 <required parameter> // -option2 // no paramater Param bool // required Controls whether this option must be supplied or not. // If a parameter is marked as required, the parser will automatically // detect it is not supplied and return an error. Required bool // parents Array of pointers which this Option is bound to Parents []*Command }
An Option represents a defined option parameter that can be specified on the command line when the program is run.
Options can be attached to multiple Command objects.
Options either have, or do not have parameters and the parser detects the difference by whether they are specified with a double dash prefix or a single dash prefix. Options with a double dash prefix (e.g. --foo) will have the next field of the command string taken as its parameter.
The parser will always perform case-insensitive matches on option names, but will also match the parameter type. If a non-parameter (e.g. -bar) is specified, but the Option has been added as a parameter type (e.g. --bar) the parser will treat it as an unknown option.
func NewOption ¶
NewOption creates a new Option object with the given name and desc, but does not bind it within the tree. This is generally useful when creating a generic Option, which needs to be bound to multiple Command objects.
The param field is used to determine whether this option takes an additional parameter after it.
func (*Option) BindCommand ¶
BindCommand binds an Option to the given Command object, so it is available to be specified for that command, and all child commands.
func (*Option) GetParents ¶
GetParents returns the parents Command objects of an Option
func (*Option) GetRequired ¶
GetRequired returns whether this Option must be specified. This requirement only applies to Options that are directly on the path between the edge Command and the root.
func (*Option) SetRequired ¶
SetRequired marks the Option so it must be specified. This requirement only applies to Options that are directly on the path between the edge Command and the root.
func (*Option) UnbindCommand ¶
UnbindCommand unbinds an Option from the given Command object, at which point it is no longer available for that command or its children.