- POSIX-style short flag combining.
- Parsed, type-safe flags.
- Parsed, type-safe positional arguments.
- Support for required flags and required positional arguments
- Callbacks per command, flag and argument.
- Help output that isn't as ugly as sin.
Kingpin can be used for simple flag+arg applications like so:
$ ping --help
usage: ping [<flags>] <ip> [<count>]
Flags:
--debug Enable debug mode.
--help Show help.
-t, --timeout=5s Timeout waiting for ping.
Args:
<ip> IP address to ping.
[<count>] Number of packets to send
$ ping 1.2.3.4 5
Would ping: 1.2.3.4 with timeout 5s%
From the following source:
package main
import (
"fmt"
"github.com/alecthomas/kingpin"
)
var (
debug = kingpin.Flag("debug", "Enable debug mode.").Bool()
timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").Default("5s").MetaVarFromDefault().Short('t').Duration()
ip = kingpin.Arg("ip", "IP address to ping.").Required().IP()
count = kingpin.Arg("count", "Number of packets to send").Int()
)
func main() {
kingpin.Parse()
fmt.Printf("Would ping: %s with timeout %s", *ip, *timeout)
}Kingpin can also produce complex command-line applications with global flags, subcommands, and per-subcommand flags, like this:
$ chat
usage: chat [<flags>] <command> [<flags>] [<args> ...]
A command-line chat application.
Flags:
--debug enable debug mode
--help Show help.
--server=127.0.0.1 server address
Commands:
help <command>
Show help for a command.
post [<flags>] <channel>
Post a message to a channel.
register <nick> <name>
Register a new user.
$ chat help post
usage: chat [<flags>] post [<flags>] <channel> [<text>]
Post a message to a channel.
Flags:
--image=IMAGE image to post
Args:
<channel> channel to post to
[<text>] text to post
$ chat post --image=~/Downloads/owls.jpg pics
...
From this code:
package main
import (
"os"
"github.com/alecthomas/kingpin"
)
var (
app = kingpin.New("chat", "A command-line chat application.")
debug = app.Flag("debug", "enable debug mode").Default("false").Bool()
serverIP = app.Flag("server", "server address").Default("127.0.0.1").MetaVarFromDefault().IP()
register = app.Command("register", "Register a new user.")
registerNick = register.Arg("nick", "nickname for user").Required().String()
registerName = register.Arg("name", "name of user").Required().String()
post = app.Command("post", "Post a message to a channel.")
postImage = post.Flag("image", "image to post").File()
postChannel = post.Arg("channel", "channel to post to").Required().String()
postText = post.Arg("text", "text to post").String()
)
func main() {
switch kingpin.MustParse(app.Parse(os.Argv[1:])) {
// Register user
case "register":
println(*registerNick)
// Post message
case "post":
if *postImage != nil {
}
if *postText != "" {
}
}
}Kingpin supports both flag and positional argument parsers for converting to
Go types. For example, some included parsers are Int(), Float(),
Duration() and ExistingFile().
Parsers conform to Go's flag.Value
interface, so any existing implementations will work.
For example, a parser for accumulating HTTP header values might look like this:
type HTTPHeaderValue http.Header
func (h *HTTPHeaderValue) Set(value string) error {
parts := strings.SplitN(value, ":", 2)
if len(parts) != 2 {
return fmt.Errorf("expected HEADER:VALUE got '%s'", value)
}
(*http.Header)(h).Add(parts[0], parts[1])
return nil
}
func (h *HTTPHeaderValue) String() string {
return ""
}As a convenience, I would recommend something like this:
func HTTPHeader(s Settings) (target *http.Header) {
target = new(http.Header)
s.SetValue((*HTTPHeaderValue)(target))
return
}You would use it like so:
headers = HTTPHeader(kingpin.Flag("--header", "Add a HTTP header to the request.").Short('-H'))The default value is the zero value for a type. This can be overridden with
the Default(value) function on flags and arguments. This function accepts a
string, which is parsed by the value itself, so it must be compliant with
the format expected.