There are a handful of powerful go CLI libraries available (spf13/cobra, urfave/cli). However sometimes an integrated shell interface is a great and useful extension for the actual application. This library offers a simple API to create powerful CLI applications and automatically starts an integrated interactive shell, if the application is started without any command arguments.
Hint: We do not guarantee 100% backwards compatiblity between minor versions (1.x). However, the API is mostly stable and should not change much.
Create a grumble APP.
varapp=grumble.New(&grumble.Config{
Name: "app",
Description: "short app description",
Flags: func(f*grumble.Flags) {
f.String("d", "directory", "DEFAULT", "set an alternative directory path")
f.Bool("v", "verbose", false, "enable verbose mode")
},
})Register a top-level command. Note: Sub commands are also supported...
app.AddCommand(&grumble.Command{
Name: "daemon",
Help: "run the daemon",
Aliases: []string{"run"},
Flags: func(f*grumble.Flags) {
f.Duration("t", "timeout", time.Second, "timeout duration")
},
Args: func(a*grumble.Args) {
a.String("service", "which service to start", grumble.Default("server"))
},
Run: func(c*grumble.Context) error {
// Parent Flags.c.App.Println("directory:", c.Flags.String("directory"))
c.App.Println("verbose:", c.Flags.Bool("verbose"))
// Flags.c.App.Println("timeout:", c.Flags.Duration("timeout"))
// Args.c.App.Println("service:", c.Args.String("service"))
returnnil
},
})Run the application.
err:=app.Run()Or use the builtin grumble.Main function to handle errors automatically.
funcmain() {
grumble.Main(app)
}Builtin support for multiple lines.
>>> This is \
... a multi line \
... command
You can pass flags in two ways: cmd --flag value or cmd --flag=value
There are some exceptions/additions to this:
- bool:
cmd --boolflagoffer a third option that does not require a value - string:
cmd --stringflag="some test string"leads to valuesome test string, as double quotes are stripped from the value
If you need to pass a flag-like value as positional argument, you can do so by using a double dash:>>> command --flag1=something -- --myPositionalArg
By calling RunWithReadline() rather than Run() you can pass instance of readline.Instance. One of interesting usages is having a possibility of remote access to your shell:
handleFunc:=func(rl*readline.Instance) {
varapp=grumble.New(&grumble.Config{
// override default interrupt handler to avoid remote shutdownInterruptHandler: func(a*grumble.App, countint) {
// do nothing
},
// your usual grumble configuration
}) // add commandsapp.RunWithReadline(rl)
}
cfg:=&readline.Config{}
readline.ListenRemote("tcp", ":5555", cfg, handleFunc)In the client code just use readline built in DialRemote function:
iferr:=readline.DialRemote("tcp", ":5555"); err!=nil {
fmt.Errorf("An error occurred: %s \n", err.Error())
}Check out the sample directory for some detailed examples.
- grml - A simple build automation tool written in Go: https://github.com/desertbit/grml
- orbit - A RPC-like networking backend written in Go: https://github.com/desertbit/orbit
- Windows unicode not fully supported (issue)
This project is based on ideas from the great ishell library.
MIT
