pax_global_header00006660000000000000000000000064133014324560014513gustar00rootroot0000000000000052 comment=fad245ddb24d7e4abfaaf373e8d110d2813f931c golang-gopkg-alecthomas-kingpin.v2-2.2.6/000077500000000000000000000000001330143245600201775ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/.travis.yml000066400000000000000000000000751330143245600223120ustar00rootroot00000000000000sudo: false language: go install: go get -t -v ./... go: 1.2 golang-gopkg-alecthomas-kingpin.v2-2.2.6/COPYING000066400000000000000000000020371330143245600212340ustar00rootroot00000000000000Copyright (C) 2014 Alec Thomas Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-gopkg-alecthomas-kingpin.v2-2.2.6/README.md000066400000000000000000000536031330143245600214650ustar00rootroot00000000000000# Kingpin - A Go (golang) command line and flag parser [![](https://godoc.org/github.com/alecthomas/kingpin?status.svg)](http://godoc.org/github.com/alecthomas/kingpin) [![Build Status](https://travis-ci.org/alecthomas/kingpin.svg?branch=master)](https://travis-ci.org/alecthomas/kingpin) [![Gitter chat](https://badges.gitter.im/alecthomas.png)](https://gitter.im/alecthomas/Lobby) - [Overview](#overview) - [Features](#features) - [User-visible changes between v1 and v2](#user-visible-changes-between-v1-and-v2) - [Flags can be used at any point after their definition.](#flags-can-be-used-at-any-point-after-their-definition) - [Short flags can be combined with their parameters](#short-flags-can-be-combined-with-their-parameters) - [API changes between v1 and v2](#api-changes-between-v1-and-v2) - [Versions](#versions) - [V2 is the current stable version](#v2-is-the-current-stable-version) - [V1 is the OLD stable version](#v1-is-the-old-stable-version) - [Change History](#change-history) - [Examples](#examples) - [Simple Example](#simple-example) - [Complex Example](#complex-example) - [Reference Documentation](#reference-documentation) - [Displaying errors and usage information](#displaying-errors-and-usage-information) - [Sub-commands](#sub-commands) - [Custom Parsers](#custom-parsers) - [Repeatable flags](#repeatable-flags) - [Boolean Values](#boolean-values) - [Default Values](#default-values) - [Place-holders in Help](#place-holders-in-help) - [Consuming all remaining arguments](#consuming-all-remaining-arguments) - [Bash/ZSH Shell Completion](#bashzsh-shell-completion) - [Supporting -h for help](#supporting--h-for-help) - [Custom help](#custom-help) ## Overview Kingpin is a [fluent-style](http://en.wikipedia.org/wiki/Fluent_interface), type-safe command-line parser. It supports flags, nested commands, and positional arguments. Install it with: $ go get gopkg.in/alecthomas/kingpin.v2 It looks like this: ```go var ( verbose = kingpin.Flag("verbose", "Verbose mode.").Short('v').Bool() name = kingpin.Arg("name", "Name of user.").Required().String() ) func main() { kingpin.Parse() fmt.Printf("%v, %s\n", *verbose, *name) } ``` More [examples](https://github.com/alecthomas/kingpin/tree/master/_examples) are available. Second to parsing, providing the user with useful help is probably the most important thing a command-line parser does. Kingpin tries to provide detailed contextual help if `--help` is encountered at any point in the command line (excluding after `--`). ## Features - Help output that isn't as ugly as sin. - Fully [customisable help](#custom-help), via Go templates. - Parsed, type-safe flags (`kingpin.Flag("f", "help").Int()`) - Parsed, type-safe positional arguments (`kingpin.Arg("a", "help").Int()`). - Parsed, type-safe, arbitrarily deep commands (`kingpin.Command("c", "help")`). - Support for required flags and required positional arguments (`kingpin.Flag("f", "").Required().Int()`). - Support for arbitrarily nested default commands (`command.Default()`). - Callbacks per command, flag and argument (`kingpin.Command("c", "").Action(myAction)`). - POSIX-style short flag combining (`-a -b` -> `-ab`). - Short-flag+parameter combining (`-a parm` -> `-aparm`). - Read command-line from files (`@`). - Automatically generate man pages (`--help-man`). ## User-visible changes between v1 and v2 ### Flags can be used at any point after their definition. Flags can be specified at any point after their definition, not just *immediately after their associated command*. From the chat example below, the following used to be required: ``` $ chat --server=chat.server.com:8080 post --image=~/Downloads/owls.jpg pics ``` But the following will now work: ``` $ chat post --server=chat.server.com:8080 --image=~/Downloads/owls.jpg pics ``` ### Short flags can be combined with their parameters Previously, if a short flag was used, any argument to that flag would have to be separated by a space. That is no longer the case. ## API changes between v1 and v2 - `ParseWithFileExpansion()` is gone. The new parser directly supports expanding `@`. - Added `FatalUsage()` and `FatalUsageContext()` for displaying an error + usage and terminating. - `Dispatch()` renamed to `Action()`. - Added `ParseContext()` for parsing a command line into its intermediate context form without executing. - Added `Terminate()` function to override the termination function. - Added `UsageForContextWithTemplate()` for printing usage via a custom template. - Added `UsageTemplate()` for overriding the default template to use. Two templates are included: 1. `DefaultUsageTemplate` - default template. 2. `CompactUsageTemplate` - compact command template for larger applications. ## Versions Kingpin uses [gopkg.in](https://gopkg.in/alecthomas/kingpin) for versioning. The current stable version is [gopkg.in/alecthomas/kingpin.v2](https://gopkg.in/alecthomas/kingpin.v2). The previous version, [gopkg.in/alecthomas/kingpin.v1](https://gopkg.in/alecthomas/kingpin.v1), is deprecated and in maintenance mode. ### [V2](https://gopkg.in/alecthomas/kingpin.v2) is the current stable version Installation: ```sh $ go get gopkg.in/alecthomas/kingpin.v2 ``` ### [V1](https://gopkg.in/alecthomas/kingpin.v1) is the OLD stable version Installation: ```sh $ go get gopkg.in/alecthomas/kingpin.v1 ``` ## Change History - *2015-09-19* -- Stable v2.1.0 release. - Added `command.Default()` to specify a default command to use if no other command matches. This allows for convenient user shortcuts. - Exposed `HelpFlag` and `VersionFlag` for further customisation. - `Action()` and `PreAction()` added and both now support an arbitrary number of callbacks. - `kingpin.SeparateOptionalFlagsUsageTemplate`. - `--help-long` and `--help-man` (hidden by default) flags. - Flags are "interspersed" by default, but can be disabled with `app.Interspersed(false)`. - Added flags for all simple builtin types (int8, uint16, etc.) and slice variants. - Use `app.Writer(os.Writer)` to specify the default writer for all output functions. - Dropped `os.Writer` prefix from all printf-like functions. - *2015-05-22* -- Stable v2.0.0 release. - Initial stable release of v2.0.0. - Fully supports interspersed flags, commands and arguments. - Flags can be present at any point after their logical definition. - Application.Parse() terminates if commands are present and a command is not parsed. - Dispatch() -> Action(). - Actions are dispatched after all values are populated. - Override termination function (defaults to os.Exit). - Override output stream (defaults to os.Stderr). - Templatised usage help, with default and compact templates. - Make error/usage functions more consistent. - Support argument expansion from files by default (with @). - Fully public data model is available via .Model(). - Parser has been completely refactored. - Parsing and execution has been split into distinct stages. - Use `go generate` to generate repeated flags. - Support combined short-flag+argument: -fARG. - *2015-01-23* -- Stable v1.3.4 release. - Support "--" for separating flags from positional arguments. - Support loading flags from files (ParseWithFileExpansion()). Use @FILE as an argument. - Add post-app and post-cmd validation hooks. This allows arbitrary validation to be added. - A bunch of improvements to help usage and formatting. - Support arbitrarily nested sub-commands. - *2014-07-08* -- Stable v1.2.0 release. - Pass any value through to `Strings()` when final argument. Allows for values that look like flags to be processed. - Allow `--help` to be used with commands. - Support `Hidden()` flags. - Parser for [units.Base2Bytes](https://github.com/alecthomas/units) type. Allows for flags like `--ram=512MB` or `--ram=1GB`. - Add an `Enum()` value, allowing only one of a set of values to be selected. eg. `Flag(...).Enum("debug", "info", "warning")`. - *2014-06-27* -- Stable v1.1.0 release. - Bug fixes. - Always return an error (rather than panicing) when misconfigured. - `OpenFile(flag, perm)` value type added, for finer control over opening files. - Significantly improved usage formatting. - *2014-06-19* -- Stable v1.0.0 release. - Support [cumulative positional](#consuming-all-remaining-arguments) arguments. - Return error rather than panic when there are fatal errors not caught by the type system. eg. when a default value is invalid. - Use gokpg.in. - *2014-06-10* -- Place-holder streamlining. - Renamed `MetaVar` to `PlaceHolder`. - Removed `MetaVarFromDefault`. Kingpin now uses [heuristics](#place-holders-in-help) to determine what to display. ## Examples ### Simple Example Kingpin can be used for simple flag+arg applications like so: ``` $ ping --help usage: ping [] [] Flags: --debug Enable debug mode. --help Show help. -t, --timeout=5s Timeout waiting for ping. Args: IP address to ping. [] Number of packets to send $ ping 1.2.3.4 5 Would ping: 1.2.3.4 with timeout 5s and count 5 ``` From the following source: ```go package main import ( "fmt" "gopkg.in/alecthomas/kingpin.v2" ) var ( debug = kingpin.Flag("debug", "Enable debug mode.").Bool() timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").Default("5s").OverrideDefaultFromEnvar("PING_TIMEOUT").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.Version("0.0.1") kingpin.Parse() fmt.Printf("Would ping: %s with timeout %s and count %d\n", *ip, *timeout, *count) } ``` ### Complex Example Kingpin can also produce complex command-line applications with global flags, subcommands, and per-subcommand flags, like this: ``` $ chat --help usage: chat [] [] [ ...] A command-line chat application. Flags: --help Show help. --debug Enable debug mode. --server=127.0.0.1 Server address. Commands: help [] Show help for a command. register Register a new user. post [] [] Post a message to a channel. $ chat help post usage: chat [] post [] [] Post a message to a channel. Flags: --image=IMAGE Image to post. Args: Channel to post to. [] Text to post. $ chat post --image=~/Downloads/owls.jpg pics ... ``` From this code: ```go package main import ( "os" "strings" "gopkg.in/alecthomas/kingpin.v2" ) var ( app = kingpin.New("chat", "A command-line chat application.") debug = app.Flag("debug", "Enable debug mode.").Bool() serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").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.").Strings() ) func main() { switch kingpin.MustParse(app.Parse(os.Args[1:])) { // Register user case register.FullCommand(): println(*registerNick) // Post message case post.FullCommand(): if *postImage != nil { } text := strings.Join(*postText, " ") println("Post:", text) } } ``` ## Reference Documentation ### Displaying errors and usage information Kingpin exports a set of functions to provide consistent errors and usage information to the user. Error messages look something like this: : error: The functions on `Application` are: Function | Purpose ---------|-------------- `Errorf(format, args)` | Display a printf formatted error to the user. `Fatalf(format, args)` | As with Errorf, but also call the termination handler. `FatalUsage(format, args)` | As with Fatalf, but also print contextual usage information. `FatalUsageContext(context, format, args)` | As with Fatalf, but also print contextual usage information from a `ParseContext`. `FatalIfError(err, format, args)` | Conditionally print an error prefixed with format+args, then call the termination handler There are equivalent global functions in the kingpin namespace for the default `kingpin.CommandLine` instance. ### Sub-commands Kingpin supports nested sub-commands, with separate flag and positional arguments per sub-command. Note that positional arguments may only occur after sub-commands. For example: ```go var ( deleteCommand = kingpin.Command("delete", "Delete an object.") deleteUserCommand = deleteCommand.Command("user", "Delete a user.") deleteUserUIDFlag = deleteUserCommand.Flag("uid", "Delete user by UID rather than username.") deleteUserUsername = deleteUserCommand.Arg("username", "Username to delete.") deletePostCommand = deleteCommand.Command("post", "Delete a post.") ) func main() { switch kingpin.Parse() { case "delete user": case "delete post": } } ``` ### Custom Parsers Kingpin supports both flag and positional argument parsers for converting to Go types. For example, some included parsers are `Int()`, `Float()`, `Duration()` and `ExistingFile()` (see [parsers.go](./parsers.go) for a complete list of included parsers). Parsers conform to Go's [`flag.Value`](http://godoc.org/flag#Value) interface, so any existing implementations will work. For example, a parser for accumulating HTTP header values might look like this: ```go 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: ```go func HTTPHeader(s Settings) (target *http.Header) { target = &http.Header{} s.SetValue((*HTTPHeaderValue)(target)) return } ``` You would use it like so: ```go headers = HTTPHeader(kingpin.Flag("header", "Add a HTTP header to the request.").Short('H')) ``` ### Repeatable flags Depending on the `Value` they hold, some flags may be repeated. The `IsCumulative() bool` function on `Value` tells if it's safe to call `Set()` multiple times or if an error should be raised if several values are passed. The built-in `Value`s returning slices and maps, as well as `Counter` are examples of `Value`s that make a flag repeatable. ### Boolean values Boolean values are uniquely managed by Kingpin. Each boolean flag will have a negative complement: `--` and `--no-`. ### Default Values 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 one or several strings, which are parsed by the value itself, so they *must* be compliant with the format expected. ### Place-holders in Help The place-holder value for a flag is the value used in the help to describe the value of a non-boolean flag. The value provided to PlaceHolder() is used if provided, then the value provided by Default() if provided, then finally the capitalised flag name is used. Here are some examples of flags with various permutations: --name=NAME // Flag(...).String() --name="Harry" // Flag(...).Default("Harry").String() --name=FULL-NAME // Flag(...).PlaceHolder("FULL-NAME").Default("Harry").String() ### Consuming all remaining arguments A common command-line idiom is to use all remaining arguments for some purpose. eg. The following command accepts an arbitrary number of IP addresses as positional arguments: ./cmd ping 10.1.1.1 192.168.1.1 Such arguments are similar to [repeatable flags](#repeatable-flags), but for arguments. Therefore they use the same `IsCumulative() bool` function on the underlying `Value`, so the built-in `Value`s for which the `Set()` function can be called several times will consume multiple arguments. To implement the above example with a custom `Value`, we might do something like this: ```go type ipList []net.IP func (i *ipList) Set(value string) error { if ip := net.ParseIP(value); ip == nil { return fmt.Errorf("'%s' is not an IP address", value) } else { *i = append(*i, ip) return nil } } func (i *ipList) String() string { return "" } func (i *ipList) IsCumulative() bool { return true } func IPList(s Settings) (target *[]net.IP) { target = new([]net.IP) s.SetValue((*ipList)(target)) return } ``` And use it like so: ```go ips := IPList(kingpin.Arg("ips", "IP addresses to ping.")) ``` ### Bash/ZSH Shell Completion By default, all flags and commands/subcommands generate completions internally. Out of the box, CLI tools using kingpin should be able to take advantage of completion hinting for flags and commands. By specifying `--completion-bash` as the first argument, your CLI tool will show possible subcommands. By ending your argv with `--`, hints for flags will be shown. To allow your end users to take advantage you must package a `/etc/bash_completion.d` script with your distribution (or the equivalent for your target platform/shell). An alternative is to instruct your end user to source a script from their `bash_profile` (or equivalent). Fortunately Kingpin makes it easy to generate or source a script for use with end users shells. `./yourtool --completion-script-bash` and `./yourtool --completion-script-zsh` will generate these scripts for you. **Installation by Package** For the best user experience, you should bundle your pre-created completion script with your CLI tool and install it inside `/etc/bash_completion.d` (or equivalent). A good suggestion is to add this as an automated step to your build pipeline, in the implementation is improved for bug fixed. **Installation by `bash_profile`** Alternatively, instruct your users to add an additional statement to their `bash_profile` (or equivalent): ``` eval "$(your-cli-tool --completion-script-bash)" ``` Or for ZSH ``` eval "$(your-cli-tool --completion-script-zsh)" ``` #### Additional API To provide more flexibility, a completion option API has been exposed for flags to allow user defined completion options, to extend completions further than just EnumVar/Enum. **Provide Static Options** When using an `Enum` or `EnumVar`, users are limited to only the options given. Maybe we wish to hint possible options to the user, but also allow them to provide their own custom option. `HintOptions` gives this functionality to flags. ``` app := kingpin.New("completion", "My application with bash completion.") app.Flag("port", "Provide a port to connect to"). Required(). HintOptions("80", "443", "8080"). IntVar(&c.port) ``` **Provide Dynamic Options** Consider the case that you needed to read a local database or a file to provide suggestions. You can dynamically generate the options ``` func listHosts() []string { // Provide a dynamic list of hosts from a hosts file or otherwise // for bash completion. In this example we simply return static slice. // You could use this functionality to reach into a hosts file to provide // completion for a list of known hosts. return []string{"sshhost.example", "webhost.example", "ftphost.example"} } app := kingpin.New("completion", "My application with bash completion.") app.Flag("flag-1", "").HintAction(listHosts).String() ``` **EnumVar/Enum** When using `Enum` or `EnumVar`, any provided options will be automatically used for bash autocompletion. However, if you wish to provide a subset or different options, you can use `HintOptions` or `HintAction` which will override the default completion options for `Enum`/`EnumVar`. **Examples** You can see an in depth example of the completion API within `examples/completion/main.go` ### Supporting -h for help `kingpin.CommandLine.HelpFlag.Short('h')` ### Custom help Kingpin v2 supports templatised help using the text/template library (actually, [a fork](https://github.com/alecthomas/template)). You can specify the template to use with the [Application.UsageTemplate()](http://godoc.org/gopkg.in/alecthomas/kingpin.v2#Application.UsageTemplate) function. There are four included templates: `kingpin.DefaultUsageTemplate` is the default, `kingpin.CompactUsageTemplate` provides a more compact representation for more complex command-line structures, `kingpin.SeparateOptionalFlagsUsageTemplate` looks like the default template, but splits required and optional command flags into separate lists, and `kingpin.ManPageTemplate` is used to generate man pages. See the above templates for examples of usage, and the the function [UsageForContextWithTemplate()](https://github.com/alecthomas/kingpin/blob/master/usage.go#L198) method for details on the context. #### Default help template ``` $ go run ./examples/curl/curl.go --help usage: curl [] [ ...] An example implementation of curl. Flags: --help Show help. -t, --timeout=5s Set connection timeout. -H, --headers=HEADER=VALUE Add HTTP headers to the request. Commands: help [...] Show help. get url Retrieve a URL. get file Retrieve a file. post [] POST a resource. ``` #### Compact help template ``` $ go run ./examples/curl/curl.go --help usage: curl [] [ ...] An example implementation of curl. Flags: --help Show help. -t, --timeout=5s Set connection timeout. -H, --headers=HEADER=VALUE Add HTTP headers to the request. Commands: help [...] get [] url file post [] ``` golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/000077500000000000000000000000001330143245600221545ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/chat1/000077500000000000000000000000001330143245600231545ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/chat1/main.go000066400000000000000000000010541330143245600244270ustar00rootroot00000000000000package main import ( "fmt" "gopkg.in/alecthomas/kingpin.v2" ) var ( debug = kingpin.Flag("debug", "Enable debug mode.").Bool() timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").Default("5s").OverrideDefaultFromEnvar("PING_TIMEOUT").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.Version("0.0.1") kingpin.Parse() fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/chat2/000077500000000000000000000000001330143245600231555ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/chat2/main.go000066400000000000000000000020351330143245600244300ustar00rootroot00000000000000package main import ( "os" "strings" "gopkg.in/alecthomas/kingpin.v2" ) var ( app = kingpin.New("chat", "A command-line chat application.") debug = app.Flag("debug", "Enable debug mode.").Bool() serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").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.").Strings() ) func main() { switch kingpin.MustParse(app.Parse(os.Args[1:])) { // Register user case register.FullCommand(): println(*registerNick) // Post message case post.FullCommand(): if *postImage != nil { } text := strings.Join(*postText, " ") println("Post:", text) } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/completion/000077500000000000000000000000001330143245600243255ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/completion/main.go000066400000000000000000000056501330143245600256060ustar00rootroot00000000000000package main import ( "fmt" "os" "gopkg.in/alecthomas/kingpin.v2" ) func listHosts() []string { // Provide a dynamic list of hosts from a hosts file or otherwise // for bash completion. In this example we simply return static slice. // You could use this functionality to reach into a hosts file to provide // completion for a list of known hosts. return []string{"sshhost.example", "webhost.example", "ftphost.example"} } type NetcatCommand struct { hostName string port int format string } func (n *NetcatCommand) run(c *kingpin.ParseContext) error { fmt.Printf("Would have run netcat to hostname %v, port %d, and output format %v\n", n.hostName, n.port, n.format) return nil } func configureNetcatCommand(app *kingpin.Application) { c := &NetcatCommand{} nc := app.Command("nc", "Connect to a Host").Action(c.run) nc.Flag("nop-flag", "Example of a flag with no options").Bool() // You can provide hint options using a function to generate them nc.Flag("host", "Provide a hostname to nc"). Required(). HintAction(listHosts). StringVar(&c.hostName) // You can provide hint options statically nc.Flag("port", "Provide a port to connect to"). Required(). HintOptions("80", "443", "8080"). IntVar(&c.port) // Enum/EnumVar options will be turned into completion options automatically nc.Flag("format", "Define the output format"). Default("raw"). EnumVar(&c.format, "raw", "json") // You can combine HintOptions with HintAction too nc.Flag("host-with-multi", "Define a hostname"). HintAction(listHosts). HintOptions("myhost.com"). String() // And combine with themselves nc.Flag("host-with-multi-options", "Define a hostname"). HintOptions("myhost.com"). HintOptions("myhost2.com"). String() // If you specify HintOptions/HintActions for Enum/EnumVar, the options // provided for Enum/EnumVar will be overridden. nc.Flag("format-with-override-1", "Define a format"). HintAction(listHosts). Enum("option1", "option2") nc.Flag("format-with-override-2", "Define a format"). HintOptions("myhost.com", "myhost2.com"). Enum("option1", "option2") } func addSubCommand(app *kingpin.Application, name string, description string) { c := app.Command(name, description).Action(func(c *kingpin.ParseContext) error { fmt.Printf("Would have run command %s.\n", name) return nil }) c.Flag("nop-flag", "Example of a flag with no options").Bool() } func main() { app := kingpin.New("completion", "My application with bash completion.") app.Flag("flag-1", "").String() app.Flag("flag-2", "").HintOptions("opt1", "opt2").String() configureNetcatCommand(app) // Add some additional top level commands addSubCommand(app, "ls", "Additional top level command to show command completion") addSubCommand(app, "ping", "Additional top level command to show command completion") addSubCommand(app, "nmap", "Additional top level command to show command completion") kingpin.MustParse(app.Parse(os.Args[1:])) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/curl/000077500000000000000000000000001330143245600231215ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/curl/main.go000066400000000000000000000055301330143245600243770ustar00rootroot00000000000000// A curl-like HTTP command-line client. package main import ( "errors" "fmt" "io" "net/http" "os" "strings" "gopkg.in/alecthomas/kingpin.v2" ) var ( timeout = kingpin.Flag("timeout", "Set connection timeout.").Short('t').Default("5s").Duration() headers = HTTPHeader(kingpin.Flag("headers", "Add HTTP headers to the request.").Short('H').PlaceHolder("HEADER=VALUE")) get = kingpin.Command("get", "GET a resource.").Default() getFlag = get.Flag("test", "Test flag").Bool() getURL = get.Command("url", "Retrieve a URL.").Default() getURLURL = getURL.Arg("url", "URL to GET.").Required().URL() getFile = get.Command("file", "Retrieve a file.") getFileFile = getFile.Arg("file", "File to retrieve.").Required().ExistingFile() post = kingpin.Command("post", "POST a resource.") postData = post.Flag("data", "Key-value data to POST").Short('d').PlaceHolder("KEY:VALUE").StringMap() postBinaryFile = post.Flag("data-binary", "File with binary data to POST.").File() postURL = post.Arg("url", "URL to POST to.").Required().URL() ) 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 "" } func HTTPHeader(s kingpin.Settings) (target *http.Header) { target = &http.Header{} s.SetValue((*HTTPHeaderValue)(target)) return } func applyRequest(req *http.Request) error { req.Header = *headers resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode > 299 { return fmt.Errorf("HTTP request failed: %s", resp.Status) } _, err = io.Copy(os.Stdout, resp.Body) return err } func apply(method string, url string) error { req, err := http.NewRequest(method, url, nil) if err != nil { return err } return applyRequest(req) } func applyPOST() error { req, err := http.NewRequest("POST", (*postURL).String(), nil) if err != nil { return err } if len(*postData) > 0 { for key, value := range *postData { req.Form.Set(key, value) } } else if postBinaryFile != nil { if headers.Get("Content-Type") != "" { headers.Set("Content-Type", "application/octet-stream") } req.Body = *postBinaryFile } else { return errors.New("--data or --data-binary must be provided to POST") } return applyRequest(req) } func main() { kingpin.UsageTemplate(kingpin.CompactUsageTemplate).Version("1.0").Author("Alec Thomas") kingpin.CommandLine.Help = "An example implementation of curl." switch kingpin.Parse() { case "get url": kingpin.FatalIfError(apply("GET", (*getURLURL).String()), "GET failed") case "post": kingpin.FatalIfError(applyPOST(), "POST failed") } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/modular/000077500000000000000000000000001330143245600236175ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/modular/main.go000066400000000000000000000010761330143245600250760ustar00rootroot00000000000000package main import ( "fmt" "os" "gopkg.in/alecthomas/kingpin.v2" ) // Context for "ls" command type LsCommand struct { All bool } func (l *LsCommand) run(c *kingpin.ParseContext) error { fmt.Printf("all=%v\n", l.All) return nil } func configureLsCommand(app *kingpin.Application) { c := &LsCommand{} ls := app.Command("ls", "List files.").Action(c.run) ls.Flag("all", "List all files.").Short('a').BoolVar(&c.All) } func main() { app := kingpin.New("modular", "My modular application.") configureLsCommand(app) kingpin.MustParse(app.Parse(os.Args[1:])) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/ping/000077500000000000000000000000001330143245600231115ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/_examples/ping/main.go000066400000000000000000000010511330143245600243610ustar00rootroot00000000000000package main import ( "fmt" "gopkg.in/alecthomas/kingpin.v2" ) var ( debug = kingpin.Flag("debug", "Enable debug mode.").Bool() timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").OverrideDefaultFromEnvar("PING_TIMEOUT").Required().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.Version("0.0.1") kingpin.Parse() fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/actions.go000066400000000000000000000016771330143245600222010ustar00rootroot00000000000000package kingpin // Action callback executed at various stages after all values are populated. // The application, commands, arguments and flags all have corresponding // actions. type Action func(*ParseContext) error type actionMixin struct { actions []Action preActions []Action } type actionApplier interface { applyActions(*ParseContext) error applyPreActions(*ParseContext) error } func (a *actionMixin) addAction(action Action) { a.actions = append(a.actions, action) } func (a *actionMixin) addPreAction(action Action) { a.preActions = append(a.preActions, action) } func (a *actionMixin) applyActions(context *ParseContext) error { for _, action := range a.actions { if err := action(context); err != nil { return err } } return nil } func (a *actionMixin) applyPreActions(context *ParseContext) error { for _, preAction := range a.preActions { if err := preAction(context); err != nil { return err } } return nil } golang-gopkg-alecthomas-kingpin.v2-2.2.6/app.go000066400000000000000000000444301330143245600213130ustar00rootroot00000000000000package kingpin import ( "fmt" "io" "os" "regexp" "strings" ) var ( ErrCommandNotSpecified = fmt.Errorf("command not specified") ) var ( envarTransformRegexp = regexp.MustCompile(`[^a-zA-Z0-9_]+`) ) type ApplicationValidator func(*Application) error // An Application contains the definitions of flags, arguments and commands // for an application. type Application struct { cmdMixin initialized bool Name string Help string author string version string errorWriter io.Writer // Destination for errors. usageWriter io.Writer // Destination for usage usageTemplate string validator ApplicationValidator terminate func(status int) // See Terminate() noInterspersed bool // can flags be interspersed with args (or must they come first) defaultEnvars bool completion bool // Help flag. Exposed for user customisation. HelpFlag *FlagClause // Help command. Exposed for user customisation. May be nil. HelpCommand *CmdClause // Version flag. Exposed for user customisation. May be nil. VersionFlag *FlagClause } // New creates a new Kingpin application instance. func New(name, help string) *Application { a := &Application{ Name: name, Help: help, errorWriter: os.Stderr, // Left for backwards compatibility purposes. usageWriter: os.Stderr, usageTemplate: DefaultUsageTemplate, terminate: os.Exit, } a.flagGroup = newFlagGroup() a.argGroup = newArgGroup() a.cmdGroup = newCmdGroup(a) a.HelpFlag = a.Flag("help", "Show context-sensitive help (also try --help-long and --help-man).") a.HelpFlag.Bool() a.Flag("help-long", "Generate long help.").Hidden().PreAction(a.generateLongHelp).Bool() a.Flag("help-man", "Generate a man page.").Hidden().PreAction(a.generateManPage).Bool() a.Flag("completion-bash", "Output possible completions for the given args.").Hidden().BoolVar(&a.completion) a.Flag("completion-script-bash", "Generate completion script for bash.").Hidden().PreAction(a.generateBashCompletionScript).Bool() a.Flag("completion-script-zsh", "Generate completion script for ZSH.").Hidden().PreAction(a.generateZSHCompletionScript).Bool() return a } func (a *Application) generateLongHelp(c *ParseContext) error { a.Writer(os.Stdout) if err := a.UsageForContextWithTemplate(c, 2, LongHelpTemplate); err != nil { return err } a.terminate(0) return nil } func (a *Application) generateManPage(c *ParseContext) error { a.Writer(os.Stdout) if err := a.UsageForContextWithTemplate(c, 2, ManPageTemplate); err != nil { return err } a.terminate(0) return nil } func (a *Application) generateBashCompletionScript(c *ParseContext) error { a.Writer(os.Stdout) if err := a.UsageForContextWithTemplate(c, 2, BashCompletionTemplate); err != nil { return err } a.terminate(0) return nil } func (a *Application) generateZSHCompletionScript(c *ParseContext) error { a.Writer(os.Stdout) if err := a.UsageForContextWithTemplate(c, 2, ZshCompletionTemplate); err != nil { return err } a.terminate(0) return nil } // DefaultEnvars configures all flags (that do not already have an associated // envar) to use a default environment variable in the form "_". // // For example, if the application is named "foo" and a flag is named "bar- // waz" the environment variable: "FOO_BAR_WAZ". func (a *Application) DefaultEnvars() *Application { a.defaultEnvars = true return a } // Terminate specifies the termination handler. Defaults to os.Exit(status). // If nil is passed, a no-op function will be used. func (a *Application) Terminate(terminate func(int)) *Application { if terminate == nil { terminate = func(int) {} } a.terminate = terminate return a } // Writer specifies the writer to use for usage and errors. Defaults to os.Stderr. // DEPRECATED: See ErrorWriter and UsageWriter. func (a *Application) Writer(w io.Writer) *Application { a.errorWriter = w a.usageWriter = w return a } // ErrorWriter sets the io.Writer to use for errors. func (a *Application) ErrorWriter(w io.Writer) *Application { a.errorWriter = w return a } // UsageWriter sets the io.Writer to use for errors. func (a *Application) UsageWriter(w io.Writer) *Application { a.usageWriter = w return a } // UsageTemplate specifies the text template to use when displaying usage // information. The default is UsageTemplate. func (a *Application) UsageTemplate(template string) *Application { a.usageTemplate = template return a } // Validate sets a validation function to run when parsing. func (a *Application) Validate(validator ApplicationValidator) *Application { a.validator = validator return a } // ParseContext parses the given command line and returns the fully populated // ParseContext. func (a *Application) ParseContext(args []string) (*ParseContext, error) { return a.parseContext(false, args) } func (a *Application) parseContext(ignoreDefault bool, args []string) (*ParseContext, error) { if err := a.init(); err != nil { return nil, err } context := tokenize(args, ignoreDefault) err := parse(context, a) return context, err } // Parse parses command-line arguments. It returns the selected command and an // error. The selected command will be a space separated subcommand, if // subcommands have been configured. // // This will populate all flag and argument values, call all callbacks, and so // on. func (a *Application) Parse(args []string) (command string, err error) { context, parseErr := a.ParseContext(args) selected := []string{} var setValuesErr error if context == nil { // Since we do not throw error immediately, there could be a case // where a context returns nil. Protect against that. return "", parseErr } if err = a.setDefaults(context); err != nil { return "", err } selected, setValuesErr = a.setValues(context) if err = a.applyPreActions(context, !a.completion); err != nil { return "", err } if a.completion { a.generateBashCompletion(context) a.terminate(0) } else { if parseErr != nil { return "", parseErr } a.maybeHelp(context) if !context.EOL() { return "", fmt.Errorf("unexpected argument '%s'", context.Peek()) } if setValuesErr != nil { return "", setValuesErr } command, err = a.execute(context, selected) if err == ErrCommandNotSpecified { a.writeUsage(context, nil) } } return command, err } func (a *Application) writeUsage(context *ParseContext, err error) { if err != nil { a.Errorf("%s", err) } if err := a.UsageForContext(context); err != nil { panic(err) } if err != nil { a.terminate(1) } else { a.terminate(0) } } func (a *Application) maybeHelp(context *ParseContext) { for _, element := range context.Elements { if flag, ok := element.Clause.(*FlagClause); ok && flag == a.HelpFlag { // Re-parse the command-line ignoring defaults, so that help works correctly. context, _ = a.parseContext(true, context.rawArgs) a.writeUsage(context, nil) } } } // Version adds a --version flag for displaying the application version. func (a *Application) Version(version string) *Application { a.version = version a.VersionFlag = a.Flag("version", "Show application version.").PreAction(func(*ParseContext) error { fmt.Fprintln(a.usageWriter, version) a.terminate(0) return nil }) a.VersionFlag.Bool() return a } // Author sets the author output by some help templates. func (a *Application) Author(author string) *Application { a.author = author return a } // Action callback to call when all values are populated and parsing is // complete, but before any command, flag or argument actions. // // All Action() callbacks are called in the order they are encountered on the // command line. func (a *Application) Action(action Action) *Application { a.addAction(action) return a } // Action called after parsing completes but before validation and execution. func (a *Application) PreAction(action Action) *Application { a.addPreAction(action) return a } // Command adds a new top-level command. func (a *Application) Command(name, help string) *CmdClause { return a.addCommand(name, help) } // Interspersed control if flags can be interspersed with positional arguments // // true (the default) means that they can, false means that all the flags must appear before the first positional arguments. func (a *Application) Interspersed(interspersed bool) *Application { a.noInterspersed = !interspersed return a } func (a *Application) defaultEnvarPrefix() string { if a.defaultEnvars { return a.Name } return "" } func (a *Application) init() error { if a.initialized { return nil } if a.cmdGroup.have() && a.argGroup.have() { return fmt.Errorf("can't mix top-level Arg()s with Command()s") } // If we have subcommands, add a help command at the top-level. if a.cmdGroup.have() { var command []string a.HelpCommand = a.Command("help", "Show help.").PreAction(func(context *ParseContext) error { a.Usage(command) a.terminate(0) return nil }) a.HelpCommand.Arg("command", "Show help on command.").StringsVar(&command) // Make help first command. l := len(a.commandOrder) a.commandOrder = append(a.commandOrder[l-1:l], a.commandOrder[:l-1]...) } if err := a.flagGroup.init(a.defaultEnvarPrefix()); err != nil { return err } if err := a.cmdGroup.init(); err != nil { return err } if err := a.argGroup.init(); err != nil { return err } for _, cmd := range a.commands { if err := cmd.init(); err != nil { return err } } flagGroups := []*flagGroup{a.flagGroup} for _, cmd := range a.commandOrder { if err := checkDuplicateFlags(cmd, flagGroups); err != nil { return err } } a.initialized = true return nil } // Recursively check commands for duplicate flags. func checkDuplicateFlags(current *CmdClause, flagGroups []*flagGroup) error { // Check for duplicates. for _, flags := range flagGroups { for _, flag := range current.flagOrder { if flag.shorthand != 0 { if _, ok := flags.short[string(flag.shorthand)]; ok { return fmt.Errorf("duplicate short flag -%c", flag.shorthand) } } if _, ok := flags.long[flag.name]; ok { return fmt.Errorf("duplicate long flag --%s", flag.name) } } } flagGroups = append(flagGroups, current.flagGroup) // Check subcommands. for _, subcmd := range current.commandOrder { if err := checkDuplicateFlags(subcmd, flagGroups); err != nil { return err } } return nil } func (a *Application) execute(context *ParseContext, selected []string) (string, error) { var err error if err = a.validateRequired(context); err != nil { return "", err } if err = a.applyValidators(context); err != nil { return "", err } if err = a.applyActions(context); err != nil { return "", err } command := strings.Join(selected, " ") if command == "" && a.cmdGroup.have() { return "", ErrCommandNotSpecified } return command, err } func (a *Application) setDefaults(context *ParseContext) error { flagElements := map[string]*ParseElement{} for _, element := range context.Elements { if flag, ok := element.Clause.(*FlagClause); ok { if flag.name == "help" { return nil } flagElements[flag.name] = element } } argElements := map[string]*ParseElement{} for _, element := range context.Elements { if arg, ok := element.Clause.(*ArgClause); ok { argElements[arg.name] = element } } // Check required flags and set defaults. for _, flag := range context.flags.long { if flagElements[flag.name] == nil { if err := flag.setDefault(); err != nil { return err } } } for _, arg := range context.arguments.args { if argElements[arg.name] == nil { if err := arg.setDefault(); err != nil { return err } } } return nil } func (a *Application) validateRequired(context *ParseContext) error { flagElements := map[string]*ParseElement{} for _, element := range context.Elements { if flag, ok := element.Clause.(*FlagClause); ok { flagElements[flag.name] = element } } argElements := map[string]*ParseElement{} for _, element := range context.Elements { if arg, ok := element.Clause.(*ArgClause); ok { argElements[arg.name] = element } } // Check required flags and set defaults. for _, flag := range context.flags.long { if flagElements[flag.name] == nil { // Check required flags were provided. if flag.needsValue() { return fmt.Errorf("required flag --%s not provided", flag.name) } } } for _, arg := range context.arguments.args { if argElements[arg.name] == nil { if arg.needsValue() { return fmt.Errorf("required argument '%s' not provided", arg.name) } } } return nil } func (a *Application) setValues(context *ParseContext) (selected []string, err error) { // Set all arg and flag values. var ( lastCmd *CmdClause flagSet = map[string]struct{}{} ) for _, element := range context.Elements { switch clause := element.Clause.(type) { case *FlagClause: if _, ok := flagSet[clause.name]; ok { if v, ok := clause.value.(repeatableFlag); !ok || !v.IsCumulative() { return nil, fmt.Errorf("flag '%s' cannot be repeated", clause.name) } } if err = clause.value.Set(*element.Value); err != nil { return } flagSet[clause.name] = struct{}{} case *ArgClause: if err = clause.value.Set(*element.Value); err != nil { return } case *CmdClause: if clause.validator != nil { if err = clause.validator(clause); err != nil { return } } selected = append(selected, clause.name) lastCmd = clause } } if lastCmd != nil && len(lastCmd.commands) > 0 { return nil, fmt.Errorf("must select a subcommand of '%s'", lastCmd.FullCommand()) } return } func (a *Application) applyValidators(context *ParseContext) (err error) { // Call command validation functions. for _, element := range context.Elements { if cmd, ok := element.Clause.(*CmdClause); ok && cmd.validator != nil { if err = cmd.validator(cmd); err != nil { return err } } } if a.validator != nil { err = a.validator(a) } return err } func (a *Application) applyPreActions(context *ParseContext, dispatch bool) error { if err := a.actionMixin.applyPreActions(context); err != nil { return err } // Dispatch to actions. if dispatch { for _, element := range context.Elements { if applier, ok := element.Clause.(actionApplier); ok { if err := applier.applyPreActions(context); err != nil { return err } } } } return nil } func (a *Application) applyActions(context *ParseContext) error { if err := a.actionMixin.applyActions(context); err != nil { return err } // Dispatch to actions. for _, element := range context.Elements { if applier, ok := element.Clause.(actionApplier); ok { if err := applier.applyActions(context); err != nil { return err } } } return nil } // Errorf prints an error message to w in the format ": error: ". func (a *Application) Errorf(format string, args ...interface{}) { fmt.Fprintf(a.errorWriter, a.Name+": error: "+format+"\n", args...) } // Fatalf writes a formatted error to w then terminates with exit status 1. func (a *Application) Fatalf(format string, args ...interface{}) { a.Errorf(format, args...) a.terminate(1) } // FatalUsage prints an error message followed by usage information, then // exits with a non-zero status. func (a *Application) FatalUsage(format string, args ...interface{}) { a.Errorf(format, args...) // Force usage to go to error output. a.usageWriter = a.errorWriter a.Usage([]string{}) a.terminate(1) } // FatalUsageContext writes a printf formatted error message to w, then usage // information for the given ParseContext, before exiting. func (a *Application) FatalUsageContext(context *ParseContext, format string, args ...interface{}) { a.Errorf(format, args...) if err := a.UsageForContext(context); err != nil { panic(err) } a.terminate(1) } // FatalIfError prints an error and exits if err is not nil. The error is printed // with the given formatted string, if any. func (a *Application) FatalIfError(err error, format string, args ...interface{}) { if err != nil { prefix := "" if format != "" { prefix = fmt.Sprintf(format, args...) + ": " } a.Errorf(prefix+"%s", err) a.terminate(1) } } func (a *Application) completionOptions(context *ParseContext) []string { args := context.rawArgs var ( currArg string prevArg string target cmdMixin ) numArgs := len(args) if numArgs > 1 { args = args[1:] currArg = args[len(args)-1] } if numArgs > 2 { prevArg = args[len(args)-2] } target = a.cmdMixin if context.SelectedCommand != nil { // A subcommand was in use. We will use it as the target target = context.SelectedCommand.cmdMixin } if (currArg != "" && strings.HasPrefix(currArg, "--")) || strings.HasPrefix(prevArg, "--") { // Perform completion for A flag. The last/current argument started with "-" var ( flagName string // The name of a flag if given (could be half complete) flagValue string // The value assigned to a flag (if given) (could be half complete) ) if strings.HasPrefix(prevArg, "--") && !strings.HasPrefix(currArg, "--") { // Matches: ./myApp --flag value // Wont Match: ./myApp --flag -- flagName = prevArg[2:] // Strip the "--" flagValue = currArg } else if strings.HasPrefix(currArg, "--") { // Matches: ./myApp --flag -- // Matches: ./myApp --flag somevalue -- // Matches: ./myApp -- flagName = currArg[2:] // Strip the "--" } options, flagMatched, valueMatched := target.FlagCompletion(flagName, flagValue) if valueMatched { // Value Matched. Show cmdCompletions return target.CmdCompletion(context) } // Add top level flags if we're not at the top level and no match was found. if context.SelectedCommand != nil && !flagMatched { topOptions, topFlagMatched, topValueMatched := a.FlagCompletion(flagName, flagValue) if topValueMatched { // Value Matched. Back to cmdCompletions return target.CmdCompletion(context) } if topFlagMatched { // Top level had a flag which matched the input. Return it's options. options = topOptions } else { // Add top level flags options = append(options, topOptions...) } } return options } // Perform completion for sub commands and arguments. return target.CmdCompletion(context) } func (a *Application) generateBashCompletion(context *ParseContext) { options := a.completionOptions(context) fmt.Printf("%s", strings.Join(options, "\n")) } func envarTransform(name string) string { return strings.ToUpper(envarTransformRegexp.ReplaceAllString(name, "_")) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/app_test.go000066400000000000000000000255761330143245600223640ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "github.com/stretchr/testify/assert" "sort" "strings" "testing" "time" ) func newTestApp() *Application { return New("test", "").Terminate(nil) } func TestCommander(t *testing.T) { c := newTestApp() ping := c.Command("ping", "Ping an IP address.") pingTTL := ping.Flag("ttl", "TTL for ICMP packets").Short('t').Default("5s").Duration() selected, err := c.Parse([]string{"ping"}) assert.NoError(t, err) assert.Equal(t, "ping", selected) assert.Equal(t, 5*time.Second, *pingTTL) selected, err = c.Parse([]string{"ping", "--ttl=10s"}) assert.NoError(t, err) assert.Equal(t, "ping", selected) assert.Equal(t, 10*time.Second, *pingTTL) } func TestRequiredFlags(t *testing.T) { c := newTestApp() c.Flag("a", "a").String() c.Flag("b", "b").Required().String() _, err := c.Parse([]string{"--a=foo"}) assert.Error(t, err) _, err = c.Parse([]string{"--b=foo"}) assert.NoError(t, err) } func TestRepeatableFlags(t *testing.T) { c := newTestApp() c.Flag("a", "a").String() c.Flag("b", "b").Strings() _, err := c.Parse([]string{"--a=foo", "--a=bar"}) assert.Error(t, err) _, err = c.Parse([]string{"--b=foo", "--b=bar"}) assert.NoError(t, err) } func TestInvalidDefaultFlagValueErrors(t *testing.T) { c := newTestApp() c.Flag("foo", "foo").Default("a").Int() _, err := c.Parse([]string{}) assert.Error(t, err) } func TestInvalidDefaultArgValueErrors(t *testing.T) { c := newTestApp() cmd := c.Command("cmd", "cmd") cmd.Arg("arg", "arg").Default("one").Int() _, err := c.Parse([]string{"cmd"}) assert.Error(t, err) } func TestArgsRequiredAfterNonRequiredErrors(t *testing.T) { c := newTestApp() cmd := c.Command("cmd", "") cmd.Arg("a", "a").String() cmd.Arg("b", "b").Required().String() _, err := c.Parse([]string{"cmd"}) assert.Error(t, err) } func TestArgsMultipleRequiredThenNonRequired(t *testing.T) { c := newTestApp().Writer(ioutil.Discard) cmd := c.Command("cmd", "") cmd.Arg("a", "a").Required().String() cmd.Arg("b", "b").Required().String() cmd.Arg("c", "c").String() cmd.Arg("d", "d").String() _, err := c.Parse([]string{"cmd", "a", "b"}) assert.NoError(t, err) _, err = c.Parse([]string{}) assert.Error(t, err) } func TestDispatchCallbackIsCalled(t *testing.T) { dispatched := false c := newTestApp() c.Command("cmd", "").Action(func(*ParseContext) error { dispatched = true return nil }) _, err := c.Parse([]string{"cmd"}) assert.NoError(t, err) assert.True(t, dispatched) } func TestTopLevelArgWorks(t *testing.T) { c := newTestApp() s := c.Arg("arg", "help").String() _, err := c.Parse([]string{"foo"}) assert.NoError(t, err) assert.Equal(t, "foo", *s) } func TestTopLevelArgCantBeUsedWithCommands(t *testing.T) { c := newTestApp() c.Arg("arg", "help").String() c.Command("cmd", "help") _, err := c.Parse([]string{}) assert.Error(t, err) } func TestTooManyArgs(t *testing.T) { a := newTestApp() a.Arg("a", "").String() _, err := a.Parse([]string{"a", "b"}) assert.Error(t, err) } func TestTooManyArgsAfterCommand(t *testing.T) { a := newTestApp() a.Command("a", "") assert.NoError(t, a.init()) _, err := a.Parse([]string{"a", "b"}) assert.Error(t, err) } func TestArgsLooksLikeFlagsWithConsumeRemainder(t *testing.T) { a := newTestApp() a.Arg("opts", "").Required().Strings() _, err := a.Parse([]string{"hello", "-world"}) assert.Error(t, err) } func TestCommandParseDoesNotResetFlagsToDefault(t *testing.T) { app := newTestApp() flag := app.Flag("flag", "").Default("default").String() app.Command("cmd", "") _, err := app.Parse([]string{"--flag=123", "cmd"}) assert.NoError(t, err) assert.Equal(t, "123", *flag) } func TestCommandParseDoesNotFailRequired(t *testing.T) { app := newTestApp() flag := app.Flag("flag", "").Required().String() app.Command("cmd", "") _, err := app.Parse([]string{"cmd", "--flag=123"}) assert.NoError(t, err) assert.Equal(t, "123", *flag) } func TestSelectedCommand(t *testing.T) { app := newTestApp() c0 := app.Command("c0", "") c0.Command("c1", "") s, err := app.Parse([]string{"c0", "c1"}) assert.NoError(t, err) assert.Equal(t, "c0 c1", s) } func TestSubCommandRequired(t *testing.T) { app := newTestApp() c0 := app.Command("c0", "") c0.Command("c1", "") _, err := app.Parse([]string{"c0"}) assert.Error(t, err) } func TestInterspersedFalse(t *testing.T) { app := newTestApp().Interspersed(false) a1 := app.Arg("a1", "").String() a2 := app.Arg("a2", "").String() f1 := app.Flag("flag", "").String() _, err := app.Parse([]string{"a1", "--flag=flag"}) assert.NoError(t, err) assert.Equal(t, "a1", *a1) assert.Equal(t, "--flag=flag", *a2) assert.Equal(t, "", *f1) } func TestInterspersedTrue(t *testing.T) { // test once with the default value and once with explicit true for i := 0; i < 2; i++ { app := newTestApp() if i != 0 { t.Log("Setting explicit") app.Interspersed(true) } else { t.Log("Using default") } a1 := app.Arg("a1", "").String() a2 := app.Arg("a2", "").String() f1 := app.Flag("flag", "").String() _, err := app.Parse([]string{"a1", "--flag=flag"}) assert.NoError(t, err) assert.Equal(t, "a1", *a1) assert.Equal(t, "", *a2) assert.Equal(t, "flag", *f1) } } func TestDefaultEnvars(t *testing.T) { a := New("some-app", "").Terminate(nil).DefaultEnvars() f0 := a.Flag("some-flag", "") f0.Bool() f1 := a.Flag("some-other-flag", "").NoEnvar() f1.Bool() f2 := a.Flag("a-1-flag", "") f2.Bool() _, err := a.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "SOME_APP_SOME_FLAG", f0.envar) assert.Equal(t, "", f1.envar) assert.Equal(t, "SOME_APP_A_1_FLAG", f2.envar) } func TestBashCompletionOptionsWithEmptyApp(t *testing.T) { a := newTestApp() context, err := a.ParseContext([]string{"--completion-bash"}) if err != nil { t.Errorf("Unexpected error whilst parsing context: [%v]", err) } args := a.completionOptions(context) assert.Equal(t, []string(nil), args) } func TestBashCompletionOptions(t *testing.T) { a := newTestApp() a.Command("one", "") a.Flag("flag-0", "").String() a.Flag("flag-1", "").HintOptions("opt1", "opt2", "opt3").String() two := a.Command("two", "") two.Flag("flag-2", "").String() two.Flag("flag-3", "").HintOptions("opt4", "opt5", "opt6").String() three := a.Command("three", "") three.Flag("flag-4", "").String() three.Arg("arg-1", "").String() three.Arg("arg-2", "").HintOptions("arg-2-opt-1", "arg-2-opt-2").String() three.Arg("arg-3", "").String() three.Arg("arg-4", "").HintAction(func() []string { return []string{"arg-4-opt-1", "arg-4-opt-2"} }).String() cases := []struct { Args string ExpectedOptions []string }{ { Args: "--completion-bash", ExpectedOptions: []string{"help", "one", "three", "two"}, }, { Args: "--completion-bash --", ExpectedOptions: []string{"--flag-0", "--flag-1", "--help"}, }, { Args: "--completion-bash --fla", ExpectedOptions: []string{"--flag-0", "--flag-1", "--help"}, }, { // No options available for flag-0, return to cmd completion Args: "--completion-bash --flag-0", ExpectedOptions: []string{"help", "one", "three", "two"}, }, { Args: "--completion-bash --flag-0 --", ExpectedOptions: []string{"--flag-0", "--flag-1", "--help"}, }, { Args: "--completion-bash --flag-1", ExpectedOptions: []string{"opt1", "opt2", "opt3"}, }, { Args: "--completion-bash --flag-1 opt", ExpectedOptions: []string{"opt1", "opt2", "opt3"}, }, { Args: "--completion-bash --flag-1 opt1", ExpectedOptions: []string{"help", "one", "three", "two"}, }, { Args: "--completion-bash --flag-1 opt1 --", ExpectedOptions: []string{"--flag-0", "--flag-1", "--help"}, }, // Try Subcommand { Args: "--completion-bash two", ExpectedOptions: []string(nil), }, { Args: "--completion-bash two --", ExpectedOptions: []string{"--help", "--flag-2", "--flag-3", "--flag-0", "--flag-1"}, }, { Args: "--completion-bash two --flag", ExpectedOptions: []string{"--help", "--flag-2", "--flag-3", "--flag-0", "--flag-1"}, }, { Args: "--completion-bash two --flag-2", ExpectedOptions: []string(nil), }, { // Top level flags carry downwards Args: "--completion-bash two --flag-1", ExpectedOptions: []string{"opt1", "opt2", "opt3"}, }, { // Top level flags carry downwards Args: "--completion-bash two --flag-1 opt", ExpectedOptions: []string{"opt1", "opt2", "opt3"}, }, { // Top level flags carry downwards Args: "--completion-bash two --flag-1 opt1", ExpectedOptions: []string(nil), }, { Args: "--completion-bash two --flag-3", ExpectedOptions: []string{"opt4", "opt5", "opt6"}, }, { Args: "--completion-bash two --flag-3 opt", ExpectedOptions: []string{"opt4", "opt5", "opt6"}, }, { Args: "--completion-bash two --flag-3 opt4", ExpectedOptions: []string(nil), }, { Args: "--completion-bash two --flag-3 opt4 --", ExpectedOptions: []string{"--help", "--flag-2", "--flag-3", "--flag-0", "--flag-1"}, }, // Args complete { // After a command with an arg with no options, nothing should be // shown Args: "--completion-bash three ", ExpectedOptions: []string(nil), }, { // After a command with an arg, explicitly starting a flag should // complete flags Args: "--completion-bash three --", ExpectedOptions: []string{"--flag-0", "--flag-1", "--flag-4", "--help"}, }, { // After a command with an arg that does have completions, they // should be shown Args: "--completion-bash three arg1 ", ExpectedOptions: []string{"arg-2-opt-1", "arg-2-opt-2"}, }, { // After a command with an arg that does have completions, but a // flag is started, flag options should be completed Args: "--completion-bash three arg1 --", ExpectedOptions: []string{"--flag-0", "--flag-1", "--flag-4", "--help"}, }, { // After a command with an arg that has no completions, and isn't first, // nothing should be shown Args: "--completion-bash three arg1 arg2 ", ExpectedOptions: []string(nil), }, { // After a command with a different arg that also has completions, // those different options should be shown Args: "--completion-bash three arg1 arg2 arg3 ", ExpectedOptions: []string{"arg-4-opt-1", "arg-4-opt-2"}, }, { // After a command with all args listed, nothing should complete Args: "--completion-bash three arg1 arg2 arg3 arg4", ExpectedOptions: []string(nil), }, } for _, c := range cases { context, _ := a.ParseContext(strings.Split(c.Args, " ")) args := a.completionOptions(context) sort.Strings(args) sort.Strings(c.ExpectedOptions) assert.Equal(t, c.ExpectedOptions, args, "Expected != Actual: [%v] != [%v]. \nInput was: [%v]", c.ExpectedOptions, args, c.Args) } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/args.go000066400000000000000000000077721330143245600214770ustar00rootroot00000000000000package kingpin import ( "fmt" ) type argGroup struct { args []*ArgClause } func newArgGroup() *argGroup { return &argGroup{} } func (a *argGroup) have() bool { return len(a.args) > 0 } // GetArg gets an argument definition. // // This allows existing arguments to be modified after definition but before parsing. Useful for // modular applications. func (a *argGroup) GetArg(name string) *ArgClause { for _, arg := range a.args { if arg.name == name { return arg } } return nil } func (a *argGroup) Arg(name, help string) *ArgClause { arg := newArg(name, help) a.args = append(a.args, arg) return arg } func (a *argGroup) init() error { required := 0 seen := map[string]struct{}{} previousArgMustBeLast := false for i, arg := range a.args { if previousArgMustBeLast { return fmt.Errorf("Args() can't be followed by another argument '%s'", arg.name) } if arg.consumesRemainder() { previousArgMustBeLast = true } if _, ok := seen[arg.name]; ok { return fmt.Errorf("duplicate argument '%s'", arg.name) } seen[arg.name] = struct{}{} if arg.required && required != i { return fmt.Errorf("required arguments found after non-required") } if arg.required { required++ } if err := arg.init(); err != nil { return err } } return nil } type ArgClause struct { actionMixin parserMixin completionsMixin envarMixin name string help string defaultValues []string required bool } func newArg(name, help string) *ArgClause { a := &ArgClause{ name: name, help: help, } return a } func (a *ArgClause) setDefault() error { if a.HasEnvarValue() { if v, ok := a.value.(remainderArg); !ok || !v.IsCumulative() { // Use the value as-is return a.value.Set(a.GetEnvarValue()) } for _, value := range a.GetSplitEnvarValue() { if err := a.value.Set(value); err != nil { return err } } return nil } if len(a.defaultValues) > 0 { for _, defaultValue := range a.defaultValues { if err := a.value.Set(defaultValue); err != nil { return err } } return nil } return nil } func (a *ArgClause) needsValue() bool { haveDefault := len(a.defaultValues) > 0 return a.required && !(haveDefault || a.HasEnvarValue()) } func (a *ArgClause) consumesRemainder() bool { if r, ok := a.value.(remainderArg); ok { return r.IsCumulative() } return false } // Required arguments must be input by the user. They can not have a Default() value provided. func (a *ArgClause) Required() *ArgClause { a.required = true return a } // Default values for this argument. They *must* be parseable by the value of the argument. func (a *ArgClause) Default(values ...string) *ArgClause { a.defaultValues = values return a } // Envar overrides the default value(s) for a flag from an environment variable, // if it is set. Several default values can be provided by using new lines to // separate them. func (a *ArgClause) Envar(name string) *ArgClause { a.envar = name a.noEnvar = false return a } // NoEnvar forces environment variable defaults to be disabled for this flag. // Most useful in conjunction with app.DefaultEnvars(). func (a *ArgClause) NoEnvar() *ArgClause { a.envar = "" a.noEnvar = true return a } func (a *ArgClause) Action(action Action) *ArgClause { a.addAction(action) return a } func (a *ArgClause) PreAction(action Action) *ArgClause { a.addPreAction(action) return a } // HintAction registers a HintAction (function) for the arg to provide completions func (a *ArgClause) HintAction(action HintAction) *ArgClause { a.addHintAction(action) return a } // HintOptions registers any number of options for the flag to provide completions func (a *ArgClause) HintOptions(options ...string) *ArgClause { a.addHintAction(func() []string { return options }) return a } func (a *ArgClause) init() error { if a.required && len(a.defaultValues) > 0 { return fmt.Errorf("required argument '%s' with unusable default value", a.name) } if a.value == nil { return fmt.Errorf("no parser defined for arg '%s'", a.name) } return nil } golang-gopkg-alecthomas-kingpin.v2-2.2.6/args_test.go000066400000000000000000000042211330143245600225200ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "os" "testing" "github.com/stretchr/testify/assert" ) func TestArgRemainder(t *testing.T) { app := New("test", "") v := app.Arg("test", "").Strings() args := []string{"hello", "world"} _, err := app.Parse(args) assert.NoError(t, err) assert.Equal(t, args, *v) } func TestArgRemainderErrorsWhenNotLast(t *testing.T) { a := newArgGroup() a.Arg("test", "").Strings() a.Arg("test2", "").String() assert.Error(t, a.init()) } func TestArgMultipleRequired(t *testing.T) { terminated := false app := New("test", "") app.Version("0.0.0").Writer(ioutil.Discard) app.Arg("a", "").Required().String() app.Arg("b", "").Required().String() app.Terminate(func(int) { terminated = true }) _, err := app.Parse([]string{}) assert.Error(t, err) _, err = app.Parse([]string{"A"}) assert.Error(t, err) _, err = app.Parse([]string{"A", "B"}) assert.NoError(t, err) _, err = app.Parse([]string{"--version"}) assert.True(t, terminated) } func TestInvalidArgsDefaultCanBeOverridden(t *testing.T) { app := New("test", "") app.Arg("a", "").Default("invalid").Bool() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestArgMultipleValuesDefault(t *testing.T) { app := New("test", "") a := app.Arg("a", "").Default("default1", "default2").Strings() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, []string{"default1", "default2"}, *a) } func TestRequiredArgWithEnvarMissingErrors(t *testing.T) { app := newTestApp() app.Arg("t", "").Envar("TEST_ARG_ENVAR").Required().Int() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestArgRequiredWithEnvar(t *testing.T) { os.Setenv("TEST_ARG_ENVAR", "123") app := newTestApp() flag := app.Arg("t", "").Envar("TEST_ARG_ENVAR").Required().Int() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, 123, *flag) } func TestSubcommandArgRequiredWithEnvar(t *testing.T) { os.Setenv("TEST_ARG_ENVAR", "123") app := newTestApp() cmd := app.Command("command", "") flag := cmd.Arg("t", "").Envar("TEST_ARG_ENVAR").Required().Int() _, err := app.Parse([]string{"command"}) assert.NoError(t, err) assert.Equal(t, 123, *flag) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/cmd.go000066400000000000000000000147041330143245600212770ustar00rootroot00000000000000package kingpin import ( "fmt" "strings" ) type cmdMixin struct { *flagGroup *argGroup *cmdGroup actionMixin } // CmdCompletion returns completion options for arguments, if that's where // parsing left off, or commands if there aren't any unsatisfied args. func (c *cmdMixin) CmdCompletion(context *ParseContext) []string { var options []string // Count args already satisfied - we won't complete those, and add any // default commands' alternatives, since they weren't listed explicitly // and the user may want to explicitly list something else. argsSatisfied := 0 for _, el := range context.Elements { switch clause := el.Clause.(type) { case *ArgClause: if el.Value != nil && *el.Value != "" { argsSatisfied++ } case *CmdClause: options = append(options, clause.completionAlts...) default: } } if argsSatisfied < len(c.argGroup.args) { // Since not all args have been satisfied, show options for the current one options = append(options, c.argGroup.args[argsSatisfied].resolveCompletions()...) } else { // If all args are satisfied, then go back to completing commands for _, cmd := range c.cmdGroup.commandOrder { if !cmd.hidden { options = append(options, cmd.name) } } } return options } func (c *cmdMixin) FlagCompletion(flagName string, flagValue string) (choices []string, flagMatch bool, optionMatch bool) { // Check if flagName matches a known flag. // If it does, show the options for the flag // Otherwise, show all flags options := []string{} for _, flag := range c.flagGroup.flagOrder { // Loop through each flag and determine if a match exists if flag.name == flagName { // User typed entire flag. Need to look for flag options. options = flag.resolveCompletions() if len(options) == 0 { // No Options to Choose From, Assume Match. return options, true, true } // Loop options to find if the user specified value matches isPrefix := false matched := false for _, opt := range options { if flagValue == opt { matched = true } else if strings.HasPrefix(opt, flagValue) { isPrefix = true } } // Matched Flag Directly // Flag Value Not Prefixed, and Matched Directly return options, true, !isPrefix && matched } if !flag.hidden { options = append(options, "--"+flag.name) } } // No Flag directly matched. return options, false, false } type cmdGroup struct { app *Application parent *CmdClause commands map[string]*CmdClause commandOrder []*CmdClause } func (c *cmdGroup) defaultSubcommand() *CmdClause { for _, cmd := range c.commandOrder { if cmd.isDefault { return cmd } } return nil } func (c *cmdGroup) cmdNames() []string { names := make([]string, 0, len(c.commandOrder)) for _, cmd := range c.commandOrder { names = append(names, cmd.name) } return names } // GetArg gets a command definition. // // This allows existing commands to be modified after definition but before parsing. Useful for // modular applications. func (c *cmdGroup) GetCommand(name string) *CmdClause { return c.commands[name] } func newCmdGroup(app *Application) *cmdGroup { return &cmdGroup{ app: app, commands: make(map[string]*CmdClause), } } func (c *cmdGroup) flattenedCommands() (out []*CmdClause) { for _, cmd := range c.commandOrder { if len(cmd.commands) == 0 { out = append(out, cmd) } out = append(out, cmd.flattenedCommands()...) } return } func (c *cmdGroup) addCommand(name, help string) *CmdClause { cmd := newCommand(c.app, name, help) c.commands[name] = cmd c.commandOrder = append(c.commandOrder, cmd) return cmd } func (c *cmdGroup) init() error { seen := map[string]bool{} if c.defaultSubcommand() != nil && !c.have() { return fmt.Errorf("default subcommand %q provided but no subcommands defined", c.defaultSubcommand().name) } defaults := []string{} for _, cmd := range c.commandOrder { if cmd.isDefault { defaults = append(defaults, cmd.name) } if seen[cmd.name] { return fmt.Errorf("duplicate command %q", cmd.name) } seen[cmd.name] = true for _, alias := range cmd.aliases { if seen[alias] { return fmt.Errorf("alias duplicates existing command %q", alias) } c.commands[alias] = cmd } if err := cmd.init(); err != nil { return err } } if len(defaults) > 1 { return fmt.Errorf("more than one default subcommand exists: %s", strings.Join(defaults, ", ")) } return nil } func (c *cmdGroup) have() bool { return len(c.commands) > 0 } type CmdClauseValidator func(*CmdClause) error // A CmdClause is a single top-level command. It encapsulates a set of flags // and either subcommands or positional arguments. type CmdClause struct { cmdMixin app *Application name string aliases []string help string isDefault bool validator CmdClauseValidator hidden bool completionAlts []string } func newCommand(app *Application, name, help string) *CmdClause { c := &CmdClause{ app: app, name: name, help: help, } c.flagGroup = newFlagGroup() c.argGroup = newArgGroup() c.cmdGroup = newCmdGroup(app) return c } // Add an Alias for this command. func (c *CmdClause) Alias(name string) *CmdClause { c.aliases = append(c.aliases, name) return c } // Validate sets a validation function to run when parsing. func (c *CmdClause) Validate(validator CmdClauseValidator) *CmdClause { c.validator = validator return c } func (c *CmdClause) FullCommand() string { out := []string{c.name} for p := c.parent; p != nil; p = p.parent { out = append([]string{p.name}, out...) } return strings.Join(out, " ") } // Command adds a new sub-command. func (c *CmdClause) Command(name, help string) *CmdClause { cmd := c.addCommand(name, help) cmd.parent = c return cmd } // Default makes this command the default if commands don't match. func (c *CmdClause) Default() *CmdClause { c.isDefault = true return c } func (c *CmdClause) Action(action Action) *CmdClause { c.addAction(action) return c } func (c *CmdClause) PreAction(action Action) *CmdClause { c.addPreAction(action) return c } func (c *CmdClause) init() error { if err := c.flagGroup.init(c.app.defaultEnvarPrefix()); err != nil { return err } if c.argGroup.have() && c.cmdGroup.have() { return fmt.Errorf("can't mix Arg()s with Command()s") } if err := c.argGroup.init(); err != nil { return err } if err := c.cmdGroup.init(); err != nil { return err } return nil } func (c *CmdClause) Hidden() *CmdClause { c.hidden = true return c } golang-gopkg-alecthomas-kingpin.v2-2.2.6/cmd/000077500000000000000000000000001330143245600207425ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/cmd/genvalues/000077500000000000000000000000001330143245600227335ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v2-2.2.6/cmd/genvalues/main.go000066400000000000000000000052671330143245600242200ustar00rootroot00000000000000package main import ( "encoding/json" "os" "os/exec" "strings" "github.com/alecthomas/template" ) const ( tmpl = `package kingpin // This file is autogenerated by "go generate .". Do not modify. {{range .}} {{if not .NoValueParser}} // -- {{.Type}} Value type {{.|ValueName}} struct { v *{{.Type}} } func new{{.|Name}}Value(p *{{.Type}}) *{{.|ValueName}} { return &{{.|ValueName}}{p} } func (f *{{.|ValueName}}) Set(s string) error { v, err := {{.Parser}} if err == nil { *f.v = ({{.Type}})(v) } return err } func (f *{{.|ValueName}}) Get() interface{} { return ({{.Type}})(*f.v) } func (f *{{.|ValueName}}) String() string { return {{.|Format}} } {{if .Help}} // {{.Help}} {{else}}\ // {{.|Name}} parses the next command-line value as {{.Type}}. {{end}}\ func (p *parserMixin) {{.|Name}}() (target *{{.Type}}) { target = new({{.Type}}) p.{{.|Name}}Var(target) return } func (p *parserMixin) {{.|Name}}Var(target *{{.Type}}) { p.SetValue(new{{.|Name}}Value(target)) } {{end}} // {{.|Plural}} accumulates {{.Type}} values into a slice. func (p *parserMixin) {{.|Plural}}() (target *[]{{.Type}}) { target = new([]{{.Type}}) p.{{.|Plural}}Var(target) return } func (p *parserMixin) {{.|Plural}}Var(target *[]{{.Type}}) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return new{{.|Name}}Value(v.(*{{.Type}})) })) } {{end}} ` ) type Value struct { Name string `json:"name"` NoValueParser bool `json:"no_value_parser"` Type string `json:"type"` Parser string `json:"parser"` Format string `json:"format"` Plural string `json:"plural"` Help string `json:"help"` } func fatalIfError(err error) { if err != nil { panic(err) } } func main() { r, err := os.Open("values.json") fatalIfError(err) defer r.Close() v := []Value{} err = json.NewDecoder(r).Decode(&v) fatalIfError(err) valueName := func(v *Value) string { if v.Name != "" { return v.Name } return strings.Title(v.Type) } t, err := template.New("genvalues").Funcs(template.FuncMap{ "Lower": strings.ToLower, "Format": func(v *Value) string { if v.Format != "" { return v.Format } return "fmt.Sprintf(\"%v\", *f.v)" }, "ValueName": func(v *Value) string { name := valueName(v) return strings.ToLower(name[0:1]) + name[1:] + "Value" }, "Name": valueName, "Plural": func(v *Value) string { if v.Plural != "" { return v.Plural } return valueName(v) + "List" }, }).Parse(tmpl) fatalIfError(err) w, err := os.Create("values_generated.go") fatalIfError(err) defer w.Close() err = t.Execute(w, v) fatalIfError(err) err = exec.Command("goimports", "-w", "values_generated.go").Run() fatalIfError(err) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/cmd_test.go000066400000000000000000000260501330143245600223330ustar00rootroot00000000000000package kingpin import ( "sort" "strings" "github.com/stretchr/testify/assert" "testing" ) func parseAndExecute(app *Application, context *ParseContext) (string, error) { if err := parse(context, app); err != nil { return "", err } selected, err := app.setValues(context) if err != nil { return "", err } return app.execute(context, selected) } func complete(t *testing.T, app *Application, args ...string) []string { context, err := app.ParseContext(args) assert.NoError(t, err) if err != nil { return nil } completions := app.completionOptions(context) sort.Strings(completions) return completions } func TestNestedCommands(t *testing.T) { app := New("app", "") sub1 := app.Command("sub1", "") sub1.Flag("sub1", "") subsub1 := sub1.Command("sub1sub1", "") subsub1.Command("sub1sub1end", "") sub2 := app.Command("sub2", "") sub2.Flag("sub2", "") sub2.Command("sub2sub1", "") context := tokenize([]string{"sub1", "sub1sub1", "sub1sub1end"}, false) selected, err := parseAndExecute(app, context) assert.NoError(t, err) assert.True(t, context.EOL()) assert.Equal(t, "sub1 sub1sub1 sub1sub1end", selected) } func TestNestedCommandsWithArgs(t *testing.T) { app := New("app", "") cmd := app.Command("a", "").Command("b", "") a := cmd.Arg("a", "").String() b := cmd.Arg("b", "").String() context := tokenize([]string{"a", "b", "c", "d"}, false) selected, err := parseAndExecute(app, context) assert.NoError(t, err) assert.True(t, context.EOL()) assert.Equal(t, "a b", selected) assert.Equal(t, "c", *a) assert.Equal(t, "d", *b) } func TestNestedCommandsWithFlags(t *testing.T) { app := New("app", "") cmd := app.Command("a", "").Command("b", "") a := cmd.Flag("aaa", "").Short('a').String() b := cmd.Flag("bbb", "").Short('b').String() err := app.init() assert.NoError(t, err) context := tokenize(strings.Split("a b --aaa x -b x", " "), false) selected, err := parseAndExecute(app, context) assert.NoError(t, err) assert.True(t, context.EOL()) assert.Equal(t, "a b", selected) assert.Equal(t, "x", *a) assert.Equal(t, "x", *b) } func TestNestedCommandWithMergedFlags(t *testing.T) { app := New("app", "") cmd0 := app.Command("a", "") cmd0f0 := cmd0.Flag("aflag", "").Bool() // cmd1 := app.Command("b", "") // cmd1f0 := cmd0.Flag("bflag", "").Bool() cmd00 := cmd0.Command("aa", "") cmd00f0 := cmd00.Flag("aaflag", "").Bool() err := app.init() assert.NoError(t, err) context := tokenize(strings.Split("a aa --aflag --aaflag", " "), false) selected, err := parseAndExecute(app, context) assert.NoError(t, err) assert.True(t, *cmd0f0) assert.True(t, *cmd00f0) assert.Equal(t, "a aa", selected) } func TestNestedCommandWithDuplicateFlagErrors(t *testing.T) { app := New("app", "") app.Flag("test", "").Bool() app.Command("cmd0", "").Flag("test", "").Bool() err := app.init() assert.Error(t, err) } func TestNestedCommandWithArgAndMergedFlags(t *testing.T) { app := New("app", "") cmd0 := app.Command("a", "") cmd0f0 := cmd0.Flag("aflag", "").Bool() // cmd1 := app.Command("b", "") // cmd1f0 := cmd0.Flag("bflag", "").Bool() cmd00 := cmd0.Command("aa", "") cmd00a0 := cmd00.Arg("arg", "").String() cmd00f0 := cmd00.Flag("aaflag", "").Bool() err := app.init() assert.NoError(t, err) context := tokenize(strings.Split("a aa hello --aflag --aaflag", " "), false) selected, err := parseAndExecute(app, context) assert.NoError(t, err) assert.True(t, *cmd0f0) assert.True(t, *cmd00f0) assert.Equal(t, "a aa", selected) assert.Equal(t, "hello", *cmd00a0) } func TestDefaultSubcommandEOL(t *testing.T) { app := newTestApp() c0 := app.Command("c0", "").Default() c0.Command("c01", "").Default() c0.Command("c02", "") cmd, err := app.Parse([]string{"c0"}) assert.NoError(t, err) assert.Equal(t, "c0 c01", cmd) } func TestDefaultSubcommandWithArg(t *testing.T) { app := newTestApp() c0 := app.Command("c0", "").Default() c01 := c0.Command("c01", "").Default() c012 := c01.Command("c012", "").Default() a0 := c012.Arg("a0", "").String() c0.Command("c02", "") cmd, err := app.Parse([]string{"c0", "hello"}) assert.NoError(t, err) assert.Equal(t, "c0 c01 c012", cmd) assert.Equal(t, "hello", *a0) } func TestDefaultSubcommandWithFlags(t *testing.T) { app := newTestApp() c0 := app.Command("c0", "").Default() _ = c0.Flag("f0", "").Int() c0c1 := c0.Command("c1", "").Default() c0c1f1 := c0c1.Flag("f1", "").Int() selected, err := app.Parse([]string{"--f1=2"}) assert.NoError(t, err) assert.Equal(t, "c0 c1", selected) assert.Equal(t, 2, *c0c1f1) _, err = app.Parse([]string{"--f2"}) assert.Error(t, err) } func TestMultipleDefaultCommands(t *testing.T) { app := newTestApp() app.Command("c0", "").Default() app.Command("c1", "").Default() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestAliasedCommand(t *testing.T) { app := newTestApp() app.Command("one", "").Alias("two") selected, _ := app.Parse([]string{"one"}) assert.Equal(t, "one", selected) selected, _ = app.Parse([]string{"two"}) assert.Equal(t, "one", selected) // 2 due to "help" and "one" assert.Equal(t, 2, len(app.Model().FlattenedCommands())) } func TestDuplicateAlias(t *testing.T) { app := newTestApp() app.Command("one", "") app.Command("two", "").Alias("one") _, err := app.Parse([]string{"one"}) assert.Error(t, err) } func TestFlagCompletion(t *testing.T) { app := newTestApp() app.Command("one", "") two := app.Command("two", "") two.Flag("flag-1", "") two.Flag("flag-2", "").HintOptions("opt1", "opt2", "opt3") two.Flag("flag-3", "") cases := []struct { target cmdMixin flagName string flagValue string expectedFlagMatch bool expectedOptionMatch bool expectedFlags []string }{ { // Test top level flags target: app.cmdMixin, flagName: "", flagValue: "", expectedFlagMatch: false, expectedOptionMatch: false, expectedFlags: []string{"--help"}, }, { // Test no flag passed target: two.cmdMixin, flagName: "", flagValue: "", expectedFlagMatch: false, expectedOptionMatch: false, expectedFlags: []string{"--flag-1", "--flag-2", "--flag-3"}, }, { // Test an incomplete flag. Should still give all options as if the flag wasn't given at all. target: two.cmdMixin, flagName: "flag-", flagValue: "", expectedFlagMatch: false, expectedOptionMatch: false, expectedFlags: []string{"--flag-1", "--flag-2", "--flag-3"}, }, { // Test with a complete flag. Should show available choices for the flag // This flag has no options. No options should be produced. // Should also report an option was matched target: two.cmdMixin, flagName: "flag-1", flagValue: "", expectedFlagMatch: true, expectedOptionMatch: true, expectedFlags: []string(nil), }, { // Test with a complete flag. Should show available choices for the flag target: two.cmdMixin, flagName: "flag-2", flagValue: "", expectedFlagMatch: true, expectedOptionMatch: false, expectedFlags: []string{"opt1", "opt2", "opt3"}, }, { // Test with a complete flag and complete option for that flag. target: two.cmdMixin, flagName: "flag-2", flagValue: "opt1", expectedFlagMatch: true, expectedOptionMatch: true, expectedFlags: []string{"opt1", "opt2", "opt3"}, }, } for i, c := range cases { choices, flagMatch, optionMatch := c.target.FlagCompletion(c.flagName, c.flagValue) assert.Equal(t, c.expectedFlags, choices, "Test case %d: expectedFlags != actual flags", i+1) assert.Equal(t, c.expectedFlagMatch, flagMatch, "Test case %d: expectedFlagMatch != flagMatch", i+1) assert.Equal(t, c.expectedOptionMatch, optionMatch, "Test case %d: expectedOptionMatch != optionMatch", i+1) } } func TestCmdCompletion(t *testing.T) { app := newTestApp() app.Command("one", "") two := app.Command("two", "") two.Command("sub1", "") two.Command("sub2", "") assert.Equal(t, []string{"help", "one", "two"}, complete(t, app)) assert.Equal(t, []string{"sub1", "sub2"}, complete(t, app, "two")) } func TestHiddenCmdCompletion(t *testing.T) { app := newTestApp() // top level visible & hidden cmds, with no sub-cmds app.Command("visible1", "") app.Command("hidden1", "").Hidden() // visible cmd with visible & hidden sub-cmds visible2 := app.Command("visible2", "") visible2.Command("visible2-visible", "") visible2.Command("visible2-hidden", "").Hidden() // hidden cmd with visible & hidden sub-cmds hidden2 := app.Command("hidden2", "").Hidden() hidden2.Command("hidden2-visible", "") hidden2.Command("hidden2-hidden", "").Hidden() // Only top level visible cmds should show assert.Equal(t, []string{"help", "visible1", "visible2"}, complete(t, app)) // Only visible sub-cmds should show assert.Equal(t, []string{"visible2-visible"}, complete(t, app, "visible2")) // Hidden commands should still complete visible sub-cmds assert.Equal(t, []string{"hidden2-visible"}, complete(t, app, "hidden2")) } func TestDefaultCmdCompletion(t *testing.T) { app := newTestApp() cmd1 := app.Command("cmd1", "") cmd1Sub1 := cmd1.Command("cmd1-sub1", "") cmd1Sub1.Arg("cmd1-sub1-arg1", "").HintOptions("cmd1-arg1").String() cmd2 := app.Command("cmd2", "").Default() cmd2.Command("cmd2-sub1", "") cmd2Sub2 := cmd2.Command("cmd2-sub2", "").Default() cmd2Sub2Sub1 := cmd2Sub2.Command("cmd2-sub2-sub1", "").Default() cmd2Sub2Sub1.Arg("cmd2-sub2-sub1-arg1", "").HintOptions("cmd2-sub2-sub1-arg1").String() cmd2Sub2Sub1.Arg("cmd2-sub2-sub1-arg2", "").HintOptions("cmd2-sub2-sub1-arg2").String() // Without args, should get: // - root cmds (including implicit "help") // - thread of default cmds // - first arg hints for the final default cmd assert.Equal(t, []string{"cmd1", "cmd2", "cmd2-sub1", "cmd2-sub2", "cmd2-sub2-sub1", "cmd2-sub2-sub1-arg1", "help"}, complete(t, app)) // With a non-default cmd already listed, should get: // - sub cmds of that arg assert.Equal(t, []string{"cmd1-sub1"}, complete(t, app, "cmd1")) // With an explicit default cmd listed, should get: // - default child-cmds // - first arg hints for the final default cmd assert.Equal(t, []string{"cmd2-sub1", "cmd2-sub2", "cmd2-sub2-sub1", "cmd2-sub2-sub1-arg1"}, complete(t, app, "cmd2")) // Args should be completed when all preceding cmds are explicit, and when // any of them are implicit (not listed). Check this by trying all possible // combinations of choosing/excluding the three levels of cmds. This tests // root-level default, middle default, and end default. for i := 0; i < 8; i++ { var cmdline []string if i&1 != 0 { cmdline = append(cmdline, "cmd2") } if i&2 != 0 { cmdline = append(cmdline, "cmd2-sub2") } if i&4 != 0 { cmdline = append(cmdline, "cmd2-sub2-sub1") } assert.Contains(t, complete(t, app, cmdline...), "cmd2-sub2-sub1-arg1", "with cmdline: %v", cmdline) } // With both args of a default sub cmd, should get no completions assert.Empty(t, complete(t, app, "arg1", "arg2")) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/completions.go000066400000000000000000000016071330143245600230660ustar00rootroot00000000000000package kingpin // HintAction is a function type who is expected to return a slice of possible // command line arguments. type HintAction func() []string type completionsMixin struct { hintActions []HintAction builtinHintActions []HintAction } func (a *completionsMixin) addHintAction(action HintAction) { a.hintActions = append(a.hintActions, action) } // Allow adding of HintActions which are added internally, ie, EnumVar func (a *completionsMixin) addHintActionBuiltin(action HintAction) { a.builtinHintActions = append(a.builtinHintActions, action) } func (a *completionsMixin) resolveCompletions() []string { var hints []string options := a.builtinHintActions if len(a.hintActions) > 0 { // User specified their own hintActions. Use those instead. options = a.hintActions } for _, hintAction := range options { hints = append(hints, hintAction()...) } return hints } golang-gopkg-alecthomas-kingpin.v2-2.2.6/completions_test.go000066400000000000000000000033511330143245600241230ustar00rootroot00000000000000package kingpin import ( "testing" "github.com/stretchr/testify/assert" ) func TestResolveWithBuiltin(t *testing.T) { a := completionsMixin{} hintAction1 := func() []string { return []string{"opt1", "opt2"} } hintAction2 := func() []string { return []string{"opt3", "opt4"} } a.builtinHintActions = []HintAction{hintAction1, hintAction2} args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2", "opt3", "opt4"}, args) } func TestResolveWithUser(t *testing.T) { a := completionsMixin{} hintAction1 := func() []string { return []string{"opt1", "opt2"} } hintAction2 := func() []string { return []string{"opt3", "opt4"} } a.hintActions = []HintAction{hintAction1, hintAction2} args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2", "opt3", "opt4"}, args) } func TestResolveWithCombination(t *testing.T) { a := completionsMixin{} builtin := func() []string { return []string{"opt1", "opt2"} } user := func() []string { return []string{"opt3", "opt4"} } a.builtinHintActions = []HintAction{builtin} a.hintActions = []HintAction{user} args := a.resolveCompletions() // User provided args take preference over builtin (enum-defined) args. assert.Equal(t, []string{"opt3", "opt4"}, args) } func TestAddHintAction(t *testing.T) { a := completionsMixin{} hintFunc := func() []string { return []string{"opt1", "opt2"} } a.addHintAction(hintFunc) args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } func TestAddHintActionBuiltin(t *testing.T) { a := completionsMixin{} hintFunc := func() []string { return []string{"opt1", "opt2"} } a.addHintActionBuiltin(hintFunc) args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/doc.go000066400000000000000000000037421330143245600213010ustar00rootroot00000000000000// Package kingpin provides command line interfaces like this: // // $ chat // usage: chat [] [] [ ...] // // Flags: // --debug enable debug mode // --help Show help. // --server=127.0.0.1 server address // // Commands: // help // Show help for a command. // // post [] // Post a message to a channel. // // register // Register a new user. // // $ chat help post // usage: chat [] post [] [] // // Post a message to a channel. // // Flags: // --image=IMAGE image to post // // Args: // channel to post to // [] text to post // $ chat post --image=~/Downloads/owls.jpg pics // // From code like this: // // package main // // import "gopkg.in/alecthomas/kingpin.v2" // // var ( // debug = kingpin.Flag("debug", "enable debug mode").Default("false").Bool() // serverIP = kingpin.Flag("server", "server address").Default("127.0.0.1").IP() // // register = kingpin.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 = kingpin.Command("post", "Post a message to a channel.") // postImage = post.Flag("image", "image to post").ExistingFile() // postChannel = post.Arg("channel", "channel to post to").Required().String() // postText = post.Arg("text", "text to post").String() // ) // // func main() { // switch kingpin.Parse() { // // Register user // case "register": // println(*registerNick) // // // Post message // case "post": // if *postImage != nil { // } // if *postText != "" { // } // } // } package kingpin golang-gopkg-alecthomas-kingpin.v2-2.2.6/envar.go000066400000000000000000000015711330143245600216450ustar00rootroot00000000000000package kingpin import ( "os" "regexp" ) var ( envVarValuesSeparator = "\r?\n" envVarValuesTrimmer = regexp.MustCompile(envVarValuesSeparator + "$") envVarValuesSplitter = regexp.MustCompile(envVarValuesSeparator) ) type envarMixin struct { envar string noEnvar bool } func (e *envarMixin) HasEnvarValue() bool { return e.GetEnvarValue() != "" } func (e *envarMixin) GetEnvarValue() string { if e.noEnvar || e.envar == "" { return "" } return os.Getenv(e.envar) } func (e *envarMixin) GetSplitEnvarValue() []string { values := make([]string, 0) envarValue := e.GetEnvarValue() if envarValue == "" { return values } // Split by new line to extract multiple values, if any. trimmed := envVarValuesTrimmer.ReplaceAllString(envarValue, "") for _, value := range envVarValuesSplitter.Split(trimmed, -1) { values = append(values, value) } return values } golang-gopkg-alecthomas-kingpin.v2-2.2.6/examples_test.go000066400000000000000000000020711330143245600234030ustar00rootroot00000000000000package kingpin import ( "fmt" "net/http" "strings" ) 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) Get() interface{} { return (http.Header)(*h) } func (h *HTTPHeaderValue) String() string { return "" } func HTTPHeader(s Settings) (target *http.Header) { target = new(http.Header) s.SetValue((*HTTPHeaderValue)(target)) return } // This example ilustrates how to define custom parsers. HTTPHeader // cumulatively parses each encountered --header flag into a http.Header struct. func ExampleValue() { var ( curl = New("curl", "transfer a URL") headers = HTTPHeader(curl.Flag("headers", "Add HTTP headers to the request.").Short('H').PlaceHolder("HEADER:VALUE")) ) curl.Parse([]string{"-H Content-Type:application/octet-stream"}) for key, value := range *headers { fmt.Printf("%s = %s\n", key, value) } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/flags.go000066400000000000000000000162551330143245600216330ustar00rootroot00000000000000package kingpin import ( "fmt" "strings" ) type flagGroup struct { short map[string]*FlagClause long map[string]*FlagClause flagOrder []*FlagClause } func newFlagGroup() *flagGroup { return &flagGroup{ short: map[string]*FlagClause{}, long: map[string]*FlagClause{}, } } // GetFlag gets a flag definition. // // This allows existing flags to be modified after definition but before parsing. Useful for // modular applications. func (f *flagGroup) GetFlag(name string) *FlagClause { return f.long[name] } // Flag defines a new flag with the given long name and help. func (f *flagGroup) Flag(name, help string) *FlagClause { flag := newFlag(name, help) f.long[name] = flag f.flagOrder = append(f.flagOrder, flag) return flag } func (f *flagGroup) init(defaultEnvarPrefix string) error { if err := f.checkDuplicates(); err != nil { return err } for _, flag := range f.long { if defaultEnvarPrefix != "" && !flag.noEnvar && flag.envar == "" { flag.envar = envarTransform(defaultEnvarPrefix + "_" + flag.name) } if err := flag.init(); err != nil { return err } if flag.shorthand != 0 { f.short[string(flag.shorthand)] = flag } } return nil } func (f *flagGroup) checkDuplicates() error { seenShort := map[rune]bool{} seenLong := map[string]bool{} for _, flag := range f.flagOrder { if flag.shorthand != 0 { if _, ok := seenShort[flag.shorthand]; ok { return fmt.Errorf("duplicate short flag -%c", flag.shorthand) } seenShort[flag.shorthand] = true } if _, ok := seenLong[flag.name]; ok { return fmt.Errorf("duplicate long flag --%s", flag.name) } seenLong[flag.name] = true } return nil } func (f *flagGroup) parse(context *ParseContext) (*FlagClause, error) { var token *Token loop: for { token = context.Peek() switch token.Type { case TokenEOL: break loop case TokenLong, TokenShort: flagToken := token defaultValue := "" var flag *FlagClause var ok bool invert := false name := token.Value if token.Type == TokenLong { flag, ok = f.long[name] if !ok { if strings.HasPrefix(name, "no-") { name = name[3:] invert = true } flag, ok = f.long[name] } if !ok { return nil, fmt.Errorf("unknown long flag '%s'", flagToken) } } else { flag, ok = f.short[name] if !ok { return nil, fmt.Errorf("unknown short flag '%s'", flagToken) } } context.Next() fb, ok := flag.value.(boolFlag) if ok && fb.IsBoolFlag() { if invert { defaultValue = "false" } else { defaultValue = "true" } } else { if invert { context.Push(token) return nil, fmt.Errorf("unknown long flag '%s'", flagToken) } token = context.Peek() if token.Type != TokenArg { context.Push(token) return nil, fmt.Errorf("expected argument for flag '%s'", flagToken) } context.Next() defaultValue = token.Value } context.matchedFlag(flag, defaultValue) return flag, nil default: break loop } } return nil, nil } // FlagClause is a fluid interface used to build flags. type FlagClause struct { parserMixin actionMixin completionsMixin envarMixin name string shorthand rune help string defaultValues []string placeholder string hidden bool } func newFlag(name, help string) *FlagClause { f := &FlagClause{ name: name, help: help, } return f } func (f *FlagClause) setDefault() error { if f.HasEnvarValue() { if v, ok := f.value.(repeatableFlag); !ok || !v.IsCumulative() { // Use the value as-is return f.value.Set(f.GetEnvarValue()) } else { for _, value := range f.GetSplitEnvarValue() { if err := f.value.Set(value); err != nil { return err } } return nil } } if len(f.defaultValues) > 0 { for _, defaultValue := range f.defaultValues { if err := f.value.Set(defaultValue); err != nil { return err } } return nil } return nil } func (f *FlagClause) needsValue() bool { haveDefault := len(f.defaultValues) > 0 return f.required && !(haveDefault || f.HasEnvarValue()) } func (f *FlagClause) init() error { if f.required && len(f.defaultValues) > 0 { return fmt.Errorf("required flag '--%s' with default value that will never be used", f.name) } if f.value == nil { return fmt.Errorf("no type defined for --%s (eg. .String())", f.name) } if v, ok := f.value.(repeatableFlag); (!ok || !v.IsCumulative()) && len(f.defaultValues) > 1 { return fmt.Errorf("invalid default for '--%s', expecting single value", f.name) } return nil } // Dispatch to the given function after the flag is parsed and validated. func (f *FlagClause) Action(action Action) *FlagClause { f.addAction(action) return f } func (f *FlagClause) PreAction(action Action) *FlagClause { f.addPreAction(action) return f } // HintAction registers a HintAction (function) for the flag to provide completions func (a *FlagClause) HintAction(action HintAction) *FlagClause { a.addHintAction(action) return a } // HintOptions registers any number of options for the flag to provide completions func (a *FlagClause) HintOptions(options ...string) *FlagClause { a.addHintAction(func() []string { return options }) return a } func (a *FlagClause) EnumVar(target *string, options ...string) { a.parserMixin.EnumVar(target, options...) a.addHintActionBuiltin(func() []string { return options }) } func (a *FlagClause) Enum(options ...string) (target *string) { a.addHintActionBuiltin(func() []string { return options }) return a.parserMixin.Enum(options...) } // Default values for this flag. They *must* be parseable by the value of the flag. func (f *FlagClause) Default(values ...string) *FlagClause { f.defaultValues = values return f } // DEPRECATED: Use Envar(name) instead. func (f *FlagClause) OverrideDefaultFromEnvar(envar string) *FlagClause { return f.Envar(envar) } // Envar overrides the default value(s) for a flag from an environment variable, // if it is set. Several default values can be provided by using new lines to // separate them. func (f *FlagClause) Envar(name string) *FlagClause { f.envar = name f.noEnvar = false return f } // NoEnvar forces environment variable defaults to be disabled for this flag. // Most useful in conjunction with app.DefaultEnvars(). func (f *FlagClause) NoEnvar() *FlagClause { f.envar = "" f.noEnvar = true return f } // PlaceHolder sets the place-holder string used for flag values in the help. The // default behaviour is to use the value provided by Default() if provided, // then fall back on the capitalized flag name. func (f *FlagClause) PlaceHolder(placeholder string) *FlagClause { f.placeholder = placeholder return f } // Hidden hides a flag from usage but still allows it to be used. func (f *FlagClause) Hidden() *FlagClause { f.hidden = true return f } // Required makes the flag required. You can not provide a Default() value to a Required() flag. func (f *FlagClause) Required() *FlagClause { f.required = true return f } // Short sets the short flag name. func (f *FlagClause) Short(name rune) *FlagClause { f.shorthand = name return f } // Bool makes this flag a boolean flag. func (f *FlagClause) Bool() (target *bool) { target = new(bool) f.SetValue(newBoolValue(target)) return } golang-gopkg-alecthomas-kingpin.v2-2.2.6/flags_test.go000066400000000000000000000224271330143245600226700ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "os" "github.com/stretchr/testify/assert" "testing" ) func TestBool(t *testing.T) { app := newTestApp() b := app.Flag("b", "").Bool() _, err := app.Parse([]string{"--b"}) assert.NoError(t, err) assert.True(t, *b) } func TestNoBool(t *testing.T) { fg := newFlagGroup() f := fg.Flag("b", "").Default("true") b := f.Bool() fg.init("") tokens := tokenize([]string{"--no-b"}, false) _, err := fg.parse(tokens) assert.NoError(t, err) assert.False(t, *b) } func TestNegateNonBool(t *testing.T) { fg := newFlagGroup() f := fg.Flag("b", "") f.Int() fg.init("") tokens := tokenize([]string{"--no-b"}, false) _, err := fg.parse(tokens) assert.Error(t, err) } func TestNegativePrefixLongFlag(t *testing.T) { fg := newFlagGroup() f := fg.Flag("no-comment", "") b := f.Bool() fg.init("") tokens := tokenize([]string{"--no-comment"}, false) _, err := fg.parse(tokens) assert.NoError(t, err) assert.False(t, *b) } func TestInvalidFlagDefaultCanBeOverridden(t *testing.T) { app := newTestApp() app.Flag("a", "").Default("invalid").Bool() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestRequiredFlag(t *testing.T) { app := newTestApp() app.Version("0.0.0").Writer(ioutil.Discard) exits := 0 app.Terminate(func(int) { exits++ }) app.Flag("a", "").Required().Bool() _, err := app.Parse([]string{"--a"}) assert.NoError(t, err) _, err = app.Parse([]string{}) assert.Error(t, err) _, err = app.Parse([]string{"--version"}) assert.Equal(t, 1, exits) } func TestShortFlag(t *testing.T) { app := newTestApp() f := app.Flag("long", "").Short('s').Bool() _, err := app.Parse([]string{"-s"}) assert.NoError(t, err) assert.True(t, *f) } func TestUnicodeShortFlag(t *testing.T) { app := newTestApp() f := app.Flag("aaa", "").Short('ä').Bool() _, err := app.Parse([]string{"-ä"}) assert.NoError(t, err) assert.True(t, *f) } func TestCombinedShortFlags(t *testing.T) { app := newTestApp() a := app.Flag("short0", "").Short('0').Bool() b := app.Flag("short1", "").Short('1').Bool() c := app.Flag("short2", "").Short('2').Bool() _, err := app.Parse([]string{"-01"}) assert.NoError(t, err) assert.True(t, *a) assert.True(t, *b) assert.False(t, *c) } func TestCombinedUnicodeShortFlags(t *testing.T) { app := newTestApp() a := app.Flag("short0", "").Short('0').Bool() b := app.Flag("short1", "").Short('1').Bool() c := app.Flag("short2", "").Short('ä').Bool() d := app.Flag("short3", "").Short('2').Bool() _, err := app.Parse([]string{"-0ä1"}) assert.NoError(t, err) assert.True(t, *a) assert.True(t, *b) assert.True(t, *c) assert.False(t, *d) } func TestCombinedShortFlagArg(t *testing.T) { a := newTestApp() n := a.Flag("short", "").Short('s').Int() _, err := a.Parse([]string{"-s10"}) assert.NoError(t, err) assert.Equal(t, 10, *n) } func TestCombinedUnicodeShortFlagArg(t *testing.T) { app := newTestApp() a := app.Flag("short", "").Short('ä').Int() _, err := app.Parse([]string{"-ä10"}) assert.NoError(t, err) assert.Equal(t, 10, *a) } func TestCombinedUnicodeShortFlagUnicodeArg(t *testing.T) { app := newTestApp() a := app.Flag("short", "").Short('ä').String() _, err := app.Parse([]string{"-äöö"}) assert.NoError(t, err) assert.Equal(t, "öö", *a) } func TestEmptyShortFlagIsAnError(t *testing.T) { _, err := newTestApp().Parse([]string{"-"}) assert.Error(t, err) } func TestRequiredWithEnvarMissingErrors(t *testing.T) { app := newTestApp() app.Flag("t", "").OverrideDefaultFromEnvar("TEST_ENVAR").Required().Int() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestRequiredWithEnvar(t *testing.T) { os.Setenv("TEST_ENVAR", "123") app := newTestApp() flag := app.Flag("t", "").Envar("TEST_ENVAR").Required().Int() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, 123, *flag) } func TestSubcommandFlagRequiredWithEnvar(t *testing.T) { os.Setenv("TEST_ENVAR", "123") app := newTestApp() cmd := app.Command("command", "") flag := cmd.Flag("t", "").Envar("TEST_ENVAR").Required().Int() _, err := app.Parse([]string{"command"}) assert.NoError(t, err) assert.Equal(t, 123, *flag) } func TestRegexp(t *testing.T) { app := newTestApp() flag := app.Flag("reg", "").Regexp() _, err := app.Parse([]string{"--reg", "^abc$"}) assert.NoError(t, err) assert.NotNil(t, *flag) assert.Equal(t, "^abc$", (*flag).String()) assert.Regexp(t, *flag, "abc") assert.NotRegexp(t, *flag, "abcd") } func TestDuplicateShortFlag(t *testing.T) { app := newTestApp() app.Flag("a", "").Short('a').String() app.Flag("b", "").Short('a').String() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestDuplicateLongFlag(t *testing.T) { app := newTestApp() app.Flag("a", "").String() app.Flag("a", "").String() _, err := app.Parse([]string{}) assert.Error(t, err) } func TestGetFlagAndOverrideDefault(t *testing.T) { app := newTestApp() a := app.Flag("a", "").Default("default").String() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "default", *a) app.GetFlag("a").Default("new") _, err = app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "new", *a) } func TestEnvarOverrideDefault(t *testing.T) { os.Setenv("TEST_ENVAR", "123") app := newTestApp() flag := app.Flag("t", "").Default("default").Envar("TEST_ENVAR").String() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "123", *flag) } func TestFlagMultipleValuesDefault(t *testing.T) { app := newTestApp() a := app.Flag("a", "").Default("default1", "default2").Strings() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, []string{"default1", "default2"}, *a) } func TestFlagMultipleValuesDefaultNonRepeatable(t *testing.T) { c := newTestApp() c.Flag("foo", "foo").Default("a", "b").String() _, err := c.Parse([]string{}) assert.Error(t, err) } func TestFlagMultipleValuesDefaultEnvarUnix(t *testing.T) { app := newTestApp() a := app.Flag("a", "").Envar("TEST_MULTIPLE_VALUES").Strings() os.Setenv("TEST_MULTIPLE_VALUES", "123\n456\n") _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, []string{"123", "456"}, *a) } func TestFlagMultipleValuesDefaultEnvarWindows(t *testing.T) { app := newTestApp() a := app.Flag("a", "").Envar("TEST_MULTIPLE_VALUES").Strings() os.Setenv("TEST_MULTIPLE_VALUES", "123\r\n456\r\n") _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, []string{"123", "456"}, *a) } func TestFlagMultipleValuesDefaultEnvarNonRepeatable(t *testing.T) { c := newTestApp() a := c.Flag("foo", "foo").Envar("TEST_MULTIPLE_VALUES_NON_REPEATABLE").String() os.Setenv("TEST_MULTIPLE_VALUES_NON_REPEATABLE", "123\n456") _, err := c.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "123\n456", *a) } func TestFlagHintAction(t *testing.T) { c := newTestApp() action := func() []string { return []string{"opt1", "opt2"} } a := c.Flag("foo", "foo").HintAction(action) args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } func TestFlagHintOptions(t *testing.T) { c := newTestApp() a := c.Flag("foo", "foo").HintOptions("opt1", "opt2") args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } func TestFlagEnumVar(t *testing.T) { c := newTestApp() var bar string a := c.Flag("foo", "foo") a.Enum("opt1", "opt2") b := c.Flag("bar", "bar") b.EnumVar(&bar, "opt3", "opt4") args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) args = b.resolveCompletions() assert.Equal(t, []string{"opt3", "opt4"}, args) } func TestMultiHintOptions(t *testing.T) { c := newTestApp() a := c.Flag("foo", "foo").HintOptions("opt1").HintOptions("opt2") args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } func TestMultiHintActions(t *testing.T) { c := newTestApp() a := c.Flag("foo", "foo"). HintAction(func() []string { return []string{"opt1"} }). HintAction(func() []string { return []string{"opt2"} }) args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } func TestCombinationHintActionsOptions(t *testing.T) { c := newTestApp() a := c.Flag("foo", "foo").HintAction(func() []string { return []string{"opt1"} }).HintOptions("opt2") args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) } func TestCombinationEnumActions(t *testing.T) { c := newTestApp() var foo string a := c.Flag("foo", "foo"). HintAction(func() []string { return []string{"opt1", "opt2"} }) a.Enum("opt3", "opt4") b := c.Flag("bar", "bar"). HintAction(func() []string { return []string{"opt5", "opt6"} }) b.EnumVar(&foo, "opt3", "opt4") // Provided HintActions should override automatically generated Enum options. args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) args = b.resolveCompletions() assert.Equal(t, []string{"opt5", "opt6"}, args) } func TestCombinationEnumOptions(t *testing.T) { c := newTestApp() var foo string a := c.Flag("foo", "foo").HintOptions("opt1", "opt2") a.Enum("opt3", "opt4") b := c.Flag("bar", "bar").HintOptions("opt5", "opt6") b.EnumVar(&foo, "opt3", "opt4") // Provided HintOptions should override automatically generated Enum options. args := a.resolveCompletions() assert.Equal(t, []string{"opt1", "opt2"}, args) args = b.resolveCompletions() assert.Equal(t, []string{"opt5", "opt6"}, args) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/global.go000066400000000000000000000053451330143245600217750ustar00rootroot00000000000000package kingpin import ( "os" "path/filepath" ) var ( // CommandLine is the default Kingpin parser. CommandLine = New(filepath.Base(os.Args[0]), "") // Global help flag. Exposed for user customisation. HelpFlag = CommandLine.HelpFlag // Top-level help command. Exposed for user customisation. May be nil. HelpCommand = CommandLine.HelpCommand // Global version flag. Exposed for user customisation. May be nil. VersionFlag = CommandLine.VersionFlag ) // Command adds a new command to the default parser. func Command(name, help string) *CmdClause { return CommandLine.Command(name, help) } // Flag adds a new flag to the default parser. func Flag(name, help string) *FlagClause { return CommandLine.Flag(name, help) } // Arg adds a new argument to the top-level of the default parser. func Arg(name, help string) *ArgClause { return CommandLine.Arg(name, help) } // Parse and return the selected command. Will call the termination handler if // an error is encountered. func Parse() string { selected := MustParse(CommandLine.Parse(os.Args[1:])) if selected == "" && CommandLine.cmdGroup.have() { Usage() CommandLine.terminate(0) } return selected } // Errorf prints an error message to stderr. func Errorf(format string, args ...interface{}) { CommandLine.Errorf(format, args...) } // Fatalf prints an error message to stderr and exits. func Fatalf(format string, args ...interface{}) { CommandLine.Fatalf(format, args...) } // FatalIfError prints an error and exits if err is not nil. The error is printed // with the given prefix. func FatalIfError(err error, format string, args ...interface{}) { CommandLine.FatalIfError(err, format, args...) } // FatalUsage prints an error message followed by usage information, then // exits with a non-zero status. func FatalUsage(format string, args ...interface{}) { CommandLine.FatalUsage(format, args...) } // FatalUsageContext writes a printf formatted error message to stderr, then // usage information for the given ParseContext, before exiting. func FatalUsageContext(context *ParseContext, format string, args ...interface{}) { CommandLine.FatalUsageContext(context, format, args...) } // Usage prints usage to stderr. func Usage() { CommandLine.Usage(os.Args[1:]) } // Set global usage template to use (defaults to DefaultUsageTemplate). func UsageTemplate(template string) *Application { return CommandLine.UsageTemplate(template) } // MustParse can be used with app.Parse(args) to exit with an error if parsing fails. func MustParse(command string, err error) string { if err != nil { Fatalf("%s, try --help", err) } return command } // Version adds a flag for displaying the application version number. func Version(version string) *Application { return CommandLine.Version(version) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/guesswidth.go000066400000000000000000000002271330143245600227150ustar00rootroot00000000000000// +build appengine !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd package kingpin import "io" func guessWidth(w io.Writer) int { return 80 } golang-gopkg-alecthomas-kingpin.v2-2.2.6/guesswidth_unix.go000066400000000000000000000013301330143245600237540ustar00rootroot00000000000000// +build !appengine,linux freebsd darwin dragonfly netbsd openbsd package kingpin import ( "io" "os" "strconv" "syscall" "unsafe" ) func guessWidth(w io.Writer) int { // check if COLUMNS env is set to comply with // http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap08.html colsStr := os.Getenv("COLUMNS") if colsStr != "" { if cols, err := strconv.Atoi(colsStr); err == nil { return cols } } if t, ok := w.(*os.File); ok { fd := t.Fd() var dimensions [4]uint16 if _, _, err := syscall.Syscall6( syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0, ); err == 0 { return int(dimensions[1]) } } return 80 } golang-gopkg-alecthomas-kingpin.v2-2.2.6/model.go000066400000000000000000000104011330143245600216220ustar00rootroot00000000000000package kingpin import ( "fmt" "strconv" "strings" ) // Data model for Kingpin command-line structure. type FlagGroupModel struct { Flags []*FlagModel } func (f *FlagGroupModel) FlagSummary() string { out := []string{} count := 0 for _, flag := range f.Flags { if flag.Name != "help" { count++ } if flag.Required { if flag.IsBoolFlag() { out = append(out, fmt.Sprintf("--[no-]%s", flag.Name)) } else { out = append(out, fmt.Sprintf("--%s=%s", flag.Name, flag.FormatPlaceHolder())) } } } if count != len(out) { out = append(out, "[]") } return strings.Join(out, " ") } type FlagModel struct { Name string Help string Short rune Default []string Envar string PlaceHolder string Required bool Hidden bool Value Value } func (f *FlagModel) String() string { return f.Value.String() } func (f *FlagModel) IsBoolFlag() bool { if fl, ok := f.Value.(boolFlag); ok { return fl.IsBoolFlag() } return false } func (f *FlagModel) FormatPlaceHolder() string { if f.PlaceHolder != "" { return f.PlaceHolder } if len(f.Default) > 0 { ellipsis := "" if len(f.Default) > 1 { ellipsis = "..." } if _, ok := f.Value.(*stringValue); ok { return strconv.Quote(f.Default[0]) + ellipsis } return f.Default[0] + ellipsis } return strings.ToUpper(f.Name) } type ArgGroupModel struct { Args []*ArgModel } func (a *ArgGroupModel) ArgSummary() string { depth := 0 out := []string{} for _, arg := range a.Args { h := "<" + arg.Name + ">" if !arg.Required { h = "[" + h depth++ } out = append(out, h) } out[len(out)-1] = out[len(out)-1] + strings.Repeat("]", depth) return strings.Join(out, " ") } type ArgModel struct { Name string Help string Default []string Envar string Required bool Value Value } func (a *ArgModel) String() string { return a.Value.String() } type CmdGroupModel struct { Commands []*CmdModel } func (c *CmdGroupModel) FlattenedCommands() (out []*CmdModel) { for _, cmd := range c.Commands { if len(cmd.Commands) == 0 { out = append(out, cmd) } out = append(out, cmd.FlattenedCommands()...) } return } type CmdModel struct { Name string Aliases []string Help string FullCommand string Depth int Hidden bool Default bool *FlagGroupModel *ArgGroupModel *CmdGroupModel } func (c *CmdModel) String() string { return c.FullCommand } type ApplicationModel struct { Name string Help string Version string Author string *ArgGroupModel *CmdGroupModel *FlagGroupModel } func (a *Application) Model() *ApplicationModel { return &ApplicationModel{ Name: a.Name, Help: a.Help, Version: a.version, Author: a.author, FlagGroupModel: a.flagGroup.Model(), ArgGroupModel: a.argGroup.Model(), CmdGroupModel: a.cmdGroup.Model(), } } func (a *argGroup) Model() *ArgGroupModel { m := &ArgGroupModel{} for _, arg := range a.args { m.Args = append(m.Args, arg.Model()) } return m } func (a *ArgClause) Model() *ArgModel { return &ArgModel{ Name: a.name, Help: a.help, Default: a.defaultValues, Envar: a.envar, Required: a.required, Value: a.value, } } func (f *flagGroup) Model() *FlagGroupModel { m := &FlagGroupModel{} for _, fl := range f.flagOrder { m.Flags = append(m.Flags, fl.Model()) } return m } func (f *FlagClause) Model() *FlagModel { return &FlagModel{ Name: f.name, Help: f.help, Short: rune(f.shorthand), Default: f.defaultValues, Envar: f.envar, PlaceHolder: f.placeholder, Required: f.required, Hidden: f.hidden, Value: f.value, } } func (c *cmdGroup) Model() *CmdGroupModel { m := &CmdGroupModel{} for _, cm := range c.commandOrder { m.Commands = append(m.Commands, cm.Model()) } return m } func (c *CmdClause) Model() *CmdModel { depth := 0 for i := c; i != nil; i = i.parent { depth++ } return &CmdModel{ Name: c.name, Aliases: c.aliases, Help: c.help, Depth: depth, Hidden: c.hidden, Default: c.isDefault, FullCommand: c.FullCommand(), FlagGroupModel: c.flagGroup.Model(), ArgGroupModel: c.argGroup.Model(), CmdGroupModel: c.cmdGroup.Model(), } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/parser.go000066400000000000000000000212721330143245600220260ustar00rootroot00000000000000package kingpin import ( "bufio" "fmt" "os" "strings" "unicode/utf8" ) type TokenType int // Token types. const ( TokenShort TokenType = iota TokenLong TokenArg TokenError TokenEOL ) func (t TokenType) String() string { switch t { case TokenShort: return "short flag" case TokenLong: return "long flag" case TokenArg: return "argument" case TokenError: return "error" case TokenEOL: return "" } return "?" } var ( TokenEOLMarker = Token{-1, TokenEOL, ""} ) type Token struct { Index int Type TokenType Value string } func (t *Token) Equal(o *Token) bool { return t.Index == o.Index } func (t *Token) IsFlag() bool { return t.Type == TokenShort || t.Type == TokenLong } func (t *Token) IsEOF() bool { return t.Type == TokenEOL } func (t *Token) String() string { switch t.Type { case TokenShort: return "-" + t.Value case TokenLong: return "--" + t.Value case TokenArg: return t.Value case TokenError: return "error: " + t.Value case TokenEOL: return "" default: panic("unhandled type") } } // A union of possible elements in a parse stack. type ParseElement struct { // Clause is either *CmdClause, *ArgClause or *FlagClause. Clause interface{} // Value is corresponding value for an ArgClause or FlagClause (if any). Value *string } // ParseContext holds the current context of the parser. When passed to // Action() callbacks Elements will be fully populated with *FlagClause, // *ArgClause and *CmdClause values and their corresponding arguments (if // any). type ParseContext struct { SelectedCommand *CmdClause ignoreDefault bool argsOnly bool peek []*Token argi int // Index of current command-line arg we're processing. args []string rawArgs []string flags *flagGroup arguments *argGroup argumenti int // Cursor into arguments // Flags, arguments and commands encountered and collected during parse. Elements []*ParseElement } func (p *ParseContext) nextArg() *ArgClause { if p.argumenti >= len(p.arguments.args) { return nil } arg := p.arguments.args[p.argumenti] if !arg.consumesRemainder() { p.argumenti++ } return arg } func (p *ParseContext) next() { p.argi++ p.args = p.args[1:] } // HasTrailingArgs returns true if there are unparsed command-line arguments. // This can occur if the parser can not match remaining arguments. func (p *ParseContext) HasTrailingArgs() bool { return len(p.args) > 0 } func tokenize(args []string, ignoreDefault bool) *ParseContext { return &ParseContext{ ignoreDefault: ignoreDefault, args: args, rawArgs: args, flags: newFlagGroup(), arguments: newArgGroup(), } } func (p *ParseContext) mergeFlags(flags *flagGroup) { for _, flag := range flags.flagOrder { if flag.shorthand != 0 { p.flags.short[string(flag.shorthand)] = flag } p.flags.long[flag.name] = flag p.flags.flagOrder = append(p.flags.flagOrder, flag) } } func (p *ParseContext) mergeArgs(args *argGroup) { for _, arg := range args.args { p.arguments.args = append(p.arguments.args, arg) } } func (p *ParseContext) EOL() bool { return p.Peek().Type == TokenEOL } func (p *ParseContext) Error() bool { return p.Peek().Type == TokenError } // Next token in the parse context. func (p *ParseContext) Next() *Token { if len(p.peek) > 0 { return p.pop() } // End of tokens. if len(p.args) == 0 { return &Token{Index: p.argi, Type: TokenEOL} } arg := p.args[0] p.next() if p.argsOnly { return &Token{p.argi, TokenArg, arg} } // All remaining args are passed directly. if arg == "--" { p.argsOnly = true return p.Next() } if strings.HasPrefix(arg, "--") { parts := strings.SplitN(arg[2:], "=", 2) token := &Token{p.argi, TokenLong, parts[0]} if len(parts) == 2 { p.Push(&Token{p.argi, TokenArg, parts[1]}) } return token } if strings.HasPrefix(arg, "-") { if len(arg) == 1 { return &Token{Index: p.argi, Type: TokenShort} } shortRune, size := utf8.DecodeRuneInString(arg[1:]) short := string(shortRune) flag, ok := p.flags.short[short] // Not a known short flag, we'll just return it anyway. if !ok { } else if fb, ok := flag.value.(boolFlag); ok && fb.IsBoolFlag() { // Bool short flag. } else { // Short flag with combined argument: -fARG token := &Token{p.argi, TokenShort, short} if len(arg) > size+1 { p.Push(&Token{p.argi, TokenArg, arg[size+1:]}) } return token } if len(arg) > size+1 { p.args = append([]string{"-" + arg[size+1:]}, p.args...) } return &Token{p.argi, TokenShort, short} } else if strings.HasPrefix(arg, "@") { expanded, err := ExpandArgsFromFile(arg[1:]) if err != nil { return &Token{p.argi, TokenError, err.Error()} } if len(p.args) == 0 { p.args = expanded } else { p.args = append(expanded, p.args...) } return p.Next() } return &Token{p.argi, TokenArg, arg} } func (p *ParseContext) Peek() *Token { if len(p.peek) == 0 { return p.Push(p.Next()) } return p.peek[len(p.peek)-1] } func (p *ParseContext) Push(token *Token) *Token { p.peek = append(p.peek, token) return token } func (p *ParseContext) pop() *Token { end := len(p.peek) - 1 token := p.peek[end] p.peek = p.peek[0:end] return token } func (p *ParseContext) String() string { return p.SelectedCommand.FullCommand() } func (p *ParseContext) matchedFlag(flag *FlagClause, value string) { p.Elements = append(p.Elements, &ParseElement{Clause: flag, Value: &value}) } func (p *ParseContext) matchedArg(arg *ArgClause, value string) { p.Elements = append(p.Elements, &ParseElement{Clause: arg, Value: &value}) } func (p *ParseContext) matchedCmd(cmd *CmdClause) { p.Elements = append(p.Elements, &ParseElement{Clause: cmd}) p.mergeFlags(cmd.flagGroup) p.mergeArgs(cmd.argGroup) p.SelectedCommand = cmd } // Expand arguments from a file. Lines starting with # will be treated as comments. func ExpandArgsFromFile(filename string) (out []string, err error) { if filename == "" { return nil, fmt.Errorf("expected @ file to expand arguments from") } r, err := os.Open(filename) if err != nil { return nil, fmt.Errorf("failed to open arguments file %q: %s", filename, err) } defer r.Close() scanner := bufio.NewScanner(r) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "#") { continue } out = append(out, line) } err = scanner.Err() if err != nil { return nil, fmt.Errorf("failed to read arguments from %q: %s", filename, err) } return } func parse(context *ParseContext, app *Application) (err error) { context.mergeFlags(app.flagGroup) context.mergeArgs(app.argGroup) cmds := app.cmdGroup ignoreDefault := context.ignoreDefault loop: for !context.EOL() && !context.Error() { token := context.Peek() switch token.Type { case TokenLong, TokenShort: if flag, err := context.flags.parse(context); err != nil { if !ignoreDefault { if cmd := cmds.defaultSubcommand(); cmd != nil { cmd.completionAlts = cmds.cmdNames() context.matchedCmd(cmd) cmds = cmd.cmdGroup break } } return err } else if flag == HelpFlag { ignoreDefault = true } case TokenArg: if cmds.have() { selectedDefault := false cmd, ok := cmds.commands[token.String()] if !ok { if !ignoreDefault { if cmd = cmds.defaultSubcommand(); cmd != nil { cmd.completionAlts = cmds.cmdNames() selectedDefault = true } } if cmd == nil { return fmt.Errorf("expected command but got %q", token) } } if cmd == HelpCommand { ignoreDefault = true } cmd.completionAlts = nil context.matchedCmd(cmd) cmds = cmd.cmdGroup if !selectedDefault { context.Next() } } else if context.arguments.have() { if app.noInterspersed { // no more flags context.argsOnly = true } arg := context.nextArg() if arg == nil { break loop } context.matchedArg(arg, token.String()) context.Next() } else { break loop } case TokenEOL: break loop } } // Move to innermost default command. for !ignoreDefault { if cmd := cmds.defaultSubcommand(); cmd != nil { cmd.completionAlts = cmds.cmdNames() context.matchedCmd(cmd) cmds = cmd.cmdGroup } else { break } } if context.Error() { return fmt.Errorf("%s", context.Peek().Value) } if !context.EOL() { return fmt.Errorf("unexpected %s", context.Peek()) } // Set defaults for all remaining args. for arg := context.nextArg(); arg != nil && !arg.consumesRemainder(); arg = context.nextArg() { for _, defaultValue := range arg.defaultValues { if err := arg.value.Set(defaultValue); err != nil { return fmt.Errorf("invalid default value '%s' for argument '%s'", defaultValue, arg.name) } } } return } golang-gopkg-alecthomas-kingpin.v2-2.2.6/parser_test.go000066400000000000000000000060651330143245600230700ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "os" "testing" "github.com/stretchr/testify/assert" ) func TestParserExpandFromFile(t *testing.T) { f, err := ioutil.TempFile("", "") assert.NoError(t, err) defer os.Remove(f.Name()) f.WriteString("hello\nworld\n") f.Close() app := New("test", "") arg0 := app.Arg("arg0", "").String() arg1 := app.Arg("arg1", "").String() _, err = app.Parse([]string{"@" + f.Name()}) assert.NoError(t, err) assert.Equal(t, "hello", *arg0) assert.Equal(t, "world", *arg1) } func TestParserExpandFromFileLeadingArg(t *testing.T) { f, err := ioutil.TempFile("", "") assert.NoError(t, err) defer os.Remove(f.Name()) f.WriteString("hello\nworld\n") f.Close() app := New("test", "") arg0 := app.Arg("arg0", "").String() arg1 := app.Arg("arg1", "").String() arg2 := app.Arg("arg2", "").String() _, err = app.Parse([]string{"prefix", "@" + f.Name()}) assert.NoError(t, err) assert.Equal(t, "prefix", *arg0) assert.Equal(t, "hello", *arg1) assert.Equal(t, "world", *arg2) } func TestParserExpandFromFileTrailingArg(t *testing.T) { f, err := ioutil.TempFile("", "") assert.NoError(t, err) defer os.Remove(f.Name()) f.WriteString("hello\nworld\n") f.Close() app := New("test", "") arg0 := app.Arg("arg0", "").String() arg1 := app.Arg("arg1", "").String() arg2 := app.Arg("arg2", "").String() _, err = app.Parse([]string{"@" + f.Name(), "suffix"}) assert.NoError(t, err) assert.Equal(t, "hello", *arg0) assert.Equal(t, "world", *arg1) assert.Equal(t, "suffix", *arg2) } func TestParserExpandFromFileMultipleSurroundingArgs(t *testing.T) { f, err := ioutil.TempFile("", "") assert.NoError(t, err) defer os.Remove(f.Name()) f.WriteString("hello\nworld\n") f.Close() app := New("test", "") arg0 := app.Arg("arg0", "").String() arg1 := app.Arg("arg1", "").String() arg2 := app.Arg("arg2", "").String() arg3 := app.Arg("arg3", "").String() _, err = app.Parse([]string{"prefix", "@" + f.Name(), "suffix"}) assert.NoError(t, err) assert.Equal(t, "prefix", *arg0) assert.Equal(t, "hello", *arg1) assert.Equal(t, "world", *arg2) assert.Equal(t, "suffix", *arg3) } func TestParserExpandFromFileMultipleFlags(t *testing.T) { f, err := ioutil.TempFile("", "") assert.NoError(t, err) defer os.Remove(f.Name()) f.WriteString("--flag1=f1\n--flag2=f2\n") f.Close() app := New("test", "") flag0 := app.Flag("flag0", "").String() flag1 := app.Flag("flag1", "").String() flag2 := app.Flag("flag2", "").String() flag3 := app.Flag("flag3", "").String() _, err = app.Parse([]string{"--flag0=f0", "@" + f.Name(), "--flag3=f3"}) assert.NoError(t, err) assert.Equal(t, "f0", *flag0) assert.Equal(t, "f1", *flag1) assert.Equal(t, "f2", *flag2) assert.Equal(t, "f3", *flag3) } func TestParseContextPush(t *testing.T) { app := New("test", "") app.Command("foo", "").Command("bar", "") c := tokenize([]string{"foo", "bar"}, false) a := c.Next() assert.Equal(t, TokenArg, a.Type) b := c.Next() assert.Equal(t, TokenArg, b.Type) c.Push(b) c.Push(a) a = c.Next() assert.Equal(t, "foo", a.Value) b = c.Next() assert.Equal(t, "bar", b.Value) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/parsers.go000066400000000000000000000124711330143245600222120ustar00rootroot00000000000000package kingpin import ( "net" "net/url" "os" "time" "github.com/alecthomas/units" ) type Settings interface { SetValue(value Value) } type parserMixin struct { value Value required bool } func (p *parserMixin) SetValue(value Value) { p.value = value } // StringMap provides key=value parsing into a map. func (p *parserMixin) StringMap() (target *map[string]string) { target = &(map[string]string{}) p.StringMapVar(target) return } // Duration sets the parser to a time.Duration parser. func (p *parserMixin) Duration() (target *time.Duration) { target = new(time.Duration) p.DurationVar(target) return } // Bytes parses numeric byte units. eg. 1.5KB func (p *parserMixin) Bytes() (target *units.Base2Bytes) { target = new(units.Base2Bytes) p.BytesVar(target) return } // IP sets the parser to a net.IP parser. func (p *parserMixin) IP() (target *net.IP) { target = new(net.IP) p.IPVar(target) return } // TCP (host:port) address. func (p *parserMixin) TCP() (target **net.TCPAddr) { target = new(*net.TCPAddr) p.TCPVar(target) return } // TCPVar (host:port) address. func (p *parserMixin) TCPVar(target **net.TCPAddr) { p.SetValue(newTCPAddrValue(target)) } // ExistingFile sets the parser to one that requires and returns an existing file. func (p *parserMixin) ExistingFile() (target *string) { target = new(string) p.ExistingFileVar(target) return } // ExistingDir sets the parser to one that requires and returns an existing directory. func (p *parserMixin) ExistingDir() (target *string) { target = new(string) p.ExistingDirVar(target) return } // ExistingFileOrDir sets the parser to one that requires and returns an existing file OR directory. func (p *parserMixin) ExistingFileOrDir() (target *string) { target = new(string) p.ExistingFileOrDirVar(target) return } // File returns an os.File against an existing file. func (p *parserMixin) File() (target **os.File) { target = new(*os.File) p.FileVar(target) return } // File attempts to open a File with os.OpenFile(flag, perm). func (p *parserMixin) OpenFile(flag int, perm os.FileMode) (target **os.File) { target = new(*os.File) p.OpenFileVar(target, flag, perm) return } // URL provides a valid, parsed url.URL. func (p *parserMixin) URL() (target **url.URL) { target = new(*url.URL) p.URLVar(target) return } // StringMap provides key=value parsing into a map. func (p *parserMixin) StringMapVar(target *map[string]string) { p.SetValue(newStringMapValue(target)) } // Float sets the parser to a float64 parser. func (p *parserMixin) Float() (target *float64) { return p.Float64() } // Float sets the parser to a float64 parser. func (p *parserMixin) FloatVar(target *float64) { p.Float64Var(target) } // Duration sets the parser to a time.Duration parser. func (p *parserMixin) DurationVar(target *time.Duration) { p.SetValue(newDurationValue(target)) } // BytesVar parses numeric byte units. eg. 1.5KB func (p *parserMixin) BytesVar(target *units.Base2Bytes) { p.SetValue(newBytesValue(target)) } // IP sets the parser to a net.IP parser. func (p *parserMixin) IPVar(target *net.IP) { p.SetValue(newIPValue(target)) } // ExistingFile sets the parser to one that requires and returns an existing file. func (p *parserMixin) ExistingFileVar(target *string) { p.SetValue(newExistingFileValue(target)) } // ExistingDir sets the parser to one that requires and returns an existing directory. func (p *parserMixin) ExistingDirVar(target *string) { p.SetValue(newExistingDirValue(target)) } // ExistingDir sets the parser to one that requires and returns an existing directory. func (p *parserMixin) ExistingFileOrDirVar(target *string) { p.SetValue(newExistingFileOrDirValue(target)) } // FileVar opens an existing file. func (p *parserMixin) FileVar(target **os.File) { p.SetValue(newFileValue(target, os.O_RDONLY, 0)) } // OpenFileVar calls os.OpenFile(flag, perm) func (p *parserMixin) OpenFileVar(target **os.File, flag int, perm os.FileMode) { p.SetValue(newFileValue(target, flag, perm)) } // URL provides a valid, parsed url.URL. func (p *parserMixin) URLVar(target **url.URL) { p.SetValue(newURLValue(target)) } // URLList provides a parsed list of url.URL values. func (p *parserMixin) URLList() (target *[]*url.URL) { target = new([]*url.URL) p.URLListVar(target) return } // URLListVar provides a parsed list of url.URL values. func (p *parserMixin) URLListVar(target *[]*url.URL) { p.SetValue(newURLListValue(target)) } // Enum allows a value from a set of options. func (p *parserMixin) Enum(options ...string) (target *string) { target = new(string) p.EnumVar(target, options...) return } // EnumVar allows a value from a set of options. func (p *parserMixin) EnumVar(target *string, options ...string) { p.SetValue(newEnumFlag(target, options...)) } // Enums allows a set of values from a set of options. func (p *parserMixin) Enums(options ...string) (target *[]string) { target = new([]string) p.EnumsVar(target, options...) return } // EnumVar allows a value from a set of options. func (p *parserMixin) EnumsVar(target *[]string, options ...string) { p.SetValue(newEnumsFlag(target, options...)) } // A Counter increments a number each time it is encountered. func (p *parserMixin) Counter() (target *int) { target = new(int) p.CounterVar(target) return } func (p *parserMixin) CounterVar(target *int) { p.SetValue(newCounterValue(target)) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/parsers_test.go000066400000000000000000000040511330143245600232440ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "net" "net/url" "os" "github.com/stretchr/testify/assert" "testing" ) func TestParseStrings(t *testing.T) { p := parserMixin{} v := p.Strings() p.value.Set("a") p.value.Set("b") assert.Equal(t, []string{"a", "b"}, *v) } func TestStringsStringer(t *testing.T) { target := []string{} v := newAccumulator(&target, func(v interface{}) Value { return newStringValue(v.(*string)) }) v.Set("hello") v.Set("world") assert.Equal(t, "hello,world", v.String()) } func TestParseStringMap(t *testing.T) { p := parserMixin{} v := p.StringMap() p.value.Set("a:b") p.value.Set("b:c") assert.Equal(t, map[string]string{"a": "b", "b": "c"}, *v) } func TestParseIP(t *testing.T) { p := parserMixin{} v := p.IP() p.value.Set("10.1.1.2") ip := net.ParseIP("10.1.1.2") assert.Equal(t, ip, *v) } func TestParseURL(t *testing.T) { p := parserMixin{} v := p.URL() p.value.Set("http://w3.org") u, err := url.Parse("http://w3.org") assert.NoError(t, err) assert.Equal(t, *u, **v) } func TestParseExistingFile(t *testing.T) { f, err := ioutil.TempFile("", "") if err != nil { t.Fatal(err) } defer f.Close() defer os.Remove(f.Name()) p := parserMixin{} v := p.ExistingFile() err = p.value.Set(f.Name()) assert.NoError(t, err) assert.Equal(t, f.Name(), *v) err = p.value.Set("/etc/hostsDEFINITELYMISSING") assert.Error(t, err) } func TestParseTCPAddr(t *testing.T) { p := parserMixin{} v := p.TCP() err := p.value.Set("127.0.0.1:1234") assert.NoError(t, err) expected, err := net.ResolveTCPAddr("tcp", "127.0.0.1:1234") assert.NoError(t, err) assert.Equal(t, *expected, **v) } func TestParseTCPAddrList(t *testing.T) { p := parserMixin{} _ = p.TCPList() err := p.value.Set("127.0.0.1:1234") assert.NoError(t, err) err = p.value.Set("127.0.0.1:1235") assert.NoError(t, err) assert.Equal(t, "127.0.0.1:1234,127.0.0.1:1235", p.value.String()) } func TestFloat32(t *testing.T) { p := parserMixin{} v := p.Float32() err := p.value.Set("123.45") assert.NoError(t, err) assert.InEpsilon(t, 123.45, *v, 0.001) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/templates.go000066400000000000000000000154661330143245600225400ustar00rootroot00000000000000package kingpin // Default usage template. var DefaultUsageTemplate = `{{define "FormatCommand"}}\ {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ {{end}}\ {{define "FormatCommands"}}\ {{range .FlattenedCommands}}\ {{if not .Hidden}}\ {{.FullCommand}}{{if .Default}}*{{end}}{{template "FormatCommand" .}} {{.Help|Wrap 4}} {{end}}\ {{end}}\ {{end}}\ {{define "FormatUsage"}}\ {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} {{if .Help}} {{.Help|Wrap 0}}\ {{end}}\ {{end}}\ {{if .Context.SelectedCommand}}\ usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}} {{else}}\ usage: {{.App.Name}}{{template "FormatUsage" .App}} {{end}}\ {{if .Context.Flags}}\ Flags: {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.Args}}\ Args: {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.SelectedCommand}}\ {{if len .Context.SelectedCommand.Commands}}\ Subcommands: {{template "FormatCommands" .Context.SelectedCommand}} {{end}}\ {{else if .App.Commands}}\ Commands: {{template "FormatCommands" .App}} {{end}}\ ` // Usage template where command's optional flags are listed separately var SeparateOptionalFlagsUsageTemplate = `{{define "FormatCommand"}}\ {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ {{end}}\ {{define "FormatCommands"}}\ {{range .FlattenedCommands}}\ {{if not .Hidden}}\ {{.FullCommand}}{{if .Default}}*{{end}}{{template "FormatCommand" .}} {{.Help|Wrap 4}} {{end}}\ {{end}}\ {{end}}\ {{define "FormatUsage"}}\ {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} {{if .Help}} {{.Help|Wrap 0}}\ {{end}}\ {{end}}\ {{if .Context.SelectedCommand}}\ usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}} {{else}}\ usage: {{.App.Name}}{{template "FormatUsage" .App}} {{end}}\ {{if .Context.Flags|RequiredFlags}}\ Required flags: {{.Context.Flags|RequiredFlags|FlagsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.Flags|OptionalFlags}}\ Optional flags: {{.Context.Flags|OptionalFlags|FlagsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.Args}}\ Args: {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.SelectedCommand}}\ Subcommands: {{if .Context.SelectedCommand.Commands}}\ {{template "FormatCommands" .Context.SelectedCommand}} {{end}}\ {{else if .App.Commands}}\ Commands: {{template "FormatCommands" .App}} {{end}}\ ` // Usage template with compactly formatted commands. var CompactUsageTemplate = `{{define "FormatCommand"}}\ {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ {{end}}\ {{define "FormatCommandList"}}\ {{range .}}\ {{if not .Hidden}}\ {{.Depth|Indent}}{{.Name}}{{if .Default}}*{{end}}{{template "FormatCommand" .}} {{end}}\ {{template "FormatCommandList" .Commands}}\ {{end}}\ {{end}}\ {{define "FormatUsage"}}\ {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} {{if .Help}} {{.Help|Wrap 0}}\ {{end}}\ {{end}}\ {{if .Context.SelectedCommand}}\ usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}} {{else}}\ usage: {{.App.Name}}{{template "FormatUsage" .App}} {{end}}\ {{if .Context.Flags}}\ Flags: {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.Args}}\ Args: {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.SelectedCommand}}\ {{if .Context.SelectedCommand.Commands}}\ Commands: {{.Context.SelectedCommand}} {{template "FormatCommandList" .Context.SelectedCommand.Commands}} {{end}}\ {{else if .App.Commands}}\ Commands: {{template "FormatCommandList" .App.Commands}} {{end}}\ ` var ManPageTemplate = `{{define "FormatFlags"}}\ {{range .Flags}}\ {{if not .Hidden}}\ .TP \fB{{if .Short}}-{{.Short|Char}}, {{end}}--{{.Name}}{{if not .IsBoolFlag}}={{.FormatPlaceHolder}}{{end}}\\fR {{.Help}} {{end}}\ {{end}}\ {{end}}\ {{define "FormatCommand"}}\ {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}{{if .Default}}*{{end}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ {{end}}\ {{define "FormatCommands"}}\ {{range .FlattenedCommands}}\ {{if not .Hidden}}\ .SS \fB{{.FullCommand}}{{template "FormatCommand" .}}\\fR .PP {{.Help}} {{template "FormatFlags" .}}\ {{end}}\ {{end}}\ {{end}}\ {{define "FormatUsage"}}\ {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}}\\fR {{end}}\ .TH {{.App.Name}} 1 {{.App.Version}} "{{.App.Author}}" .SH "NAME" {{.App.Name}} .SH "SYNOPSIS" .TP \fB{{.App.Name}}{{template "FormatUsage" .App}} .SH "DESCRIPTION" {{.App.Help}} .SH "OPTIONS" {{template "FormatFlags" .App}}\ {{if .App.Commands}}\ .SH "COMMANDS" {{template "FormatCommands" .App}}\ {{end}}\ ` // Default usage template. var LongHelpTemplate = `{{define "FormatCommand"}}\ {{if .FlagSummary}} {{.FlagSummary}}{{end}}\ {{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\ {{end}}\ {{define "FormatCommands"}}\ {{range .FlattenedCommands}}\ {{if not .Hidden}}\ {{.FullCommand}}{{template "FormatCommand" .}} {{.Help|Wrap 4}} {{with .Flags|FlagsToTwoColumns}}{{FormatTwoColumnsWithIndent . 4 2}}{{end}} {{end}}\ {{end}}\ {{end}}\ {{define "FormatUsage"}}\ {{template "FormatCommand" .}}{{if .Commands}} [ ...]{{end}} {{if .Help}} {{.Help|Wrap 0}}\ {{end}}\ {{end}}\ usage: {{.App.Name}}{{template "FormatUsage" .App}} {{if .Context.Flags}}\ Flags: {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .Context.Args}}\ Args: {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} {{end}}\ {{if .App.Commands}}\ Commands: {{template "FormatCommands" .App}} {{end}}\ ` var BashCompletionTemplate = ` _{{.App.Name}}_bash_autocomplete() { local cur prev opts base COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" opts=$( ${COMP_WORDS[0]} --completion-bash ${COMP_WORDS[@]:1:$COMP_CWORD} ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 } complete -F _{{.App.Name}}_bash_autocomplete {{.App.Name}} ` var ZshCompletionTemplate = ` #compdef {{.App.Name}} autoload -U compinit && compinit autoload -U bashcompinit && bashcompinit _{{.App.Name}}_bash_autocomplete() { local cur prev opts base COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" opts=$( ${COMP_WORDS[0]} --completion-bash ${COMP_WORDS[@]:1:$COMP_CWORD} ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 } complete -F _{{.App.Name}}_bash_autocomplete {{.App.Name}} ` golang-gopkg-alecthomas-kingpin.v2-2.2.6/usage.go000066400000000000000000000126251330143245600216400ustar00rootroot00000000000000package kingpin import ( "bytes" "fmt" "go/doc" "io" "strings" "github.com/alecthomas/template" ) var ( preIndent = " " ) func formatTwoColumns(w io.Writer, indent, padding, width int, rows [][2]string) { // Find size of first column. s := 0 for _, row := range rows { if c := len(row[0]); c > s && c < 30 { s = c } } indentStr := strings.Repeat(" ", indent) offsetStr := strings.Repeat(" ", s+padding) for _, row := range rows { buf := bytes.NewBuffer(nil) doc.ToText(buf, row[1], "", preIndent, width-s-padding-indent) lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") fmt.Fprintf(w, "%s%-*s%*s", indentStr, s, row[0], padding, "") if len(row[0]) >= 30 { fmt.Fprintf(w, "\n%s%s", indentStr, offsetStr) } fmt.Fprintf(w, "%s\n", lines[0]) for _, line := range lines[1:] { fmt.Fprintf(w, "%s%s%s\n", indentStr, offsetStr, line) } } } // Usage writes application usage to w. It parses args to determine // appropriate help context, such as which command to show help for. func (a *Application) Usage(args []string) { context, err := a.parseContext(true, args) a.FatalIfError(err, "") if err := a.UsageForContextWithTemplate(context, 2, a.usageTemplate); err != nil { panic(err) } } func formatAppUsage(app *ApplicationModel) string { s := []string{app.Name} if len(app.Flags) > 0 { s = append(s, app.FlagSummary()) } if len(app.Args) > 0 { s = append(s, app.ArgSummary()) } return strings.Join(s, " ") } func formatCmdUsage(app *ApplicationModel, cmd *CmdModel) string { s := []string{app.Name, cmd.String()} if len(app.Flags) > 0 { s = append(s, app.FlagSummary()) } if len(app.Args) > 0 { s = append(s, app.ArgSummary()) } return strings.Join(s, " ") } func formatFlag(haveShort bool, flag *FlagModel) string { flagString := "" if flag.Short != 0 { flagString += fmt.Sprintf("-%c, --%s", flag.Short, flag.Name) } else { if haveShort { flagString += fmt.Sprintf(" --%s", flag.Name) } else { flagString += fmt.Sprintf("--%s", flag.Name) } } if !flag.IsBoolFlag() { flagString += fmt.Sprintf("=%s", flag.FormatPlaceHolder()) } if v, ok := flag.Value.(repeatableFlag); ok && v.IsCumulative() { flagString += " ..." } return flagString } type templateParseContext struct { SelectedCommand *CmdModel *FlagGroupModel *ArgGroupModel } type templateContext struct { App *ApplicationModel Width int Context *templateParseContext } // UsageForContext displays usage information from a ParseContext (obtained from // Application.ParseContext() or Action(f) callbacks). func (a *Application) UsageForContext(context *ParseContext) error { return a.UsageForContextWithTemplate(context, 2, a.usageTemplate) } // UsageForContextWithTemplate is the base usage function. You generally don't need to use this. func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent int, tmpl string) error { width := guessWidth(a.usageWriter) funcs := template.FuncMap{ "Indent": func(level int) string { return strings.Repeat(" ", level*indent) }, "Wrap": func(indent int, s string) string { buf := bytes.NewBuffer(nil) indentText := strings.Repeat(" ", indent) doc.ToText(buf, s, indentText, " "+indentText, width-indent) return buf.String() }, "FormatFlag": formatFlag, "FlagsToTwoColumns": func(f []*FlagModel) [][2]string { rows := [][2]string{} haveShort := false for _, flag := range f { if flag.Short != 0 { haveShort = true break } } for _, flag := range f { if !flag.Hidden { rows = append(rows, [2]string{formatFlag(haveShort, flag), flag.Help}) } } return rows }, "RequiredFlags": func(f []*FlagModel) []*FlagModel { requiredFlags := []*FlagModel{} for _, flag := range f { if flag.Required { requiredFlags = append(requiredFlags, flag) } } return requiredFlags }, "OptionalFlags": func(f []*FlagModel) []*FlagModel { optionalFlags := []*FlagModel{} for _, flag := range f { if !flag.Required { optionalFlags = append(optionalFlags, flag) } } return optionalFlags }, "ArgsToTwoColumns": func(a []*ArgModel) [][2]string { rows := [][2]string{} for _, arg := range a { s := "<" + arg.Name + ">" if !arg.Required { s = "[" + s + "]" } rows = append(rows, [2]string{s, arg.Help}) } return rows }, "FormatTwoColumns": func(rows [][2]string) string { buf := bytes.NewBuffer(nil) formatTwoColumns(buf, indent, indent, width, rows) return buf.String() }, "FormatTwoColumnsWithIndent": func(rows [][2]string, indent, padding int) string { buf := bytes.NewBuffer(nil) formatTwoColumns(buf, indent, padding, width, rows) return buf.String() }, "FormatAppUsage": formatAppUsage, "FormatCommandUsage": formatCmdUsage, "IsCumulative": func(value Value) bool { r, ok := value.(remainderArg) return ok && r.IsCumulative() }, "Char": func(c rune) string { return string(c) }, } t, err := template.New("usage").Funcs(funcs).Parse(tmpl) if err != nil { return err } var selectedCommand *CmdModel if context.SelectedCommand != nil { selectedCommand = context.SelectedCommand.Model() } ctx := templateContext{ App: a.Model(), Width: width, Context: &templateParseContext{ SelectedCommand: selectedCommand, FlagGroupModel: context.flags.Model(), ArgGroupModel: context.arguments.Model(), }, } return t.Execute(a.usageWriter, ctx) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/usage_test.go000066400000000000000000000027611330143245600226770ustar00rootroot00000000000000package kingpin import ( "bytes" "strings" "testing" "github.com/stretchr/testify/assert" ) func TestFormatTwoColumns(t *testing.T) { buf := bytes.NewBuffer(nil) formatTwoColumns(buf, 2, 2, 20, [][2]string{ {"--hello", "Hello world help with something that is cool."}, }) expected := ` --hello Hello world help with something that is cool. ` assert.Equal(t, expected, buf.String()) } func TestFormatTwoColumnsWide(t *testing.T) { samples := [][2]string{ {strings.Repeat("x", 29), "29 chars"}, {strings.Repeat("x", 30), "30 chars"}} buf := bytes.NewBuffer(nil) formatTwoColumns(buf, 0, 0, 200, samples) expected := `xxxxxxxxxxxxxxxxxxxxxxxxxxxxx29 chars xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 30 chars ` assert.Equal(t, expected, buf.String()) } func TestHiddenCommand(t *testing.T) { templates := []struct{ name, template string }{ {"default", DefaultUsageTemplate}, {"Compact", CompactUsageTemplate}, {"Long", LongHelpTemplate}, {"Man", ManPageTemplate}, } var buf bytes.Buffer t.Log("1") a := New("test", "Test").Writer(&buf).Terminate(nil) a.Command("visible", "visible") a.Command("hidden", "hidden").Hidden() for _, tp := range templates { buf.Reset() a.UsageTemplate(tp.template) a.Parse(nil) // a.Parse([]string{"--help"}) usage := buf.String() t.Logf("Usage for %s is:\n%s\n", tp.name, usage) assert.NotContains(t, usage, "hidden") assert.Contains(t, usage, "visible") } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/values.go000066400000000000000000000235671330143245600220420ustar00rootroot00000000000000package kingpin //go:generate go run ./cmd/genvalues/main.go import ( "fmt" "net" "net/url" "os" "reflect" "regexp" "strings" "time" "github.com/alecthomas/units" ) // NOTE: Most of the base type values were lifted from: // http://golang.org/src/pkg/flag/flag.go?s=20146:20222 // Value is the interface to the dynamic value stored in a flag. // (The default value is represented as a string.) // // If a Value has an IsBoolFlag() bool method returning true, the command-line // parser makes --name equivalent to -name=true rather than using the next // command-line argument, and adds a --no-name counterpart for negating the // flag. type Value interface { String() string Set(string) error } // Getter is an interface that allows the contents of a Value to be retrieved. // It wraps the Value interface, rather than being part of it, because it // appeared after Go 1 and its compatibility rules. All Value types provided // by this package satisfy the Getter interface. type Getter interface { Value Get() interface{} } // Optional interface to indicate boolean flags that don't accept a value, and // implicitly have a --no- negation counterpart. type boolFlag interface { Value IsBoolFlag() bool } // Optional interface for arguments that cumulatively consume all remaining // input. type remainderArg interface { Value IsCumulative() bool } // Optional interface for flags that can be repeated. type repeatableFlag interface { Value IsCumulative() bool } type accumulator struct { element func(value interface{}) Value typ reflect.Type slice reflect.Value } // Use reflection to accumulate values into a slice. // // target := []string{} // newAccumulator(&target, func (value interface{}) Value { // return newStringValue(value.(*string)) // }) func newAccumulator(slice interface{}, element func(value interface{}) Value) *accumulator { typ := reflect.TypeOf(slice) if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Slice { panic("expected a pointer to a slice") } return &accumulator{ element: element, typ: typ.Elem().Elem(), slice: reflect.ValueOf(slice), } } func (a *accumulator) String() string { out := []string{} s := a.slice.Elem() for i := 0; i < s.Len(); i++ { out = append(out, a.element(s.Index(i).Addr().Interface()).String()) } return strings.Join(out, ",") } func (a *accumulator) Set(value string) error { e := reflect.New(a.typ) if err := a.element(e.Interface()).Set(value); err != nil { return err } slice := reflect.Append(a.slice.Elem(), e.Elem()) a.slice.Elem().Set(slice) return nil } func (a *accumulator) Get() interface{} { return a.slice.Interface() } func (a *accumulator) IsCumulative() bool { return true } func (b *boolValue) IsBoolFlag() bool { return true } // -- time.Duration Value type durationValue time.Duration func newDurationValue(p *time.Duration) *durationValue { return (*durationValue)(p) } func (d *durationValue) Set(s string) error { v, err := time.ParseDuration(s) *d = durationValue(v) return err } func (d *durationValue) Get() interface{} { return time.Duration(*d) } func (d *durationValue) String() string { return (*time.Duration)(d).String() } // -- map[string]string Value type stringMapValue map[string]string func newStringMapValue(p *map[string]string) *stringMapValue { return (*stringMapValue)(p) } var stringMapRegex = regexp.MustCompile("[:=]") func (s *stringMapValue) Set(value string) error { parts := stringMapRegex.Split(value, 2) if len(parts) != 2 { return fmt.Errorf("expected KEY=VALUE got '%s'", value) } (*s)[parts[0]] = parts[1] return nil } func (s *stringMapValue) Get() interface{} { return (map[string]string)(*s) } func (s *stringMapValue) String() string { return fmt.Sprintf("%s", map[string]string(*s)) } func (s *stringMapValue) IsCumulative() bool { return true } // -- net.IP Value type ipValue net.IP func newIPValue(p *net.IP) *ipValue { return (*ipValue)(p) } func (i *ipValue) Set(value string) error { if ip := net.ParseIP(value); ip == nil { return fmt.Errorf("'%s' is not an IP address", value) } else { *i = *(*ipValue)(&ip) return nil } } func (i *ipValue) Get() interface{} { return (net.IP)(*i) } func (i *ipValue) String() string { return (*net.IP)(i).String() } // -- *net.TCPAddr Value type tcpAddrValue struct { addr **net.TCPAddr } func newTCPAddrValue(p **net.TCPAddr) *tcpAddrValue { return &tcpAddrValue{p} } func (i *tcpAddrValue) Set(value string) error { if addr, err := net.ResolveTCPAddr("tcp", value); err != nil { return fmt.Errorf("'%s' is not a valid TCP address: %s", value, err) } else { *i.addr = addr return nil } } func (t *tcpAddrValue) Get() interface{} { return (*net.TCPAddr)(*t.addr) } func (i *tcpAddrValue) String() string { return (*i.addr).String() } // -- existingFile Value type fileStatValue struct { path *string predicate func(os.FileInfo) error } func newFileStatValue(p *string, predicate func(os.FileInfo) error) *fileStatValue { return &fileStatValue{ path: p, predicate: predicate, } } func (e *fileStatValue) Set(value string) error { if s, err := os.Stat(value); os.IsNotExist(err) { return fmt.Errorf("path '%s' does not exist", value) } else if err != nil { return err } else if err := e.predicate(s); err != nil { return err } *e.path = value return nil } func (f *fileStatValue) Get() interface{} { return (string)(*f.path) } func (e *fileStatValue) String() string { return *e.path } // -- os.File value type fileValue struct { f **os.File flag int perm os.FileMode } func newFileValue(p **os.File, flag int, perm os.FileMode) *fileValue { return &fileValue{p, flag, perm} } func (f *fileValue) Set(value string) error { if fd, err := os.OpenFile(value, f.flag, f.perm); err != nil { return err } else { *f.f = fd return nil } } func (f *fileValue) Get() interface{} { return (*os.File)(*f.f) } func (f *fileValue) String() string { if *f.f == nil { return "" } return (*f.f).Name() } // -- url.URL Value type urlValue struct { u **url.URL } func newURLValue(p **url.URL) *urlValue { return &urlValue{p} } func (u *urlValue) Set(value string) error { if url, err := url.Parse(value); err != nil { return fmt.Errorf("invalid URL: %s", err) } else { *u.u = url return nil } } func (u *urlValue) Get() interface{} { return (*url.URL)(*u.u) } func (u *urlValue) String() string { if *u.u == nil { return "" } return (*u.u).String() } // -- []*url.URL Value type urlListValue []*url.URL func newURLListValue(p *[]*url.URL) *urlListValue { return (*urlListValue)(p) } func (u *urlListValue) Set(value string) error { if url, err := url.Parse(value); err != nil { return fmt.Errorf("invalid URL: %s", err) } else { *u = append(*u, url) return nil } } func (u *urlListValue) Get() interface{} { return ([]*url.URL)(*u) } func (u *urlListValue) String() string { out := []string{} for _, url := range *u { out = append(out, url.String()) } return strings.Join(out, ",") } func (u *urlListValue) IsCumulative() bool { return true } // A flag whose value must be in a set of options. type enumValue struct { value *string options []string } func newEnumFlag(target *string, options ...string) *enumValue { return &enumValue{ value: target, options: options, } } func (a *enumValue) String() string { return *a.value } func (a *enumValue) Set(value string) error { for _, v := range a.options { if v == value { *a.value = value return nil } } return fmt.Errorf("enum value must be one of %s, got '%s'", strings.Join(a.options, ","), value) } func (e *enumValue) Get() interface{} { return (string)(*e.value) } // -- []string Enum Value type enumsValue struct { value *[]string options []string } func newEnumsFlag(target *[]string, options ...string) *enumsValue { return &enumsValue{ value: target, options: options, } } func (s *enumsValue) Set(value string) error { for _, v := range s.options { if v == value { *s.value = append(*s.value, value) return nil } } return fmt.Errorf("enum value must be one of %s, got '%s'", strings.Join(s.options, ","), value) } func (e *enumsValue) Get() interface{} { return ([]string)(*e.value) } func (s *enumsValue) String() string { return strings.Join(*s.value, ",") } func (s *enumsValue) IsCumulative() bool { return true } // -- units.Base2Bytes Value type bytesValue units.Base2Bytes func newBytesValue(p *units.Base2Bytes) *bytesValue { return (*bytesValue)(p) } func (d *bytesValue) Set(s string) error { v, err := units.ParseBase2Bytes(s) *d = bytesValue(v) return err } func (d *bytesValue) Get() interface{} { return units.Base2Bytes(*d) } func (d *bytesValue) String() string { return (*units.Base2Bytes)(d).String() } func newExistingFileValue(target *string) *fileStatValue { return newFileStatValue(target, func(s os.FileInfo) error { if s.IsDir() { return fmt.Errorf("'%s' is a directory", s.Name()) } return nil }) } func newExistingDirValue(target *string) *fileStatValue { return newFileStatValue(target, func(s os.FileInfo) error { if !s.IsDir() { return fmt.Errorf("'%s' is a file", s.Name()) } return nil }) } func newExistingFileOrDirValue(target *string) *fileStatValue { return newFileStatValue(target, func(s os.FileInfo) error { return nil }) } type counterValue int func newCounterValue(n *int) *counterValue { return (*counterValue)(n) } func (c *counterValue) Set(s string) error { *c++ return nil } func (c *counterValue) Get() interface{} { return (int)(*c) } func (c *counterValue) IsBoolFlag() bool { return true } func (c *counterValue) String() string { return fmt.Sprintf("%d", *c) } func (c *counterValue) IsCumulative() bool { return true } func resolveHost(value string) (net.IP, error) { if ip := net.ParseIP(value); ip != nil { return ip, nil } else { if addr, err := net.ResolveIPAddr("ip", value); err != nil { return nil, err } else { return addr.IP, nil } } } golang-gopkg-alecthomas-kingpin.v2-2.2.6/values.json000066400000000000000000000033421330143245600223730ustar00rootroot00000000000000[ {"type": "bool", "parser": "strconv.ParseBool(s)"}, {"type": "string", "parser": "s, error(nil)", "format": "string(*f.v)", "plural": "Strings"}, {"type": "uint", "parser": "strconv.ParseUint(s, 0, 64)", "plural": "Uints"}, {"type": "uint8", "parser": "strconv.ParseUint(s, 0, 8)"}, {"type": "uint16", "parser": "strconv.ParseUint(s, 0, 16)"}, {"type": "uint32", "parser": "strconv.ParseUint(s, 0, 32)"}, {"type": "uint64", "parser": "strconv.ParseUint(s, 0, 64)"}, {"type": "int", "parser": "strconv.ParseFloat(s, 64)", "plural": "Ints"}, {"type": "int8", "parser": "strconv.ParseInt(s, 0, 8)"}, {"type": "int16", "parser": "strconv.ParseInt(s, 0, 16)"}, {"type": "int32", "parser": "strconv.ParseInt(s, 0, 32)"}, {"type": "int64", "parser": "strconv.ParseInt(s, 0, 64)"}, {"type": "float64", "parser": "strconv.ParseFloat(s, 64)"}, {"type": "float32", "parser": "strconv.ParseFloat(s, 32)"}, {"name": "Duration", "type": "time.Duration", "no_value_parser": true}, {"name": "IP", "type": "net.IP", "no_value_parser": true}, {"name": "TCPAddr", "Type": "*net.TCPAddr", "plural": "TCPList", "no_value_parser": true}, {"name": "ExistingFile", "Type": "string", "plural": "ExistingFiles", "no_value_parser": true}, {"name": "ExistingDir", "Type": "string", "plural": "ExistingDirs", "no_value_parser": true}, {"name": "ExistingFileOrDir", "Type": "string", "plural": "ExistingFilesOrDirs", "no_value_parser": true}, {"name": "Regexp", "Type": "*regexp.Regexp", "parser": "regexp.Compile(s)"}, {"name": "ResolvedIP", "Type": "net.IP", "parser": "resolveHost(s)", "help": "Resolve a hostname or IP to an IP."}, {"name": "HexBytes", "Type": "[]byte", "parser": "hex.DecodeString(s)", "help": "Bytes as a hex string."} ] golang-gopkg-alecthomas-kingpin.v2-2.2.6/values_generated.go000066400000000000000000000446641330143245600240610ustar00rootroot00000000000000package kingpin import ( "encoding/hex" "fmt" "net" "regexp" "strconv" "time" ) // This file is autogenerated by "go generate .". Do not modify. // -- bool Value type boolValue struct{ v *bool } func newBoolValue(p *bool) *boolValue { return &boolValue{p} } func (f *boolValue) Set(s string) error { v, err := strconv.ParseBool(s) if err == nil { *f.v = (bool)(v) } return err } func (f *boolValue) Get() interface{} { return (bool)(*f.v) } func (f *boolValue) String() string { return fmt.Sprintf("%v", *f.v) } // Bool parses the next command-line value as bool. func (p *parserMixin) Bool() (target *bool) { target = new(bool) p.BoolVar(target) return } func (p *parserMixin) BoolVar(target *bool) { p.SetValue(newBoolValue(target)) } // BoolList accumulates bool values into a slice. func (p *parserMixin) BoolList() (target *[]bool) { target = new([]bool) p.BoolListVar(target) return } func (p *parserMixin) BoolListVar(target *[]bool) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newBoolValue(v.(*bool)) })) } // -- string Value type stringValue struct{ v *string } func newStringValue(p *string) *stringValue { return &stringValue{p} } func (f *stringValue) Set(s string) error { v, err := s, error(nil) if err == nil { *f.v = (string)(v) } return err } func (f *stringValue) Get() interface{} { return (string)(*f.v) } func (f *stringValue) String() string { return string(*f.v) } // String parses the next command-line value as string. func (p *parserMixin) String() (target *string) { target = new(string) p.StringVar(target) return } func (p *parserMixin) StringVar(target *string) { p.SetValue(newStringValue(target)) } // Strings accumulates string values into a slice. func (p *parserMixin) Strings() (target *[]string) { target = new([]string) p.StringsVar(target) return } func (p *parserMixin) StringsVar(target *[]string) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newStringValue(v.(*string)) })) } // -- uint Value type uintValue struct{ v *uint } func newUintValue(p *uint) *uintValue { return &uintValue{p} } func (f *uintValue) Set(s string) error { v, err := strconv.ParseUint(s, 0, 64) if err == nil { *f.v = (uint)(v) } return err } func (f *uintValue) Get() interface{} { return (uint)(*f.v) } func (f *uintValue) String() string { return fmt.Sprintf("%v", *f.v) } // Uint parses the next command-line value as uint. func (p *parserMixin) Uint() (target *uint) { target = new(uint) p.UintVar(target) return } func (p *parserMixin) UintVar(target *uint) { p.SetValue(newUintValue(target)) } // Uints accumulates uint values into a slice. func (p *parserMixin) Uints() (target *[]uint) { target = new([]uint) p.UintsVar(target) return } func (p *parserMixin) UintsVar(target *[]uint) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newUintValue(v.(*uint)) })) } // -- uint8 Value type uint8Value struct{ v *uint8 } func newUint8Value(p *uint8) *uint8Value { return &uint8Value{p} } func (f *uint8Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 8) if err == nil { *f.v = (uint8)(v) } return err } func (f *uint8Value) Get() interface{} { return (uint8)(*f.v) } func (f *uint8Value) String() string { return fmt.Sprintf("%v", *f.v) } // Uint8 parses the next command-line value as uint8. func (p *parserMixin) Uint8() (target *uint8) { target = new(uint8) p.Uint8Var(target) return } func (p *parserMixin) Uint8Var(target *uint8) { p.SetValue(newUint8Value(target)) } // Uint8List accumulates uint8 values into a slice. func (p *parserMixin) Uint8List() (target *[]uint8) { target = new([]uint8) p.Uint8ListVar(target) return } func (p *parserMixin) Uint8ListVar(target *[]uint8) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newUint8Value(v.(*uint8)) })) } // -- uint16 Value type uint16Value struct{ v *uint16 } func newUint16Value(p *uint16) *uint16Value { return &uint16Value{p} } func (f *uint16Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 16) if err == nil { *f.v = (uint16)(v) } return err } func (f *uint16Value) Get() interface{} { return (uint16)(*f.v) } func (f *uint16Value) String() string { return fmt.Sprintf("%v", *f.v) } // Uint16 parses the next command-line value as uint16. func (p *parserMixin) Uint16() (target *uint16) { target = new(uint16) p.Uint16Var(target) return } func (p *parserMixin) Uint16Var(target *uint16) { p.SetValue(newUint16Value(target)) } // Uint16List accumulates uint16 values into a slice. func (p *parserMixin) Uint16List() (target *[]uint16) { target = new([]uint16) p.Uint16ListVar(target) return } func (p *parserMixin) Uint16ListVar(target *[]uint16) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newUint16Value(v.(*uint16)) })) } // -- uint32 Value type uint32Value struct{ v *uint32 } func newUint32Value(p *uint32) *uint32Value { return &uint32Value{p} } func (f *uint32Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 32) if err == nil { *f.v = (uint32)(v) } return err } func (f *uint32Value) Get() interface{} { return (uint32)(*f.v) } func (f *uint32Value) String() string { return fmt.Sprintf("%v", *f.v) } // Uint32 parses the next command-line value as uint32. func (p *parserMixin) Uint32() (target *uint32) { target = new(uint32) p.Uint32Var(target) return } func (p *parserMixin) Uint32Var(target *uint32) { p.SetValue(newUint32Value(target)) } // Uint32List accumulates uint32 values into a slice. func (p *parserMixin) Uint32List() (target *[]uint32) { target = new([]uint32) p.Uint32ListVar(target) return } func (p *parserMixin) Uint32ListVar(target *[]uint32) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newUint32Value(v.(*uint32)) })) } // -- uint64 Value type uint64Value struct{ v *uint64 } func newUint64Value(p *uint64) *uint64Value { return &uint64Value{p} } func (f *uint64Value) Set(s string) error { v, err := strconv.ParseUint(s, 0, 64) if err == nil { *f.v = (uint64)(v) } return err } func (f *uint64Value) Get() interface{} { return (uint64)(*f.v) } func (f *uint64Value) String() string { return fmt.Sprintf("%v", *f.v) } // Uint64 parses the next command-line value as uint64. func (p *parserMixin) Uint64() (target *uint64) { target = new(uint64) p.Uint64Var(target) return } func (p *parserMixin) Uint64Var(target *uint64) { p.SetValue(newUint64Value(target)) } // Uint64List accumulates uint64 values into a slice. func (p *parserMixin) Uint64List() (target *[]uint64) { target = new([]uint64) p.Uint64ListVar(target) return } func (p *parserMixin) Uint64ListVar(target *[]uint64) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newUint64Value(v.(*uint64)) })) } // -- int Value type intValue struct{ v *int } func newIntValue(p *int) *intValue { return &intValue{p} } func (f *intValue) Set(s string) error { v, err := strconv.ParseFloat(s, 64) if err == nil { *f.v = (int)(v) } return err } func (f *intValue) Get() interface{} { return (int)(*f.v) } func (f *intValue) String() string { return fmt.Sprintf("%v", *f.v) } // Int parses the next command-line value as int. func (p *parserMixin) Int() (target *int) { target = new(int) p.IntVar(target) return } func (p *parserMixin) IntVar(target *int) { p.SetValue(newIntValue(target)) } // Ints accumulates int values into a slice. func (p *parserMixin) Ints() (target *[]int) { target = new([]int) p.IntsVar(target) return } func (p *parserMixin) IntsVar(target *[]int) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newIntValue(v.(*int)) })) } // -- int8 Value type int8Value struct{ v *int8 } func newInt8Value(p *int8) *int8Value { return &int8Value{p} } func (f *int8Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 8) if err == nil { *f.v = (int8)(v) } return err } func (f *int8Value) Get() interface{} { return (int8)(*f.v) } func (f *int8Value) String() string { return fmt.Sprintf("%v", *f.v) } // Int8 parses the next command-line value as int8. func (p *parserMixin) Int8() (target *int8) { target = new(int8) p.Int8Var(target) return } func (p *parserMixin) Int8Var(target *int8) { p.SetValue(newInt8Value(target)) } // Int8List accumulates int8 values into a slice. func (p *parserMixin) Int8List() (target *[]int8) { target = new([]int8) p.Int8ListVar(target) return } func (p *parserMixin) Int8ListVar(target *[]int8) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newInt8Value(v.(*int8)) })) } // -- int16 Value type int16Value struct{ v *int16 } func newInt16Value(p *int16) *int16Value { return &int16Value{p} } func (f *int16Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 16) if err == nil { *f.v = (int16)(v) } return err } func (f *int16Value) Get() interface{} { return (int16)(*f.v) } func (f *int16Value) String() string { return fmt.Sprintf("%v", *f.v) } // Int16 parses the next command-line value as int16. func (p *parserMixin) Int16() (target *int16) { target = new(int16) p.Int16Var(target) return } func (p *parserMixin) Int16Var(target *int16) { p.SetValue(newInt16Value(target)) } // Int16List accumulates int16 values into a slice. func (p *parserMixin) Int16List() (target *[]int16) { target = new([]int16) p.Int16ListVar(target) return } func (p *parserMixin) Int16ListVar(target *[]int16) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newInt16Value(v.(*int16)) })) } // -- int32 Value type int32Value struct{ v *int32 } func newInt32Value(p *int32) *int32Value { return &int32Value{p} } func (f *int32Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 32) if err == nil { *f.v = (int32)(v) } return err } func (f *int32Value) Get() interface{} { return (int32)(*f.v) } func (f *int32Value) String() string { return fmt.Sprintf("%v", *f.v) } // Int32 parses the next command-line value as int32. func (p *parserMixin) Int32() (target *int32) { target = new(int32) p.Int32Var(target) return } func (p *parserMixin) Int32Var(target *int32) { p.SetValue(newInt32Value(target)) } // Int32List accumulates int32 values into a slice. func (p *parserMixin) Int32List() (target *[]int32) { target = new([]int32) p.Int32ListVar(target) return } func (p *parserMixin) Int32ListVar(target *[]int32) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newInt32Value(v.(*int32)) })) } // -- int64 Value type int64Value struct{ v *int64 } func newInt64Value(p *int64) *int64Value { return &int64Value{p} } func (f *int64Value) Set(s string) error { v, err := strconv.ParseInt(s, 0, 64) if err == nil { *f.v = (int64)(v) } return err } func (f *int64Value) Get() interface{} { return (int64)(*f.v) } func (f *int64Value) String() string { return fmt.Sprintf("%v", *f.v) } // Int64 parses the next command-line value as int64. func (p *parserMixin) Int64() (target *int64) { target = new(int64) p.Int64Var(target) return } func (p *parserMixin) Int64Var(target *int64) { p.SetValue(newInt64Value(target)) } // Int64List accumulates int64 values into a slice. func (p *parserMixin) Int64List() (target *[]int64) { target = new([]int64) p.Int64ListVar(target) return } func (p *parserMixin) Int64ListVar(target *[]int64) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newInt64Value(v.(*int64)) })) } // -- float64 Value type float64Value struct{ v *float64 } func newFloat64Value(p *float64) *float64Value { return &float64Value{p} } func (f *float64Value) Set(s string) error { v, err := strconv.ParseFloat(s, 64) if err == nil { *f.v = (float64)(v) } return err } func (f *float64Value) Get() interface{} { return (float64)(*f.v) } func (f *float64Value) String() string { return fmt.Sprintf("%v", *f.v) } // Float64 parses the next command-line value as float64. func (p *parserMixin) Float64() (target *float64) { target = new(float64) p.Float64Var(target) return } func (p *parserMixin) Float64Var(target *float64) { p.SetValue(newFloat64Value(target)) } // Float64List accumulates float64 values into a slice. func (p *parserMixin) Float64List() (target *[]float64) { target = new([]float64) p.Float64ListVar(target) return } func (p *parserMixin) Float64ListVar(target *[]float64) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newFloat64Value(v.(*float64)) })) } // -- float32 Value type float32Value struct{ v *float32 } func newFloat32Value(p *float32) *float32Value { return &float32Value{p} } func (f *float32Value) Set(s string) error { v, err := strconv.ParseFloat(s, 32) if err == nil { *f.v = (float32)(v) } return err } func (f *float32Value) Get() interface{} { return (float32)(*f.v) } func (f *float32Value) String() string { return fmt.Sprintf("%v", *f.v) } // Float32 parses the next command-line value as float32. func (p *parserMixin) Float32() (target *float32) { target = new(float32) p.Float32Var(target) return } func (p *parserMixin) Float32Var(target *float32) { p.SetValue(newFloat32Value(target)) } // Float32List accumulates float32 values into a slice. func (p *parserMixin) Float32List() (target *[]float32) { target = new([]float32) p.Float32ListVar(target) return } func (p *parserMixin) Float32ListVar(target *[]float32) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newFloat32Value(v.(*float32)) })) } // DurationList accumulates time.Duration values into a slice. func (p *parserMixin) DurationList() (target *[]time.Duration) { target = new([]time.Duration) p.DurationListVar(target) return } func (p *parserMixin) DurationListVar(target *[]time.Duration) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newDurationValue(v.(*time.Duration)) })) } // IPList accumulates net.IP values into a slice. func (p *parserMixin) IPList() (target *[]net.IP) { target = new([]net.IP) p.IPListVar(target) return } func (p *parserMixin) IPListVar(target *[]net.IP) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newIPValue(v.(*net.IP)) })) } // TCPList accumulates *net.TCPAddr values into a slice. func (p *parserMixin) TCPList() (target *[]*net.TCPAddr) { target = new([]*net.TCPAddr) p.TCPListVar(target) return } func (p *parserMixin) TCPListVar(target *[]*net.TCPAddr) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newTCPAddrValue(v.(**net.TCPAddr)) })) } // ExistingFiles accumulates string values into a slice. func (p *parserMixin) ExistingFiles() (target *[]string) { target = new([]string) p.ExistingFilesVar(target) return } func (p *parserMixin) ExistingFilesVar(target *[]string) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newExistingFileValue(v.(*string)) })) } // ExistingDirs accumulates string values into a slice. func (p *parserMixin) ExistingDirs() (target *[]string) { target = new([]string) p.ExistingDirsVar(target) return } func (p *parserMixin) ExistingDirsVar(target *[]string) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newExistingDirValue(v.(*string)) })) } // ExistingFilesOrDirs accumulates string values into a slice. func (p *parserMixin) ExistingFilesOrDirs() (target *[]string) { target = new([]string) p.ExistingFilesOrDirsVar(target) return } func (p *parserMixin) ExistingFilesOrDirsVar(target *[]string) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newExistingFileOrDirValue(v.(*string)) })) } // -- *regexp.Regexp Value type regexpValue struct{ v **regexp.Regexp } func newRegexpValue(p **regexp.Regexp) *regexpValue { return ®expValue{p} } func (f *regexpValue) Set(s string) error { v, err := regexp.Compile(s) if err == nil { *f.v = (*regexp.Regexp)(v) } return err } func (f *regexpValue) Get() interface{} { return (*regexp.Regexp)(*f.v) } func (f *regexpValue) String() string { return fmt.Sprintf("%v", *f.v) } // Regexp parses the next command-line value as *regexp.Regexp. func (p *parserMixin) Regexp() (target **regexp.Regexp) { target = new(*regexp.Regexp) p.RegexpVar(target) return } func (p *parserMixin) RegexpVar(target **regexp.Regexp) { p.SetValue(newRegexpValue(target)) } // RegexpList accumulates *regexp.Regexp values into a slice. func (p *parserMixin) RegexpList() (target *[]*regexp.Regexp) { target = new([]*regexp.Regexp) p.RegexpListVar(target) return } func (p *parserMixin) RegexpListVar(target *[]*regexp.Regexp) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newRegexpValue(v.(**regexp.Regexp)) })) } // -- net.IP Value type resolvedIPValue struct{ v *net.IP } func newResolvedIPValue(p *net.IP) *resolvedIPValue { return &resolvedIPValue{p} } func (f *resolvedIPValue) Set(s string) error { v, err := resolveHost(s) if err == nil { *f.v = (net.IP)(v) } return err } func (f *resolvedIPValue) Get() interface{} { return (net.IP)(*f.v) } func (f *resolvedIPValue) String() string { return fmt.Sprintf("%v", *f.v) } // Resolve a hostname or IP to an IP. func (p *parserMixin) ResolvedIP() (target *net.IP) { target = new(net.IP) p.ResolvedIPVar(target) return } func (p *parserMixin) ResolvedIPVar(target *net.IP) { p.SetValue(newResolvedIPValue(target)) } // ResolvedIPList accumulates net.IP values into a slice. func (p *parserMixin) ResolvedIPList() (target *[]net.IP) { target = new([]net.IP) p.ResolvedIPListVar(target) return } func (p *parserMixin) ResolvedIPListVar(target *[]net.IP) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newResolvedIPValue(v.(*net.IP)) })) } // -- []byte Value type hexBytesValue struct{ v *[]byte } func newHexBytesValue(p *[]byte) *hexBytesValue { return &hexBytesValue{p} } func (f *hexBytesValue) Set(s string) error { v, err := hex.DecodeString(s) if err == nil { *f.v = ([]byte)(v) } return err } func (f *hexBytesValue) Get() interface{} { return ([]byte)(*f.v) } func (f *hexBytesValue) String() string { return fmt.Sprintf("%v", *f.v) } // Bytes as a hex string. func (p *parserMixin) HexBytes() (target *[]byte) { target = new([]byte) p.HexBytesVar(target) return } func (p *parserMixin) HexBytesVar(target *[]byte) { p.SetValue(newHexBytesValue(target)) } // HexBytesList accumulates []byte values into a slice. func (p *parserMixin) HexBytesList() (target *[][]byte) { target = new([][]byte) p.HexBytesListVar(target) return } func (p *parserMixin) HexBytesListVar(target *[][]byte) { p.SetValue(newAccumulator(target, func(v interface{}) Value { return newHexBytesValue(v.(*[]byte)) })) } golang-gopkg-alecthomas-kingpin.v2-2.2.6/values_test.go000066400000000000000000000046731330143245600230760ustar00rootroot00000000000000package kingpin import ( "net" "github.com/stretchr/testify/assert" "testing" ) func TestAccumulatorStrings(t *testing.T) { target := []string{} acc := newAccumulator(&target, func(v interface{}) Value { return newStringValue(v.(*string)) }) acc.Set("a") assert.Equal(t, []string{"a"}, target) acc.Set("b") assert.Equal(t, []string{"a", "b"}, target) } func TestStrings(t *testing.T) { app := New("", "") app.Arg("a", "").Required().String() app.Arg("b", "").Required().String() c := app.Arg("c", "").Required().Strings() app.Parse([]string{"a", "b", "a", "b"}) assert.Equal(t, []string{"a", "b"}, *c) } func TestEnum(t *testing.T) { app := New("", "") a := app.Arg("a", "").Enum("one", "two", "three") _, err := app.Parse([]string{"moo"}) assert.Error(t, err) _, err = app.Parse([]string{"one"}) assert.NoError(t, err) assert.Equal(t, "one", *a) } func TestEnumVar(t *testing.T) { app := New("", "") var a string app.Arg("a", "").EnumVar(&a, "one", "two", "three") _, err := app.Parse([]string{"moo"}) assert.Error(t, err) _, err = app.Parse([]string{"one"}) assert.NoError(t, err) assert.Equal(t, "one", a) } func TestCounter(t *testing.T) { app := New("", "") c := app.Flag("f", "").Counter() _, err := app.Parse([]string{"--f", "--f", "--f"}) assert.NoError(t, err) assert.Equal(t, 3, *c) } func TestIPv4Addr(t *testing.T) { app := newTestApp() flag := app.Flag("addr", "").ResolvedIP() _, err := app.Parse([]string{"--addr", net.IPv4(1, 2, 3, 4).String()}) assert.NoError(t, err) assert.NotNil(t, *flag) assert.Equal(t, net.IPv4(1, 2, 3, 4), *flag) } func TestInvalidIPv4Addr(t *testing.T) { app := newTestApp() app.Flag("addr", "").ResolvedIP() _, err := app.Parse([]string{"--addr", "1.2.3.256"}) assert.Error(t, err) } func TestIPv6Addr(t *testing.T) { app := newTestApp() flag := app.Flag("addr", "").ResolvedIP() _, err := app.Parse([]string{"--addr", net.IPv6interfacelocalallnodes.String()}) assert.NoError(t, err) assert.NotNil(t, *flag) assert.Equal(t, net.IPv6interfacelocalallnodes, *flag) } func TestHexBytes(t *testing.T) { app := newTestApp() actual := app.Arg("bytes", "").HexBytes() _, err := app.Parse([]string{"01020aff"}) assert.NoError(t, err) assert.Equal(t, []byte{0x01, 0x02, 0x0a, 0xff}, *actual) } func TestSetValueDoesNotReset(t *testing.T) { app := newTestApp() mapping := map[string]string{ "key": "value", } app.Flag("set", "").StringMapVar(&mapping) assert.NotEmpty(t, mapping) }