Gist: Go basic CLI package
A basic Go package for handling multiple CLI commands with one executable.
Last updated on: 2025-02-24
Basic package definition
package cli
import "fmt"
type HandlerFunc func(args ...string) (exitcode int)
type Command struct {
Keyword string
Description string
Do func(args ...string) (exitcode int)
}
func Run(args []string, commands []*Command, onArgsNone, onNotFound HandlerFunc) (exitcode int) {
if len(args) == 0 {
return onArgsNone(args...)
}
for _, cmd := range commands {
if cmd.Keyword == args[0] {
return cmd.Do(args[1:]...)
}
}
return onNotFound(args...)
}
func PrintAvailableCommands(commands []*Command) {
fmt.Println("Available commands:")
for _, cmd := range commands {
fmt.Printf("- %-20s %s\n", cmd.Keyword, cmd.Description)
}
}
Example usage
package main
import (
"os"
)
func main() {
os.Exit(cli.Run(
os.Args[1:],
myapp.AllCLICommands,
myapp.CLICommandHelloWorld.Do,
myapp.HandleCLICommandNotFound,
))
}
package myapp
import (
"fmt"
)
var AllCLICommands = []*cli.Command{
CLICommandHelloWorld,
CLICommandFoo
}
func init() { AllCLICommands = append([]*cli.Command{CLICommandHelp}, AllCLICommands...) }
var CLICommandHelp = &cli.Command{
Keyword: "help",
Description: "Prints helpful information about this executable",
Do: func(args ...string) (exitcode int) {
cli.PrintAvailableCommands(AllCLICommands)
return 0
},
}
func HandleCLICommandNotFound(args ...string) (exitcode int) {
fmt.Printf("Command not found: %q\n", args[0])
_ = CLICommandHelp.Do()
return 1
}
var CLICommandHelloWorld = &cli.Command{
Keyword: "hello",
Description: "Prints 'Hello World!' to stdout",
Do: func(args ...string) (exitcode int) {
fmt.Println("Hello World!")
return 0
},
}
var CLICommandFoo = &cli.Command{
Keyword: "foo",
Description: "Prints 'foo' to stdout",
Do: func(args ...string) (exitcode int) {
fmt.Println("foo")
return 0
},
}