Documentation ¶
Overview ¶
The cli package provides a simple library for creating command-line applications. See http://github.com/turbinelabs/cli for a richer discussion of motivation and feature set. See the examples for basic usage.
Example (SingleCommand) ¶
This example shows how to create a single-command CLI
// This package contains a trivial example use of the cli package package main import ( "fmt" "strconv" "github.com/turbinelabs/cli" "github.com/turbinelabs/cli/command" "github.com/turbinelabs/nonstdlib/flag/usage" ) // The typical pattern is to provide a public Cmd() func. This function should // initialize the command.Cmd, the command.Runner, and flags. func Cmd() *command.Cmd { // typically the command.Runner is initialized only with internally-defined // state; all necessary external state should be provided via flags. One can // inline the initializaton of the command.Runner in the command.Cmd // initialization if no flags are necessary, but it's often convenient to // have a typed reference runner := &runner{} cmd := &command.Cmd{ Name: "adder", Summary: "add a delimited string of integers together", Usage: "[OPTIONS] <int>...", Description: "add a delimited string of integers together", Runner: runner, } // The flag.FlagSet is a member of the command.Cmd, and the flag // value is a member of the command.Runner. cmd.Flags.BoolVar(&runner.verbose, "verbose", false, "Produce verbose output") // If we wrap flag.Required(...) around the usage string, Cmd.Run(...) // will fail if it is unspecified cmd.Flags.StringVar(&runner.thing, "thing", "", usage.Required("The thing")) return cmd } // The private command.Runner implementation should contain any state needed // to execute the command. The values should be initialized via flags declared // in the Cmd() function. type runner struct { verbose bool thing string } // Run does the actual work, based on state provided by flags, and the // args remaining after the flags have been parsed. func (f *runner) Run(cmd *command.Cmd, args []string) command.CmdErr { ints := []int{} sum := 0 // argument validation should occur at the top of the function, and // errors should be reported via the cmd.BadInput or cmd.BadInputf methods. // In this case, the main work of the function is done at the same time. for _, arg := range args { i, err := strconv.Atoi(arg) if err != nil { return cmd.BadInputf("Bad integer: \"%s\": %s", arg, err) } ints = append(ints, i) sum += i } if f.verbose && len(ints) > 0 { fmt.Print(ints[0]) for _, i := range ints[1:] { fmt.Print(" + ", i) } fmt.Print(" = ") } fmt.Printf(`The thing: %s, the sum: %d`, f.thing, sum) // In this case, there was no error. Errors should be returned via the // cmd.Error or cmd.Errorf methods. return command.NoError() } func mkSingleCmdCLI() cli.CLI { // make a new CLI passing the version string and a command.Cmd // while it's possible to add flags to the CLI, they are ignored; only the // Cmd's flags are presented to the user. return cli.New("1.0.2", Cmd()) } // This example shows how to create a single-command CLI func main() { // this would be your main() function // run the Main function, which calls os.Exit with the appropriate exit status mkSingleCmdCLI().Main() } // Add the following to your tests to validate that there are no collisions // between command flags and that help text can be generated without error: // package main // import ( // "testing" // "github.com/turbinelabs/test/assert" // ) // func TestCLI(t *testing.T) { // assert.Nil(t, mkCLI().Validate()) // }
Output:
Example (SubCommands) ¶
This example shows how to create a CLI with multiple sub-commands
// This package contains a trivial example use of the cli package package main import ( "fmt" "strings" "github.com/turbinelabs/cli" "github.com/turbinelabs/cli/command" ) // The typical pattern is to provide a public CmdXYZ() func for each // sub-command you wish to provide. This function should initialize the // command.Cmd, the command.Runner, and flags. func CmdSplit() *command.Cmd { // typically the command.Runner is initialized only with internally-defined // state; all necessary external state should be provided via flags. One can // inline the initializaton of the command.Runner in the command.Cmd // initialization if no flags are necessary, but it's often convenient to // have a typed reference runner := &splitRunner{} cmd := &command.Cmd{ Name: "split", Summary: "split strings", Usage: "[OPTIONS] <string>", Description: "split strings using the specified delimiter", Runner: runner, } // The flag.FlagSet is a member of the command.Cmd, and the flag // value is a member of the command.Runner. cmd.Flags.StringVar(&runner.delim, "delim", ",", "The delimiter on which to split the string") return cmd } // The private command.Runner implementation should contain any state needed // to execute the command. The values should be initialized via flags declared // in the CmdXYZ() function. type splitRunner struct { delim string } // Run does the actual work, based on state provided by flags, and the // args remaining after the flags have been parsed. func (f *splitRunner) Run(cmd *command.Cmd, args []string) command.CmdErr { // argument validation should occur at the top of the function, and // errors should be reported via the cmd.BadInput or cmd.BadInputf methods if len(args) < 1 { return cmd.BadInput("missing \"string\" argument.") } str := args[0] if globalFlags.verbose { fmt.Printf("Splitting \"%s\"\n", str) } split := strings.Split(str, f.delim) for i, term := range split { if globalFlags.verbose { fmt.Printf("[%d] ", i) } fmt.Println(term) } // In this case, there was no error. Errors should be returned via the // cmd.Error or cmd.Errorf methods. return command.NoError() } // A second command func CmdJoin() *command.Cmd { runner := &joinRunner{} cmd := &command.Cmd{ Name: "join", Summary: "join strings", Usage: "[OPTIONS] <string>...", Description: "join strings using the specified delimiter", Runner: runner, } cmd.Flags.StringVar(&runner.delim, "delim", ",", "The delimiter with which to join the strings") return cmd } // a second Runner type joinRunner struct { delim string } func (f *joinRunner) Run(cmd *command.Cmd, args []string) command.CmdErr { if globalFlags.verbose { fmt.Printf("Joining \"%v\"\n", args) } joined := strings.Join(args, f.delim) fmt.Println(joined) return command.NoError() } // while not manditory, keeping globally-configured flags in a single struct // makes it obvious where they came from at access time. type globalFlagsT struct { verbose bool } var globalFlags = globalFlagsT{} func mkSubCmdCLI() cli.CLI { // make a new CLI passing the description and version and one or more sub commands c := cli.NewWithSubCmds( "an example CLI for simple string operations", "1.2.3", CmdSplit(), CmdJoin(), ) // Global flags can be used to modify global state c.Flags().BoolVar(&globalFlags.verbose, "verbose", false, "Produce verbose output") return c } // This example shows how to create a CLI with multiple sub-commands func main() { // this would be your main() function // run the Main function, which calls os.Exit with the appropriate exit status mkSubCmdCLI().Main() } // Add the following to your tests to validate that there are no collisions // between command flags: // package main // import ( // "testing" // "github.com/turbinelabs/test/assert" // ) // func TestCLI(t *testing.T) { // assert.Nil(t, mkCLI().Validate()) // }
Output:
Index ¶
Examples ¶
Constants ¶
View Source
const HelpSummary = "Show a list of commands or help for one command"
View Source
const VersionSummary = "Print the version and exit"
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CLI ¶
type CLI interface { // Flags returns a pointer to the global flags for the CLI Flags() *flag.FlagSet // Set the flags SetFlags(*flag.FlagSet) // Main serves as the main() function for the CLI. It will parse // the command-line arguments and flags, call the appropriate sub-command, // and return exit status and output error messages as appropriate. Main() // Validate can be used to make sure the CLI is well-defined from within // unit tests. In particular it will validate that no two flags exist with // the same environment key. As a last-ditch effort, Validate will be called // at the start of Main. ValidationFlag values may be passed to alter the // level of validation performed. Validate(...ValidationFlag) error // Returns the CLI version data. Version() app.Version }
A CLI represents a command-line application
type ValidationFlag ¶
type ValidationFlag int
const ( // Skips Validating that global and subcommand help text can // be generated. ValidateSkipHelpText ValidationFlag = iota )
Directories ¶
Path | Synopsis |
---|---|
The app package provides a simple App struct to describe a command-line application, and a Usage interface, which describers the global and command-specific usage of the App.
|
The app package provides a simple App struct to describe a command-line application, and a Usage interface, which describers the global and command-specific usage of the App. |
The command package provides an abstraction for a command-line application sub-command, a means to execute code when that sub-command is invoked, a means to report success/failure status of said code, and generic implementations of help and version sub-commands.
|
The command package provides an abstraction for a command-line application sub-command, a means to execute code when that sub-command is invoked, a means to report success/failure status of said code, and generic implementations of help and version sub-commands. |
Click to show internal directories.
Click to hide internal directories.