pax_global_header00006660000000000000000000000064132451504760014521gustar00rootroot0000000000000052 comment=b8d601de6db1f3b56a99ffe9051eb708574bc1cd golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/000077500000000000000000000000001324515047600226405ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/.gometalinter.conf000066400000000000000000000005211324515047600262550ustar00rootroot00000000000000{ "Exclude": [ "should have comment or be unexported", "comment on exported", "Use of unsafe calls should be audited", "unused struct field github.com/alecthomas/kingpin.cmdGroup.parent", "don't use underscores in Go names; var i18n_" ], "Disable": ["unconvert", "gocyclo", "maligned", "errcheck", "goconst"] } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/.travis.yml000066400000000000000000000003571324515047600247560ustar00rootroot00000000000000sudo: false language: go install: - go get github.com/alecthomas/gometalinter - gometalinter --install - go get -t -v ./... script: - go test -v ./... - gometalinter --config .gometalinter.conf go: [1.6, 1.7, 1.8, 1.9] golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/COPYING000066400000000000000000000020371324515047600236750ustar00rootroot00000000000000Copyright (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.v3-3.0~git20180227.b8d601d/README.md000066400000000000000000000622361324515047600241300ustar00rootroot00000000000000# 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.png)](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 v2 and v3](#user-visible-changes-between-v2-and-v3) - [Some flag types have been removed.](#some-flag-types-have-been-removed) - [Semantics around boolean flags have changed.](#semantics-around-boolean-flags-have-changed) - [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) - [Configuration files and other external sources of flag/argument values](#configuration-files-and-other-external-sources-of-flagargument-values) - [Struct tag interpolation](#struct-tag-interpolation) - [Bash/ZSH Shell Completion](#bashzsh-shell-completion) - [Additional API](#additional-api) - [Supporting -h for help](#supporting--h-for-help) - [Custom help](#custom-help) - [Adding a new help command](#adding-a-new-help-command) - [Default help template](#default-help-template) - [Compact help template](#compact-help-template) ## 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`). - Negatable boolean flags (`--[no-]flag`). ## User-visible changes between v2 and v3 ### Some flag types have been removed. Some flag types had unintended side-effects, or poor usability. For example, flags that created/opened files could result in file-descriptor leaks. To avoid confusion these have been removed. ### Semantics around boolean flags have changed. `Bool()` now creates a non-negatable flag. Use `NegatableBool()` to add a boolean flag that supports both `--flag` and `--no-flag`. This will be displayed in the help. ## 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 0 ``` 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", *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()`. 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.")) ``` ### Configuration files and other external sources of flag/argument values Kingpin v3 now supports [custom value resolvers](https://godoc.org/gopkg.in/alecthomas/kingpin.v3-unstable#Resolver) for flags and arguments. This is used internally to resolve default values and environment variables, but applications can define their own resolvers to load flags from configuration files, or elsewhere. Included is a [JSONResolver](https://godoc.org/gopkg.in/alecthomas/kingpin.v3-unstable#JSONResolver) that loads values from a JSON file, including multi-value flags. ### Struct tag interpolation Kingpin v3 now supports defining flags, arguments and commands via struct reflection. If desired, this can (almost) completely replace the fluent-style interface. The name of the flag will default to the CamelCase name transformed to camel- case. This can be overridden with the "long" tag. All basic Go types are supported including floats, ints, strings, time.Duration, and slices of same. For compatibility, also supports the tags used by https://github.com/jessevdk/go-flags ```go type MyFlags struct { Arg string `arg:"true" help:"An argument"` Debug bool `help:"Enable debug mode."` URL string `help:"URL to connect to." default:"localhost:80"` Login struct { Name string `help:"Username to authenticate with." args:"true"` } `help:"Login to server."` } flags := &MyFlags{} kingpin.Struct(flags) ``` Supported struct tags are: | Tag | Description | | --------------- | ------------------------------------------- | | `help` | Help text. | | `placeholder` | Placeholder text. | | `default` | Default value. | | `short` | Short name, if flag. | | `long` | Long name, for overriding field name. | | `required` | If present, flag/arg is required. | | `hidden` | If present, flag/arg/command is hidden. | | `enum` | For enums, a comma separated list of cases. | | `arg` | If true, field is an argument. | ### 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(args []string) []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.GetFlag("help").Short('h')` ### Custom help Kingpin supports templatised help using the text/template library. 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, 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. #### Adding a new help command It is often useful to add extra help formats, such as man pages, etc. Here's how you'd add a `--help-man` flag: ```go kingpin.Flag("help-man", "Generate man page."). UsageActionTemplate(kingpin.ManPageTemplate). Bool() ``` #### 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.v3-3.0~git20180227.b8d601d/_examples/000077500000000000000000000000001324515047600246155ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/chat1/000077500000000000000000000000001324515047600256155ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/chat1/main.go000066400000000000000000000010541324515047600270700ustar00rootroot00000000000000package 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.v3-3.0~git20180227.b8d601d/_examples/chat2/000077500000000000000000000000001324515047600256165ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/chat2/main.go000066400000000000000000000020351324515047600270710ustar00rootroot00000000000000package 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.v3-3.0~git20180227.b8d601d/_examples/completion/000077500000000000000000000000001324515047600267665ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/completion/main.go000066400000000000000000000056471324515047600302550ustar00rootroot00000000000000package main import ( "fmt" "os" "github.com/alecthomas/kingpin" ) 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.v3-3.0~git20180227.b8d601d/_examples/curl/000077500000000000000000000000001324515047600255625ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/curl/main.go000066400000000000000000000056321324515047600270430ustar00rootroot00000000000000// A curl-like HTTP command-line client. package main import ( "errors" "fmt" "io" "net/http" "os" "strings" "github.com/alecthomas/kingpin" ) 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.").String() 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") } body, err := os.Open(*postBinaryFile) if err != nil { return err } req.Body = body } 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.v3-3.0~git20180227.b8d601d/_examples/modular/000077500000000000000000000000001324515047600262605ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/modular/main.go000066400000000000000000000011071324515047600275320ustar00rootroot00000000000000package main import ( "fmt" "os" "gopkg.in/alecthomas/kingpin.v3-unstable" ) // 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.v3-3.0~git20180227.b8d601d/_examples/ping/000077500000000000000000000000001324515047600255525ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/_examples/ping/main.go000066400000000000000000000010511324515047600270220ustar00rootroot00000000000000package 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.v3-3.0~git20180227.b8d601d/actions.go000066400000000000000000000022501324515047600246260ustar00rootroot00000000000000package kingpin // Action callback triggered during parsing. // // "element" is the flag, argument or command associated with the callback. It contains the Clause // and string value, if any. // // "context" contains the full parse context, including all other elements that have been parsed. type Action func(element *ParseElement, context *ParseContext) error type actionApplier interface { applyActions(*ParseElement, *ParseContext) error applyPreActions(*ParseElement, *ParseContext) error } type actionMixin struct { actions []Action preActions []Action } func (a *actionMixin) addAction(action Action) { a.actions = append(a.actions, action) } func (a *actionMixin) addPreAction(action Action) { a.actions = append(a.actions, action) } func (a *actionMixin) applyActions(element *ParseElement, context *ParseContext) error { for _, action := range a.actions { if err := action(element, context); err != nil { return err } } return nil } func (a *actionMixin) applyPreActions(element *ParseElement, context *ParseContext) error { for _, preAction := range a.preActions { if err := preAction(element, context); err != nil { return err } } return nil } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/actions_test.go000066400000000000000000000023101324515047600256620ustar00rootroot00000000000000package kingpin import ( "testing" "github.com/stretchr/testify/require" ) func TestFlagPreAction(t *testing.T) { a := newTestApp() actual := "" flag := a.Flag("flag", "").PreAction(func(e *ParseElement, c *ParseContext) error { actual = *e.Value return nil }).NegatableBool() _, err := a.Parse([]string{}) require.NoError(t, err) require.Equal(t, "", actual) require.False(t, *flag) _, err = a.Parse([]string{"--flag"}) require.NoError(t, err) require.Equal(t, "true", actual) require.True(t, *flag) _, err = a.Parse([]string{"--no-flag"}) require.NoError(t, err) require.Equal(t, "false", actual) require.False(t, *flag) } func TestFlagAction(t *testing.T) { a := newTestApp() actual := "" flag := a.Flag("flag", "").PreAction(func(e *ParseElement, c *ParseContext) error { actual = *e.Value return nil }).NegatableBool() _, err := a.Parse([]string{}) require.NoError(t, err) require.Equal(t, "", actual) require.False(t, *flag) _, err = a.Parse([]string{"--flag"}) require.NoError(t, err) require.Equal(t, "true", actual) require.True(t, *flag) _, err = a.Parse([]string{"--no-flag"}) require.NoError(t, err) require.Equal(t, "false", actual) require.False(t, *flag) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/app.go000066400000000000000000000454561324515047600237650ustar00rootroot00000000000000package kingpin import ( "fmt" "io" "os" "strings" ) var ( errCommandNotSpecified = TError("command not specified") ) // 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 output io.Writer // Destination for usage. errors io.Writer terminate func(status int) // See Terminate() noInterspersed bool // can flags be interspersed with args (or must they come first) envarSeparator string defaultEnvars bool resolvers []Resolver completion bool helpFlag *Clause helpCommand *CmdClause defaultUsage *UsageContext } // New creates a new Kingpin application instance. func New(name, help string) *Application { a := &Application{ Name: name, Help: help, output: os.Stdout, errors: os.Stderr, terminate: os.Exit, envarSeparator: string(os.PathListSeparator), defaultUsage: &UsageContext{ Template: DefaultUsageTemplate, }, } a.flagGroup = newFlagGroup() a.argGroup = newArgGroup() a.cmdGroup = newCmdGroup(a) a.helpFlag = a.Flag("help", T("Show context-sensitive help.")).Action(func(e *ParseElement, c *ParseContext) error { c.Application.UsageForContext(c) c.Application.terminate(0) return nil }) a.helpFlag.Bool() a.Flag("completion-bash", T("Output possible completions for the given args.")).Hidden().BoolVar(&a.completion) a.Flag("completion-script-bash", T("Generate completion script for bash.")).Hidden().PreAction(a.generateBashCompletionScript).Bool() a.Flag("completion-script-zsh", T("Generate completion script for ZSH.")).Hidden().PreAction(a.generateZSHCompletionScript).Bool() return a } // Struct allows applications to define flags with struct tags. // // Supported struct tags are: help, placeholder, default, short, long, required, hidden, env, // enum, and arg. // // The name of the flag will default to the CamelCase name transformed to camel-case. This can // be overridden with the "long" tag. // // All basic Go types are supported including floats, ints, strings, time.Duration, // and slices of same. // // For compatibility, also supports the tags used by https://github.com/jessevdk/go-flags func (a *Application) Struct(v interface{}) error { return a.fromStruct(nil, v) } func (a *Application) generateBashCompletionScript(e *ParseElement, c *ParseContext) error { usageContext := &UsageContext{ Template: BashCompletionTemplate, } a.Writers(os.Stdout, os.Stderr) if err := a.UsageForContextWithTemplate(usageContext, c); err != nil { return err } a.terminate(0) return nil } func (a *Application) generateZSHCompletionScript(e *ParseElement, c *ParseContext) error { usageContext := &UsageContext{ Template: ZshCompletionTemplate, } a.Writers(os.Stdout, os.Stderr) if err := a.UsageForContextWithTemplate(usageContext, c); err != nil { return err } a.terminate(0) return nil } // Action is an application-wide callback. It is used in two situations: first, with a nil "element" // parameter when parsing is complete, and second whenever a command, argument or flag is // encountered. func (a *Application) Action(action Action) *Application { a.addAction(action) return a } // PreAction is an application-wide callback. It is in two situations: first, with a nil "element" // parameter, and second, whenever a command, argument or flag is encountered. func (a *Application) PreAction(action Action) *Application { a.addPreAction(action) return a } // 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 } // EnvarSeparator sets the string that is used for separating values in environment variables. // // This defaults to the current OS's path list separator (typically : or ;). func (a *Application) EnvarSeparator(sep string) *Application { a.envarSeparator = sep return a } // Resolver adds an ordered set of flag/argument resolvers. // // Resolvers provide default flag/argument values, from environment variables, configuration files, etc. Multiple // resolvers may be added, and they are processed in order. // // The last Resolver to return a value always wins. Values returned from resolvers are not cumulative. func (a *Application) Resolver(resolvers ...Resolver) *Application { a.resolvers = append(a.resolvers, resolvers...) 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 } // Writers specifies the writers to use for usage and errors. Defaults to os.Stderr. func (a *Application) Writers(out, err io.Writer) *Application { a.output = out a.errors = err return a } // UsageTemplate specifies the text template to use when displaying usage // information via --help. The default is DefaultUsageTemplate. func (a *Application) UsageTemplate(template string) *Application { a.defaultUsage.Template = template return a } // UsageContext specifies the UsageContext to use when displaying usage // information via --help. func (a *Application) UsageContext(context *UsageContext) *Application { a.defaultUsage = context 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, a.buildResolvers()) context.Application = a err := parse(context, a) return context, err } // Build resolvers to emulate the envar and defaults behaviour that was previously hard-coded. func (a *Application) buildResolvers() []Resolver { // .Default() has lowest priority... resolvers := []Resolver{defaultsResolver()} // Then custom resolvers... resolvers = append(resolvers, a.resolvers...) // Finally, envars are highest priority behind direct flag parsing. if a.defaultEnvars { resolvers = append(resolvers, PrefixedEnvarResolver(a.Name+"_", a.envarSeparator)) } resolvers = append(resolvers, envarResolver(a.envarSeparator)) return resolvers } // 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) 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 "", TError("unexpected argument '{{.Arg0}}'", V{"Arg0": 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) } a.terminate(1) } func (a *Application) maybeHelp(context *ParseContext) { for _, element := range context.Elements { if element.OneOf.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.Flag("version", T("Show application version.")). PreAction(func(*ParseElement, *ParseContext) error { fmt.Fprintln(a.output, version) a.terminate(0) return nil }). Bool() return a } // Author sets the author name for usage templates. func (a *Application) Author(author string) *Application { a.author = author 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) init() error { if a.initialized { return nil } if err := a.checkArgCommandMixing(); err != nil { return err } // If we have subcommands, add a help command at the top-level. if a.cmdGroup.have() { var command []string a.helpCommand = a.Command("help", T("Show help.")). PreAction(func(element *ParseElement, context *ParseContext) error { a.Usage(command) command = []string{} a.terminate(0) return nil }) a.helpCommand. Arg("command", T("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(); 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 TError("duplicate short flag -{{.Arg0}}", V{"Arg0": flag.shorthand}) } } if _, ok := flags.long[flag.name]; ok { return TError("duplicate long flag --{{.Arg0}}", V{"Arg0": 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.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 := context.Elements.FlagMap() argElements := context.Elements.ArgMap() // Check required flags and set defaults. for _, flag := range context.flags.long { if flagElements[flag.name] == nil { if err := flag.setDefault(context); err != nil { return err } } else { flag.reset() } } for _, arg := range context.arguments.args { if argElements[arg.name] == nil { if err := arg.setDefault(context); err != nil { return err } } else { arg.reset() } } return nil } func (a *Application) validateRequired(context *ParseContext) error { flagElements := context.Elements.FlagMap() argElements := context.Elements.ArgMap() // 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(context) { return TError("required flag --{{.Arg0}} not provided", V{"Arg0": flag.name}) } } } for _, arg := range context.arguments.args { if argElements[arg.name] == nil { if arg.needsValue(context) { return TError("required argument '{{.Arg0}}' not provided", V{"Arg0": 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 { case element.OneOf.Flag != nil: clause := element.OneOf.Flag if _, ok := flagSet[clause.name]; ok { if v, ok := clause.value.(cumulativeValue); !ok || !v.IsCumulative() { return nil, TError("flag '{{.Arg0}}' cannot be repeated", V{"Arg0": clause.name}) } } if err = clause.value.Set(*element.Value); err != nil { return } flagSet[clause.name] = struct{}{} case element.OneOf.Arg != nil: clause := element.OneOf.Arg if err = clause.value.Set(*element.Value); err != nil { return } case element.OneOf.Cmd != nil: clause := element.OneOf.Cmd if clause.validator != nil { if err = clause.validator(clause); err != nil { return } } selected = append(selected, clause.name) lastCmd = clause } } if lastCmd == nil || lastCmd.optionalSubcommands { return } if len(lastCmd.commands) > 0 { return nil, TError("must select a subcommand of '{{.Arg0}}'", V{"Arg0": lastCmd.FullCommand()}) } return } // Errorf prints an error message to w in the format ": error: ". func (a *Application) Errorf(format string, args ...interface{}) { fmt.Fprintf(a.errors, a.Name+T(": 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...) 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 (a *Application) applyPreActions(context *ParseContext, dispatch bool) error { if !dispatch { return nil } if err := a.actionMixin.applyPreActions(nil, context); err != nil { return err } for _, element := range context.Elements { if err := a.actionMixin.applyPreActions(element, context); err != nil { return err } var applier actionApplier switch { case element.OneOf.Arg != nil: applier = element.OneOf.Arg case element.OneOf.Flag != nil: applier = element.OneOf.Flag case element.OneOf.Cmd != nil: applier = element.OneOf.Cmd } if err := applier.applyPreActions(element, context); err != nil { return err } } return nil } func (a *Application) applyActions(context *ParseContext) error { if err := a.actionMixin.applyActions(nil, context); err != nil { return err } // Dispatch to actions. for _, element := range context.Elements { if err := a.actionMixin.applyActions(element, context); err != nil { return err } var applier actionApplier switch { case element.OneOf.Arg != nil: applier = element.OneOf.Arg case element.OneOf.Flag != nil: applier = element.OneOf.Flag case element.OneOf.Cmd != nil: applier = element.OneOf.Cmd } if err := applier.applyActions(element, context); err != nil { return err } } return nil } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/app_test.go000066400000000000000000000271251324515047600250150ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "os" "github.com/stretchr/testify/assert" "sort" "strings" "testing" "time" ) func newTestApp() *Application { return New("test", ""). Terminate(nil). Writers(ioutil.Discard, ioutil.Discard) } 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().Writers(ioutil.Discard, 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(element *ParseElement, context *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 TestOptionalSubcommandsApp(t *testing.T) { app := newTestApp() c0 := app.Command("c0", "").OptionalSubcommands() c0.Command("c1", "") s, err := app.Parse([]string{"c0"}) assert.NoError(t, err) assert.Equal(t, "c0", s) } 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() os.Setenv("SOME_APP_SOME_FLAG", "true") f0 := a.Flag("some-flag", "").Bool() f1 := a.Flag("some-other-flag", "").NoEnvar() f1.Bool() _, err := a.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, true, *f0) assert.Equal(t, "", f1.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) } } func TestApplicationWideActions(t *testing.T) { a := newTestApp() a.Flag("--flag", "").String() c := a.Command("cmd", "") c.Arg("arg", "").String() preValues := []string{} a.PreAction(func(element *ParseElement, context *ParseContext) error { preValues = append(preValues, *element.Value) return nil }) values := []string{} a.Action(func(element *ParseElement, context *ParseContext) error { values = append(values, *element.Value) return nil }) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/args.go000066400000000000000000000024231324515047600241240ustar00rootroot00000000000000package kingpin type argGroup struct { args []*Clause } 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) *Clause { for _, arg := range a.args { if arg.name == name { return arg } } return nil } func (a *argGroup) Arg(name, help string) *Clause { arg := NewClause(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 TError("Args() can't be followed by another argument '{{.Arg0}}'", V{"Arg0": arg.name}) } if arg.consumesRemainder() { previousArgMustBeLast = true } if _, ok := seen[arg.name]; ok { return TError("duplicate argument '{{.Arg0}}'", V{"Arg0": arg.name}) } seen[arg.name] = struct{}{} if arg.required && required != i { return TError("required arguments found after non-required") } if arg.required { required++ } if err := arg.init(); err != nil { return err } } return nil } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/args_test.go000066400000000000000000000041431324515047600251640ustar00rootroot00000000000000package kingpin import ( "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 := newTestApp().Version("0.0.0") 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) _, _ = 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.v3-3.0~git20180227.b8d601d/camelcase.go000066400000000000000000000055061324515047600251120ustar00rootroot00000000000000package kingpin // NOTE: This code is from https://github.com/fatih/camelcase. MIT license. import ( "unicode" "unicode/utf8" ) // Split splits the camelcase word and returns a list of words. It also // supports digits. Both lower camel case and upper camel case are supported. // For more info please check: http://en.wikipedia.org/wiki/CamelCase // // Examples // // "" => [""] // "lowercase" => ["lowercase"] // "Class" => ["Class"] // "MyClass" => ["My", "Class"] // "MyC" => ["My", "C"] // "HTML" => ["HTML"] // "PDFLoader" => ["PDF", "Loader"] // "AString" => ["A", "String"] // "SimpleXMLParser" => ["Simple", "XML", "Parser"] // "vimRPCPlugin" => ["vim", "RPC", "Plugin"] // "GL11Version" => ["GL", "11", "Version"] // "99Bottles" => ["99", "Bottles"] // "May5" => ["May", "5"] // "BFG9000" => ["BFG", "9000"] // "BöseÜberraschung" => ["Böse", "Überraschung"] // "Two spaces" => ["Two", " ", "spaces"] // "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"] // // Splitting rules // // 1) If string is not valid UTF-8, return it without splitting as // single item array. // 2) Assign all unicode characters into one of 4 sets: lower case // letters, upper case letters, numbers, and all other characters. // 3) Iterate through characters of string, introducing splits // between adjacent characters that belong to different sets. // 4) Iterate through array of split strings, and if a given string // is upper case: // if subsequent string is lower case: // move last character of upper case string to beginning of // lower case string func camelCase(src string) (entries []string) { // don't split invalid utf8 if !utf8.ValidString(src) { return []string{src} } entries = []string{} var runes [][]rune lastClass := 0 // split into fields based on class of unicode character for _, r := range src { var class int switch true { case unicode.IsLower(r): class = 1 case unicode.IsUpper(r): class = 2 case unicode.IsDigit(r): class = 3 default: class = 4 } if class == lastClass { runes[len(runes)-1] = append(runes[len(runes)-1], r) } else { runes = append(runes, []rune{r}) } lastClass = class } // handle upper case -> lower case sequences, e.g. // "PDFL", "oader" -> "PDF", "Loader" for i := 0; i < len(runes)-1; i++ { if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) { runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...) runes[i] = runes[i][:len(runes[i])-1] } } // construct []string from results for _, s := range runes { if len(s) > 0 { entries = append(entries, string(s)) } } return } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/clause.go000066400000000000000000000205741324515047600244530ustar00rootroot00000000000000package kingpin import ( "net" "github.com/alecthomas/units" ) // A Clause represents a flag or an argument passed by the user. type Clause struct { actionMixin completionsMixin name string shorthand rune help string placeholder string hidden bool defaultValues []string value Value required bool envar string noEnvar bool } func NewClause(name, help string) *Clause { return &Clause{ name: name, help: help, } } func (c *Clause) consumesRemainder() bool { if r, ok := c.value.(cumulativeValue); ok { return r.IsCumulative() } return false } func (c *Clause) init() error { if c.required && len(c.defaultValues) > 0 { return TError("required flag '--{{.Arg0}}' with default value that will never be used", V{"Arg0": c.name}) } if c.value == nil { return TError("no type defined for --{{.Arg0}} (eg. .String())", V{"Arg0": c.name}) } if v, ok := c.value.(cumulativeValue); (!ok || !v.IsCumulative()) && len(c.defaultValues) > 1 { return TError("invalid default for '--{{.Arg0}}', expecting single value", V{"Arg0": c.name}) } return nil } func (c *Clause) Help(help string) *Clause { c.help = help return c } // UsageAction adds a PreAction() that will display the given UsageContext. func (c *Clause) UsageAction(context *UsageContext) *Clause { c.PreAction(func(e *ParseElement, c *ParseContext) error { c.Application.UsageForContextWithTemplate(context, c) c.Application.terminate(0) return nil }) return c } func (c *Clause) UsageActionTemplate(template string) *Clause { return c.UsageAction(&UsageContext{Template: template}) } // Action adds a callback action to be executed after the command line is parsed and any // non-terminating builtin actions have completed (eg. help, completion, etc.). func (c *Clause) Action(action Action) *Clause { c.actions = append(c.actions, action) return c } // PreAction adds a callback action to be executed after flag values are parsed but before // any other processing, such as help, completion, etc. func (c *Clause) PreAction(action Action) *Clause { c.preActions = append(c.preActions, action) return c } // HintAction registers a HintAction (function) for the flag to provide completions func (c *Clause) HintAction(action HintAction) *Clause { c.addHintAction(action) return c } // 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 (c *Clause) Envar(name string) *Clause { c.envar = name c.noEnvar = false return c } // NoEnvar forces environment variable defaults to be disabled for this flag. // Most useful in conjunction with PrefixedEnvarResolver. func (c *Clause) NoEnvar() *Clause { c.envar = "" c.noEnvar = true return c } func (c *Clause) resolveCompletions() []string { var hints []string options := c.builtinHintActions if len(c.hintActions) > 0 { // User specified their own hintActions. Use those instead. options = c.hintActions } for _, hintAction := range options { hints = append(hints, hintAction()...) } return hints } // HintOptions registers any number of options for the flag to provide completions func (c *Clause) HintOptions(options ...string) *Clause { c.addHintAction(func() []string { return options }) return c } // Default values for this flag. They *must* be parseable by the value of the flag. func (c *Clause) Default(values ...string) *Clause { c.defaultValues = values return c } // 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 (c *Clause) PlaceHolder(placeholder string) *Clause { c.placeholder = placeholder return c } // Hidden hides a flag from usage but still allows it to be used. func (c *Clause) Hidden() *Clause { c.hidden = true return c } // Required makes the flag required. You can not provide a Default() value to a Required() flag. func (c *Clause) Required() *Clause { c.required = true return c } // Short sets the short flag name. func (c *Clause) Short(name rune) *Clause { c.shorthand = name return c } func (c *Clause) needsValue(context *ParseContext) bool { return c.required && !c.canResolve(context) } func (c *Clause) canResolve(context *ParseContext) bool { for _, resolver := range context.resolvers { rvalues, err := resolver.Resolve(c.name, context) if err != nil { return false } if rvalues != nil { return true } } return false } func (c *Clause) reset() { if c, ok := c.value.(cumulativeValue); ok { c.Reset() } } func (c *Clause) setDefault(context *ParseContext) error { var values []string for _, resolver := range context.resolvers { rvalues, err := resolver.Resolve(c.name, context) if err != nil { return err } if rvalues != nil { values = rvalues } } if values != nil { c.reset() for _, value := range values { if err := c.value.Set(value); err != nil { return err } } return nil } return nil } func (c *Clause) SetValue(value Value) { c.value = value } // StringMap provides key=value parsing into a map. func (c *Clause) StringMap(options ...AccumulatorOption) (target *map[string]string) { target = &(map[string]string{}) c.StringMapVar(target, options...) return } // StringMap provides key=value parsing into a map. func (c *Clause) StringMapVar(target *map[string]string, options ...AccumulatorOption) { c.SetValue(newStringMapValue(target, options...)) } // Bytes parses numeric byte units. eg. 1.5KB func (c *Clause) Bytes() (target *units.Base2Bytes) { target = new(units.Base2Bytes) c.BytesVar(target) return } // ExistingFile sets the parser to one that requires and returns an existing file. func (c *Clause) ExistingFile() (target *string) { target = new(string) c.ExistingFileVar(target) return } // ExistingDir sets the parser to one that requires and returns an existing directory. func (c *Clause) ExistingDir() (target *string) { target = new(string) c.ExistingDirVar(target) return } // ExistingFileOrDir sets the parser to one that requires and returns an existing file OR directory. func (c *Clause) ExistingFileOrDir() (target *string) { target = new(string) c.ExistingFileOrDirVar(target) return } // Float sets the parser to a float64 parser. func (c *Clause) Float() (target *float64) { return c.Float64() } // Float sets the parser to a float64 parser. func (c *Clause) FloatVar(target *float64) { c.Float64Var(target) } // BytesVar parses numeric byte units. eg. 1.5KB func (c *Clause) BytesVar(target *units.Base2Bytes) { c.SetValue(newBytesValue(target)) } // ExistingFile sets the parser to one that requires and returns an existing file. func (c *Clause) ExistingFileVar(target *string) { c.SetValue(newExistingFileValue(target)) } // ExistingDir sets the parser to one that requires and returns an existing directory. func (c *Clause) ExistingDirVar(target *string) { c.SetValue(newExistingDirValue(target)) } // ExistingDir sets the parser to one that requires and returns an existing directory. func (c *Clause) ExistingFileOrDirVar(target *string) { c.SetValue(newExistingFileOrDirValue(target)) } // Enum allows a value from a set of options. func (c *Clause) Enum(options ...string) (target *string) { target = new(string) c.EnumVar(target, options...) return } // EnumVar allows a value from a set of options. func (c *Clause) EnumVar(target *string, options ...string) { c.addHintActionBuiltin(func() []string { return options }) c.SetValue(newEnumFlag(target, options...)) } // Enums allows a set of values from a set of options. func (c *Clause) Enums(options ...string) (target *[]string) { target = new([]string) c.EnumsVar(target, options...) return } // EnumsVar allows a value from a set of options. func (c *Clause) EnumsVar(target *[]string, options ...string) { c.SetValue(newEnumsFlag(target, options...)) } // Counter increments a number each time it is encountered. func (c *Clause) Counter() (target *int) { target = new(int) c.CounterVar(target) return } func (c *Clause) CounterVar(target *int) { c.SetValue(newCounterValue(target)) } // IP provides a validated parsed *net.IP value. func (c *Clause) IP() (target *net.IP) { target = new(net.IP) c.IPVar(target) return } // IPVar provides a validated parsed *net.IP value. func (c *Clause) IPVar(target *net.IP) { c.SetValue(newIPValue(target)) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/clause_test.go000066400000000000000000000034041324515047600255030ustar00rootroot00000000000000package kingpin import ( "io/ioutil" "net/url" "os" "github.com/stretchr/testify/assert" "testing" ) func TestParseStrings(t *testing.T) { p := Clause{} 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, nil, 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 := Clause{} 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 TestParseStringMapWithSeparator(t *testing.T) { p := Clause{} v := p.StringMap(Separator(";")) p.value.Set("a:b") p.value.Set("b:c;c:d") assert.Equal(t, map[string]string{"a": "b", "b": "c", "c": "d"}, *v) } func TestParseURL(t *testing.T) { p := Clause{} 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 := Clause{} 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 TestFloat32(t *testing.T) { p := Clause{} v := p.Float32() err := p.value.Set("123.45") assert.NoError(t, err) assert.InEpsilon(t, 123.45, *v, 0.001) } func TestUnicodeShortFlag(t *testing.T) { app := newTestApp() f := app.Flag("long", "").Short('ä').Bool() _, err := app.Parse([]string{"-ä"}) assert.NoError(t, err) assert.True(t, *f) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/cmd.go000066400000000000000000000174361324515047600237450ustar00rootroot00000000000000package kingpin import ( "errors" "strings" ) type cmdMixin struct { actionMixin *flagGroup *argGroup *cmdGroup } // 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 { case el.OneOf.Arg != nil: if el.Value != nil && *el.Value != "" { argsSatisfied++ } case el.OneOf.Cmd != nil: options = append(options, el.OneOf.Cmd.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) 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 TError("default subcommand {{.Arg0}} provided but no subcommands defined", V{"Arg0": c.defaultSubcommand().name}) } defaults := []string{} for _, cmd := range c.commandOrder { if cmd.isDefault { defaults = append(defaults, cmd.name) } if seen[cmd.name] { return TError("duplicate command {{.Arg0}}", V{"Arg0": cmd.name}) } seen[cmd.name] = true for _, alias := range cmd.aliases { if seen[alias] { return TError("alias duplicates existing command {{.Arg0}}", V{"Arg0": alias}) } c.commands[alias] = cmd } if err := cmd.init(); err != nil { return err } } if len(defaults) > 1 { return TError("more than one default subcommand exists: {{.Arg0}}", V{"Arg0": 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 optionalSubcommands bool } 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 } // Struct allows applications to define flags with struct tags. // // Supported struct tags are: help, placeholder, default, short, long, required, hidden, env, // enum, and arg. // // The name of the flag will default to the CamelCase name transformed to camel-case. This can // be overridden with the "long" tag. // // All basic Go types are supported including floats, ints, strings, time.Duration, // and slices of same. // // For compatibility, also supports the tags used by https://github.com/jessevdk/go-flags func (c *CmdClause) Struct(v interface{}) error { return c.fromStruct(c, v) } // 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 } // FullCommand returns the fully qualified "path" to this command, // including interspersed argument placeholders. Does not include trailing // argument placeholders. // // eg. "signup " func (c *CmdClause) FullCommand() string { return strings.Join(c.fullCommand(), " ") } func (c *CmdClause) fullCommand() (out []string) { out = append(out, c.name) for _, arg := range c.args { text := "<" + arg.name + ">" if _, ok := arg.value.(cumulativeValue); ok { text += " ..." } if !arg.required { text = "[" + text + "]" } out = append(out, text) } if c.parent != nil { out = append(c.parent.fullCommand(), out...) } return } // Command adds a new sub-command. func (c *CmdClause) Command(name, help string) *CmdClause { cmd := c.addCommand(name, help) cmd.parent = c return cmd } // OptionalSubcommands makes subcommands optional func (c *CmdClause) OptionalSubcommands() *CmdClause { c.optionalSubcommands = true return c } // 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 *cmdMixin) checkArgCommandMixing() error { if c.argGroup.have() && c.cmdGroup.have() { for _, arg := range c.args { if arg.consumesRemainder() { return errors.New("cannot mix cumulative Arg() with Command()s") } if !arg.required { return errors.New("Arg()s mixed with Command()s MUST be required") } } } return nil } func (c *CmdClause) init() error { if err := c.flagGroup.init(); err != nil { return err } if err := c.checkArgCommandMixing(); err != nil { return err } if err := c.argGroup.init(); err != nil { return err } return c.cmdGroup.init() } func (c *CmdClause) Hidden() *CmdClause { c.hidden = true return c } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/cmd/000077500000000000000000000000001324515047600234035ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/cmd/embedi18n/000077500000000000000000000000001324515047600251575ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/cmd/embedi18n/main.go000066400000000000000000000013741324515047600264370ustar00rootroot00000000000000package main import ( "bytes" "compress/gzip" "fmt" "io/ioutil" "os" "strings" ) func compress(data []byte) []byte { w := bytes.NewBuffer(nil) gw, err := gzip.NewWriterLevel(w, gzip.BestCompression) if err != nil { panic(err) } _, err = gw.Write(data) if err != nil { panic(err) } gw.Close() return w.Bytes() } func main() { name := os.Args[1] r, err := os.Open("i18n/" + name + ".all.json") if err != nil { panic(err) } defer r.Close() data, err := ioutil.ReadAll(r) if err != nil { panic(err) } data = compress(data) id := strings.Replace(name, "-", "_", -1) w, err := os.Create("i18n_" + id + ".go") if err != nil { panic(err) } defer w.Close() fmt.Fprintf(w, `package kingpin var i18n_%s = []byte(%q) `, id, data) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/cmd/genvalues/000077500000000000000000000000001324515047600253745ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/cmd/genvalues/main.go000066400000000000000000000054461324515047600266600ustar00rootroot00000000000000package main import ( "encoding/json" "os" "os/exec" "strings" "text/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 *Clause) {{.|Name}}() (target *{{.Type}}) { target = new({{.Type}}) p.{{.|Name}}Var(target) return } func (p *Clause) {{.|Name}}Var(target *{{.Type}}) { p.SetValue(new{{.|Name}}Value(target)) } {{end}} {{if not .NoPlural}} // {{.|Plural}} accumulates {{.Type}} values into a slice. func (p *Clause) {{.|Plural}}(options...AccumulatorOption) (target *[]{{.Type}}) { target = new([]{{.Type}}) p.{{.|Plural}}Var(target, options...) return } func (p *Clause) {{.|Plural}}Var(target *[]{{.Type}}, options...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return new{{.|Name}}Value(v.(*{{.Type}})) })) } {{end}} {{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"` NoPlural bool `json:"no_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.v3-3.0~git20180227.b8d601d/cmd_test.go000066400000000000000000000273721324515047600250040ustar00rootroot00000000000000package 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, nil) 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, nil) 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.Fields("a b --aaa x -b x"), false, nil) 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.Fields("a aa --aflag --aaflag"), false, nil) 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.Fields("a aa hello --aflag --aaflag"), false, nil) 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")) } func TestCannotMixOptionalArgWithCommand(t *testing.T) { app := newTestApp() app.Arg("arg", "").String() app.Command("cmd", "") _, err := app.Parse([]string{}) assert.Error(t, err) } func TestMixArgWithCommand(t *testing.T) { app := newTestApp() arg0 := app.Arg("arg0", "").Required().String() arg1 := app.Arg("arg1", "").Required().String() cmd := app.Command("cmd", "") arg2 := cmd.Arg("arg2", "").Required().String() _, err := app.Parse([]string{"a", "b", "cmd"}) assert.Error(t, err) selected, err := app.Parse([]string{"a", "b", "cmd", "c"}) assert.NoError(t, err) assert.Equal(t, "a", *arg0) assert.Equal(t, "b", *arg1) assert.Equal(t, "cmd", selected) assert.Equal(t, "c", *arg2) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/completions.go000066400000000000000000000016101324515047600255210ustar00rootroot00000000000000package 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.v3-3.0~git20180227.b8d601d/completions_test.go000066400000000000000000000033511324515047600265640ustar00rootroot00000000000000package 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.v3-3.0~git20180227.b8d601d/doc.go000066400000000000000000000037421324515047600237420ustar00rootroot00000000000000// 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.v1" // // 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.v3-3.0~git20180227.b8d601d/examples_test.go000066400000000000000000000020701324515047600260430ustar00rootroot00000000000000package 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 *Clause) (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.v3-3.0~git20180227.b8d601d/flags.go000066400000000000000000000061071324515047600242670ustar00rootroot00000000000000package kingpin import "strings" type flagGroup struct { short map[string]*Clause long map[string]*Clause flagOrder []*Clause } func newFlagGroup() *flagGroup { return &flagGroup{ short: map[string]*Clause{}, long: map[string]*Clause{}, } } // 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) *Clause { return f.long[name] } // Flag defines a new flag with the given long name and help. func (f *flagGroup) Flag(name, help string) *Clause { flag := NewClause(name, help) f.long[name] = flag f.flagOrder = append(f.flagOrder, flag) return flag } func (f *flagGroup) init() error { if err := f.checkDuplicates(); err != nil { return err } for _, flag := range f.long { 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 TError("duplicate short flag -{{.Arg0}}", V{"Arg0": flag.shorthand}) } seenShort[flag.shorthand] = true } if _, ok := seenLong[flag.name]; ok { return TError("duplicate long flag --{{.Arg0}}", V{"Arg0": flag.name}) } seenLong[flag.name] = true } return nil } func (f *flagGroup) parse(context *ParseContext) (*Clause, error) { var token *Token loop: for { token = context.Peek() switch token.Type { case TokenEOL: break loop case TokenLong, TokenShort: flagToken := token var flag *Clause 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] // Found an inverted flag. Check if the flag supports it. if ok { bf, bok := flag.value.(BoolFlag) ok = bok && bf.BoolFlagIsNegatable() } } } else if strings.HasPrefix(name, "no-") { invert = true } if !ok { return nil, TError("unknown long flag '{{.Arg0}}'", V{"Arg0": flagToken}) } } else { flag, ok = f.short[name] if !ok { return nil, TError("unknown short flag '{{.Arg0}}'", V{"Arg0": flagToken}) } } context.Next() var defaultValue string if isBoolFlag(flag.value) { if invert { defaultValue = "false" } else { defaultValue = "true" } } else { if invert { context.Push(token) return nil, TError("unknown long flag '{{.Arg0}}'", V{"Arg0": flagToken}) } token = context.Peek() if token.Type != TokenArg { context.Push(token) return nil, TError("expected argument for flag '{{.Arg0}}'", V{"Arg0": flagToken}) } context.Next() defaultValue = token.Value } context.matchedFlag(flag, defaultValue) return flag, nil default: break loop } } return nil, nil } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/flags_test.go000066400000000000000000000214271324515047600253300ustar00rootroot00000000000000package kingpin import ( "bytes" "os" "testing" "github.com/stretchr/testify/assert" ) 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 TestNegatableBool(t *testing.T) { app := newTestApp() f := app.Flag("b", "").Default("true") b := f.NegatableBool() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.True(t, *b) _, err = app.Parse([]string{"--no-b"}) assert.NoError(t, err) assert.False(t, *b) } func TestNegateNonBool(t *testing.T) { app := newTestApp() f := app.Flag("b", "") f.Int() _, err := app.Parse([]string{"--no-b"}) assert.Error(t, err) } func TestNegativePrefixLongFlag(t *testing.T) { app := newTestApp() f := app.Flag("no-comment", "") b := f.Bool() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.False(t, *b) _, err = app.Parse([]string{"--no-comment"}) assert.NoError(t, err) assert.False(t, *b) } func TestNonNegatableBoolFlagCanNotBeNegated(t *testing.T) { app := newTestApp() nonNegatable := app.Flag("nonneg", "").Bool() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.False(t, *nonNegatable) _, err = app.Parse([]string{"--nonneg"}) assert.NoError(t, err) assert.True(t, *nonNegatable) _, err = app.Parse([]string{"--no-nonneg"}) assert.Error(t, err) } func TestHelpForBoolFlags(t *testing.T) { app := newTestApp() app.Flag("yes", "").Default("true").NegatableBool() app.Flag("no", "").Default("false").NegatableBool() app.Flag("nonneg", "").Bool() w := bytes.NewBuffer(nil) app.Writers(w, w).Usage(nil) assert.Contains(t, w.String(), "--[no-]yes") assert.Contains(t, w.String(), "--[no-]no") assert.Contains(t, w.String(), "--nonneg") } 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().Version("0.0.0") 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) // This will error because the Terminate() function doesn't actually terminate. _, _ = 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 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 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 TestEmptyShortFlagIsAnError(t *testing.T) { _, err := newTestApp().Parse([]string{"-"}) assert.Error(t, err) } func TestRequiredWithEnvarMissingErrors(t *testing.T) { app := newTestApp() app.Flag("t", "").Envar("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:456") _, 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.v3-3.0~git20180227.b8d601d/global.go000066400000000000000000000052151324515047600244320ustar00rootroot00000000000000package kingpin import ( "os" "path/filepath" ) var ( // CommandLine is the default Kingpin parser. CommandLine = New(filepath.Base(os.Args[0]), "") ) // 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) *Clause { return CommandLine.Flag(name, help) } // Arg adds a new argument to the top-level of the default parser. func Arg(name, help string) *Clause { return CommandLine.Arg(name, help) } // Struct creates a command-line from a struct. func Struct(v interface{}) *Application { err := CommandLine.Struct(v) FatalIfError(err, "") return CommandLine } // 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:]) } // UsageTemplate associates a template with a flag. The flag must be a Bool() and must // already be defined. 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(T("{{.Arg0}}, try --help", V{"Arg0": 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.v3-3.0~git20180227.b8d601d/guesswidth.go000066400000000000000000000002271324515047600253560ustar00rootroot00000000000000// +build appengine !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd package kingpin import "io" func guessWidth(w io.Writer) int { return 80 } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/guesswidth_unix.go000066400000000000000000000013301324515047600264150ustar00rootroot00000000000000// +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.v3-3.0~git20180227.b8d601d/i18n/000077500000000000000000000000001324515047600234175ustar00rootroot00000000000000golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n/README.md000066400000000000000000000012521324515047600246760ustar00rootroot00000000000000# Internationalisation for Kingpin Kingpin uses [go-1i8n](https://github.com/nicksnyder/go-i18n) to provide internationalisation. ## Adding a language 1. Follow the go-18n instructions [here](https://github.com/nicksnyder/go-i18n#workflow) to add a new language. 2. Once translated, place the `.all.json` file in this directory. 3. Edit `kingpin/i18n_init.go`: 1. Add a new `//go:generate` line for your language. 2. Add a new `i18n.ParseTranslationFileBytes()` entry to `initI18N()`, for your language. 4. Run `go generate -x .` from the top-level kingpin directory. 5. Add a test to `kingpin/i18n_init_test.go`. Note that templates are not currently translated. golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n/en-AU.all.json000066400000000000000000000133041324515047600257670ustar00rootroot00000000000000[ { "id": "'{{.Arg0}}' is a directory", "translation": "'{{.Arg0}}' is a directory" }, { "id": "'{{.Arg0}}' is a file", "translation": "'{{.Arg0}}' is a file" }, { "id": ": error: ", "translation": ": error: " }, { "id": "\u003cEOL\u003e", "translation": "\u003cEOL\u003e" }, { "id": "\u003cnil\u003e", "translation": "\u003cnil\u003e" }, { "id": "Args() can't be followed by another argument '{{.Arg0}}'", "translation": "Args() can't be followed by another argument '{{.Arg0}}'" }, { "id": "Generate a man page.", "translation": "Generate a man page." }, { "id": "Generate completion script for ZSH.", "translation": "Generate completion script for ZSH." }, { "id": "Generate completion script for bash.", "translation": "Generate completion script for bash." }, { "id": "Generate long help.", "translation": "Generate long help." }, { "id": "Output possible completions for the given args.", "translation": "Output possible completions for the given args." }, { "id": "Show application version.", "translation": "Show application version." }, { "id": "Show context-sensitive help.", "translation": "Show context-sensitive help." }, { "id": "Show help on command.", "translation": "Show help on command." }, { "id": "Show help.", "translation": "Show help." }, { "id": "[\u003cflags\u003e]", "translation": "[\u003cflags\u003e]" }, { "id": "alias duplicates existing command {{.Arg0}}", "translation": "alias duplicates existing command {{.Arg0}}" }, { "id": "argument", "translation": "argument" }, { "id": "can't mix Arg()s with Command()s", "translation": "can't mix Arg()s with Command()s" }, { "id": "can't mix top-level Arg()s with Command()s", "translation": "can't mix top-level Arg()s with Command()s" }, { "id": "command not specified", "translation": "command not specified" }, { "id": "default subcommand {{.Arg0}} provided but no subcommands defined", "translation": "default subcommand {{.Arg0}} provided but no subcommands defined" }, { "id": "duplicate argument '{{.Arg0}}'", "translation": "duplicate argument '{{.Arg0}}'" }, { "id": "duplicate command {{.Arg0}}", "translation": "duplicate command {{.Arg0}}" }, { "id": "duplicate long flag --{{.Arg0}}", "translation": "duplicate long flag --{{.Arg0}}" }, { "id": "duplicate short flag -{{.Arg0}}", "translation": "duplicate short flag -{{.Arg0}}" }, { "id": "enum value must be one of {{.Arg0}}, got '{{.Arg1}}'", "translation": "enum value must be one of {{.Arg0}}, got '{{.Arg1}}'" }, { "id": "error", "translation": "error" }, { "id": "error: ", "translation": "error: " }, { "id": "expected KEY=VALUE got '{{.Arg0}}'", "translation": "expected KEY=VALUE got '{{.Arg0}}'" }, { "id": "expected argument for flag '{{.Arg0}}'", "translation": "expected argument for flag '{{.Arg0}}'" }, { "id": "expected command but got {{.Arg0}}", "translation": "expected command but got {{.Arg0}}" }, { "id": "flag '{{.Arg0}}' cannot be repeated", "translation": "flag '{{.Arg0}}' cannot be repeated" }, { "id": "invalid URL: {{.Arg0}}", "translation": "invalid URL: {{.Arg0}}" }, { "id": "invalid default for '--{{.Arg0}}', expecting single value", "translation": "invalid default for '--{{.Arg0}}', expecting single value" }, { "id": "invalid default value '{{.Arg0}}' for argument '{{.Arg1}}'", "translation": "invalid default value '{{.Arg0}}' for argument '{{.Arg1}}'" }, { "id": "long flag", "translation": "long flag" }, { "id": "more than one default subcommand exists: {{.Arg0}}", "translation": "more than one default subcommand exists: {{.Arg0}}" }, { "id": "must select a subcommand of '{{.Arg0}}'", "translation": "must select a subcommand of '{{.Arg0}}'" }, { "id": "no type defined for --{{.Arg0}} (eg. .String())", "translation": "no type defined for --{{.Arg0}} (eg. .String())" }, { "id": "path '{{.Arg0}}' does not exist", "translation": "path '{{.Arg0}}' does not exist" }, { "id": "required argument '{{.Arg0}}' not provided", "translation": "required argument '{{.Arg0}}' not provided" }, { "id": "required arguments found after non-required", "translation": "required arguments found after non-required" }, { "id": "required flag '--{{.Arg0}}' with default value that will never be used", "translation": "required flag '--{{.Arg0}}' with default value that will never be used" }, { "id": "required flag --{{.Arg0}} not provided", "translation": "required flag --{{.Arg0}} not provided" }, { "id": "short flag", "translation": "short flag" }, { "id": "unexpected argument '{{.Arg0}}'", "translation": "unexpected argument '{{.Arg0}}'" }, { "id": "unexpected '{{.Arg0}}'", "translation": "unexpected '{{.Arg0}}'" }, { "id": "unknown", "translation": "unknown" }, { "id": "unknown long flag '{{.Arg0}}'", "translation": "unknown long flag '{{.Arg0}}'" }, { "id": "unknown short flag '{{.Arg0}}'", "translation": "unknown short flag '{{.Arg0}}'" }, { "id": "{{.Arg0}}, try --help", "translation": "{{.Arg0}}, try --help" }, { "id": "usage:", "translation": "usage:" }, { "id": "Flags:", "translation": "Flags:" }, { "id": "Args:", "translation": "Args:" }, { "id": "Commands:", "translation": "Commands:" }, { "id": "Subcommands:", "translation": "Subcommands:" } ] golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n/fr.all.json000066400000000000000000000007511324515047600254730ustar00rootroot00000000000000[ { "id": "Show context-sensitive help.", "translation": "Afficher l'aide contextuelle." }, { "id": "usage:", "translation": "usage:" }, { "id": "Flags:", "translation": "Drapeaux:" }, { "id": "Args:", "translation": "Arguments:" }, { "id": "Commands:", "translation": "Commandes:" }, { "id": "Subcommands:", "translation": "Sous-commandes:" }, { "id": "Show help.", "translation": "Afficher l'aide." } ] golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n_en_AU.go000066400000000000000000000051641324515047600250230ustar00rootroot00000000000000package kingpin var i18n_en_AU = []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x02\xff\xa4XOk+7\x10\xbf\xfbS\f\xb9؆8\xa4\xf4f\xe8!\x94\xb4\x85\x06\x1e4\xbcB\xfb\xfa\x0e\xf2\xee쮨,m%\xad\x9d\x10\xf2\u074bv\xfdg\x93\xccHZ\xe7f\xd0\xfc\xfex\xa4\x19\x8d\xf6\xdb\f\xe0e\x06\x00p%˫5\\\xcd_^n\xeel}\xfb\xfa:\a\xe9@@)-\x16\xde\xd8\xe7\xab\xeb!\xce[\xa1\x9d\x12^\x1a\x9d\x00\xcc\x00^\xaf\x93\x02\x95T\x98\xcb\xddǒ\xb4k@k\x8d]\x03Cu^'\xe1\xfft\xb7\xb7?\x16\xf7_\x1e\xfa\x1f\x9c\x9f\xf7Q\x11*-U\x06\xd59\x8a\xa4\xba\xb3\xb5[,\xa1\x10z\xeea\x83P\x19\xa5\xcc\x1eK\xd8<\x83\xd0\xc67hAغۢ\xf60J\x16\xa3y1\x1di\xeeW\xd4h\x85G\x10\xb0\x15\x1aZQ\xe3\r#L\x86\xc6I\v\xb3m\x15\x06\x02p\x85\x95\xad\x87\xcaX\xf8\xfb\xf1\xb7\xa4F\x04y\x89\xe4F\xb8\xe6B\xcd\x01\x1a\x17UF\xd7Рj\x93\x1a\xa3H\x92\xf2K\xe7\xdb\xceCk\x9c\x93\x1b5\xf6\xe4z7\xbeA\xa8\xe5\x0eu\xd8c\xc7\xc9Me!\xad<6f\x0f\xa2m\x95,zbءu\xd2hN\x94\x8f\xe7\xe9\v\xa3=>\xf9\x95C\xed\xa4\x97;\x8cf1\n\xe1E\xc2:\x18\x1d\xb2\xb0\x15\xba\x8c\xb2\u007f\x88\x8d\xd3&\xb9\x18\x82oC稔\xa8\xdd\xd0;\xbe3LT$I)\x94\x14\x0e\xcan\xc8?:\xc0'\xe9\xbc\xd4\xf5\xf1\xbf\xc0\xa9\x170RS\x18h\v\x87\xb6\xc3\xf1\x1f\x97I\xf0\xd0ж\xf2\t\xeel\xbdX:\xd8K\xdf\xc0σ\xf2b\xe9\x18\xd2$,!\xe6M\xbbR\xb8Cu\xa9l\x92\x806pȨ6\x1e\\\x8b\x85\xac$\x96\x9c\x16\x19KҖX\x89Nyp\xdd\xe6ÞAk\xcdN\x96\xe1\xa6\xe8G\x9ea||̦l\\\x1cL\n\x9f\xe7!\x86|\x14@\x12t\xfa㕛\xae\xef\x14*%5I!\x83\xf8_m\xf6\x9ae\x1aVc\xd0\xd1\b\x9bc-\x86\x89ʌ\xc6\xd7|\x1d\x06D\n\x8d\xe6Qo\x9fa\xb5\n\xefx\x86\x9f\x8e\xa5\xfd;Q\xe3\x9a\xf39,\x92\xc0_\xc2ӟ\x03\x1e\x16\xd9\x0f\x8f\xeb\xc8WD\x06vx\xba\xb2\xd0\xf3:\xfdm\xe4\xfc\xfc\xe3\x18ބ\x04\x92\xd9\xf7\xd9\xff\x01\x00\x00\xff\xffrWY\x98\xc4\x16\x00\x00") golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n_fr.go000066400000000000000000000010701324515047600244330ustar00rootroot00000000000000package kingpin var i18n_fr = []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x02\xff\x94\xd1A\xaa\x830\x10\x06\xe0}N1d\xf36\xea\x01\xdc\xc9{\xbc\v\xb8,]L㨁\x98H&i\x85һ\x17\xd1nJ\a\xe9\xfa\xcf\xf7\a\xe6?)\x80\xbb\x02\x00ж\xd35\xe8v\f70\xc1'ZR\xc9\xe4\xd9&{%\x18\xc9͕.\xb6\x97)\xa2g\x87\xc9\x06\xbf\x92\xa6\xef\xad\x19)\x82\xfbA\xdb\xd1Kgr\x8e*\xad\x00\x1e\xc5\xfb/\x99q\xa0Z\xe8\xdbÏ\xf0\xdf\xe1\xc0\x12\xfc\x8b8\x13\xe6E\xb0M\x94i\x13\x87<\x91O,\xd8\xdf0M\xe8;\xd1\xef9I\xbe\xcd\x17sPц̥9\xeaY\xe7\xf9b\x8c\xed\xfe\uab1e\x01\x00\x00\xff\xff\x1esa\xbf\xe9\x01\x00\x00") golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n_init.go000066400000000000000000000033561324515047600250000ustar00rootroot00000000000000package kingpin //go:generate go run ./cmd/embedi18n/main.go en-AU //go:generate go run ./cmd/embedi18n/main.go fr import ( "bytes" "compress/gzip" "io/ioutil" "os" "strings" "github.com/nicksnyder/go-i18n/i18n" ) type tError struct { msg string args []interface{} } // TError is an error that translates itself. // // It has the same signature and usage as T(). func TError(msg string, args ...interface{}) error { return &tError{msg: msg, args: args} } func (i *tError) Error() string { return T(i.msg, i.args...) } // T is a translation function. var T = initI18N() func initI18N() i18n.TranslateFunc { // Initialise translations. i18n.ParseTranslationFileBytes("i18n/en-AU.all.json", decompressLang(i18n_en_AU)) i18n.ParseTranslationFileBytes("i18n/fr.all.json", decompressLang(i18n_fr)) // Detect language. lang := detectLang() t, err := i18n.Tfunc(lang, "en") if err != nil { panic(err) } return t } func detectLang() string { lang := os.Getenv("LANG") if lang == "" { return "en" } // Remove encoding spec (eg. ".UTF-8") if idx := strings.Index(lang, "."); idx != -1 { lang = lang[0:idx] } // en_AU -> en-AU return strings.Replace(lang, "_", "-", -1) } func decompressLang(data []byte) []byte { r := bytes.NewReader(data) gr, err := gzip.NewReader(r) if err != nil { panic(err) } out, err := ioutil.ReadAll(gr) if err != nil { panic(err) } return out } // SetLanguage sets the language for Kingpin. func SetLanguage(lang string, others ...string) error { t, err := i18n.Tfunc(lang, others...) if err != nil { return err } T = t return nil } // V is a convenience alias for translation function variables. // eg. T("Something {{.Arg0}}", V{"Arg0": "moo"}) type V map[string]interface{} golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/i18n_init_test.go000066400000000000000000000004531324515047600260320ustar00rootroot00000000000000package kingpin import ( "github.com/nicksnyder/go-i18n/i18n" "github.com/stretchr/testify/require" "testing" ) func TestI18N_fr(t *testing.T) { f, err := i18n.Tfunc("fr") require.NoError(t, err) require.Equal(t, "Afficher l'aide contextuelle.", f("Show context-sensitive help."), ) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/model.go000066400000000000000000000140721324515047600242730ustar00rootroot00000000000000// nolint: golint package kingpin import ( "fmt" "strconv" "strings" ) // Data model for Kingpin command-line structure. type FlagGroupModel struct { Flags []*ClauseModel } func (f *FlagGroupModel) FlagByName(name string) *ClauseModel { for _, flag := range f.Flags { if flag.Name == name { return flag } } return nil } 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() { if flag.IsNegatable() { out = append(out, fmt.Sprintf("--[no-]%s", flag.Name)) } else { out = append(out, fmt.Sprintf("--%s", flag.Name)) } } else { out = append(out, fmt.Sprintf("--%s=%s", flag.Name, flag.FormatPlaceHolder())) } } } if count != len(out) { out = append(out, T("[]")) } return strings.Join(out, " ") } type ClauseModel struct { Name string Help string Short rune Default []string PlaceHolder string Required bool Hidden bool Value Value Cumulative bool } func (c *ClauseModel) String() string { return c.Value.String() } func (c *ClauseModel) IsBoolFlag() bool { return isBoolFlag(c.Value) } func (c *ClauseModel) IsNegatable() bool { bf, ok := c.Value.(BoolFlag) return ok && bf.BoolFlagIsNegatable() } func (c *ClauseModel) FormatPlaceHolder() string { if c.PlaceHolder != "" { return c.PlaceHolder } if len(c.Default) > 0 { ellipsis := "" if len(c.Default) > 1 { ellipsis = "..." } if _, ok := c.Value.(*stringValue); ok { return strconv.Quote(c.Default[0]) + ellipsis } return c.Default[0] + ellipsis } return strings.ToUpper(c.Name) } type ArgGroupModel struct { Args []*ClauseModel } func (a *ArgGroupModel) ArgSummary() string { depth := 0 out := []string{} for _, arg := range a.Args { h := "<" + arg.Name + ">" if arg.Cumulative { h += " ..." } if !arg.Required { h = "[" + h depth++ } out = append(out, h) } if len(out) == 0 { return "" } out[len(out)-1] = out[len(out)-1] + strings.Repeat("]", depth) return strings.Join(out, " ") } type CmdGroupModel struct { Commands []*CmdModel } func (c *CmdGroupModel) FlattenedCommands() (out []*CmdModel) { for _, cmd := range c.Commands { if cmd.OptionalSubcommands { out = append(out, cmd) } if len(cmd.Commands) == 0 { out = append(out, cmd) } out = append(out, cmd.FlattenedCommands()...) } return } type CmdModel struct { Name string Aliases []string Help string Depth int Hidden bool Default bool OptionalSubcommands bool Parent *CmdModel *FlagGroupModel *ArgGroupModel *CmdGroupModel } func (c *CmdModel) String() string { return c.CmdSummary() } func (c *CmdModel) CmdSummary() string { out := []string{} for cursor := c; cursor != nil; cursor = cursor.Parent { text := cursor.Name if cursor.Default { text = "*" + text } if flags := cursor.FlagSummary(); flags != "" { text += " " + flags } if args := cursor.ArgSummary(); args != "" { text += " " + args } out = append([]string{text}, out...) } return strings.Join(out, " ") } // FullCommand is the command path to this node, excluding positional arguments and flags. func (c *CmdModel) FullCommand() string { out := []string{} for i := c; i != nil; i = i.Parent { out = append([]string{i.Name}, out...) } return strings.Join(out, " ") } type ApplicationModel struct { Name string Help string Version string Author string *ArgGroupModel *CmdGroupModel *FlagGroupModel } func (a *ApplicationModel) AppSummary() string { summary := a.Name if flags := a.FlagSummary(); flags != "" { summary += " " + flags } if args := a.ArgSummary(); args != "" { summary += " " + args } if len(a.Commands) > 0 { summary += " " } return summary } func (a *ApplicationModel) FindModelForCommand(cmd *CmdClause) *CmdModel { if cmd == nil { return nil } path := []string{} for c := cmd; c != nil; c = c.parent { path = append([]string{c.name}, path...) } var selected *CmdModel cursor := a.CmdGroupModel for _, component := range path { for _, cmd := range cursor.Commands { if cmd.Name == component { selected = cmd cursor = cmd.CmdGroupModel break } } } if selected == nil { panic("this shouldn't happen") } return selected } 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(nil), } } func (a *argGroup) Model() *ArgGroupModel { m := &ArgGroupModel{} for _, arg := range a.args { m.Args = append(m.Args, arg.Model()) } return m } func (f *flagGroup) Model() *FlagGroupModel { m := &FlagGroupModel{} for _, fl := range f.flagOrder { m.Flags = append(m.Flags, fl.Model()) } return m } func (f *Clause) Model() *ClauseModel { _, cumulative := f.value.(cumulativeValue) return &ClauseModel{ Name: f.name, Help: f.help, Short: f.shorthand, Default: f.defaultValues, PlaceHolder: f.placeholder, Required: f.required, Hidden: f.hidden, Value: f.value, Cumulative: cumulative, } } func (c *cmdGroup) Model(parent *CmdModel) *CmdGroupModel { m := &CmdGroupModel{} for _, cm := range c.commandOrder { m.Commands = append(m.Commands, cm.Model(parent)) } return m } func (c *CmdClause) Model(parent *CmdModel) *CmdModel { depth := 0 for i := c; i != nil; i = i.parent { depth++ } cmd := &CmdModel{ Name: c.name, Parent: parent, Aliases: c.aliases, Help: c.help, Depth: depth, Hidden: c.hidden, Default: c.isDefault, OptionalSubcommands: c.optionalSubcommands, FlagGroupModel: c.flagGroup.Model(), ArgGroupModel: c.argGroup.Model(), } cmd.CmdGroupModel = c.cmdGroup.Model(cmd) return cmd } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/model_test.go000066400000000000000000000021241324515047600253250ustar00rootroot00000000000000package kingpin import ( "github.com/stretchr/testify/assert" "testing" ) func TestFindModel(t *testing.T) { app := newTestApp() cmd := app.Command("cmd", "").Command("cmd2", "") model := app.Model() cmdModel := model.FindModelForCommand(cmd) assert.NotNil(t, cmdModel) assert.Equal(t, "cmd2", cmdModel.Name) } func TestFullCommand(t *testing.T) { app := newTestApp() cmd := app.Command("cmd", "").Command("cmd2", "") model := app.Model() cmdModel := model.FindModelForCommand(cmd) assert.Equal(t, "cmd cmd2", cmdModel.FullCommand()) } func TestCmdSummary(t *testing.T) { app := newTestApp() cmd := app.Command("cmd", "") cmd.Flag("flag", "").Required().String() cmd = cmd.Command("cmd2", "") cmd.Arg("arg", "").Required().String() model := app.Model() cmdModel := model.FindModelForCommand(cmd) assert.Equal(t, "cmd --flag=FLAG cmd2 ", cmdModel.CmdSummary()) } func TestModelValue(t *testing.T) { app := newTestApp() value := app.Flag("test", "").Bool() *value = true model := app.Model() flag := model.FlagByName("test") assert.Equal(t, "true", flag.Value.String()) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/parser.go000066400000000000000000000232721324515047600244710ustar00rootroot00000000000000package kingpin import ( "bufio" "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 T("short flag") case TokenLong: return T("long flag") case TokenArg: return T("argument") case TokenError: return T("error") case TokenEOL: return T("") } return T("unknown") } 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 T("error: ") + t.Value case TokenEOL: return T("") default: panic("unhandled type") } } type OneOfClause struct { Flag *Clause Arg *Clause Cmd *CmdClause } // A ParseElement represents the parsers view of each element in the command-line argument slice. type ParseElement struct { // Clause associated with this element. Exactly one of these will be present. OneOf OneOfClause // Value is corresponding value for an argument or flag. For commands this value will be nil. Value *string } // ParseElements represents each element in the command-line argument slice. type ParseElements []*ParseElement // FlagMap collects all parsed flags into a map keyed by long name. func (p ParseElements) FlagMap() map[string]*ParseElement { // Collect flags into maps. flags := map[string]*ParseElement{} for _, element := range p { if element.OneOf.Flag != nil { flags[element.OneOf.Flag.name] = element } } return flags } // ArgMap collects all parsed positional arguments into a map keyed by long name. func (p ParseElements) ArgMap() map[string]*ParseElement { flags := map[string]*ParseElement{} for _, element := range p { if element.OneOf.Arg != nil { flags[element.OneOf.Arg.name] = element } } return flags } // 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 { Application *Application // May be nil in tests. SelectedCommand *CmdClause resolvers []Resolver 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 ParseElements } func (p *ParseContext) CombinedFlagsAndArgs() []*Clause { return append(p.Args(), p.Flags()...) } func (p *ParseContext) Args() []*Clause { return p.arguments.args } func (p *ParseContext) Flags() []*Clause { return p.flags.flagOrder } // LastCmd returns true if the element is the last (sub)command being evaluated. func (p *ParseContext) LastCmd(element *ParseElement) bool { lastCmdIndex := -1 eIndex := -2 for i, e := range p.Elements { if element == e { eIndex = i } if e.OneOf.Cmd != nil { lastCmdIndex = i } } return lastCmdIndex == eIndex } func (p *ParseContext) nextArg() *Clause { 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, resolvers []Resolver) *ParseContext { return &ParseContext{ ignoreDefault: ignoreDefault, args: args, rawArgs: args, flags: newFlagGroup(), arguments: newArgGroup(), resolvers: resolvers, } } 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) { p.arguments.args = append(p.arguments.args, args.args...) } func (p *ParseContext) EOL() bool { return p.Peek().Type == TokenEOL } // 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} } rn, size := utf8.DecodeRuneInString(arg[1:]) short := string(rn) flag, ok := p.flags.short[short] // Not a known short flag, we'll just return it anyway. if !ok { } else if isBoolFlag(flag.value) { // Bool short flag. } else { // Short flag with combined argument: -fARG token := &Token{p.argi, TokenShort, short} if len(arg) > 2 { p.Push(&Token{p.argi, TokenArg, arg[1+size:]}) } return token } if len(arg) > 1+size { p.args = append([]string{"-" + arg[1+size:]}, p.args...) } return &Token{p.argi, TokenShort, short} } 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 { if p.SelectedCommand == nil { return "" } return p.SelectedCommand.FullCommand() } func (p *ParseContext) matchedFlag(flag *Clause, value string) { p.Elements = append(p.Elements, &ParseElement{OneOf: OneOfClause{Flag: flag}, Value: &value}) } func (p *ParseContext) matchedArg(arg *Clause, value string) { p.Elements = append(p.Elements, &ParseElement{OneOf: OneOfClause{Arg: arg}, Value: &value}) } func (p *ParseContext) matchedCmd(cmd *CmdClause) { p.Elements = append(p.Elements, &ParseElement{OneOf: OneOfClause{Cmd: 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) { r, err := os.Open(filename) if err != nil { return nil, 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() return } func parse(context *ParseContext, app *Application) (err error) { // nolint: gocyclo context.mergeFlags(app.flagGroup) context.mergeArgs(app.argGroup) cmds := app.cmdGroup ignoreDefault := context.ignoreDefault loop: for !context.EOL() { 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 == app.helpFlag { ignoreDefault = true } case TokenArg: if context.arguments.have() { if app.noInterspersed { // no more flags context.argsOnly = true } arg := context.nextArg() if arg != nil { context.matchedArg(arg, token.String()) context.Next() continue } } 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 TError("expected command but got {{.Arg0}}", V{"Arg0": token}) } } if cmd == app.helpCommand { ignoreDefault = true } cmd.completionAlts = nil context.matchedCmd(cmd) cmds = cmd.cmdGroup if !selectedDefault { context.Next() } continue } 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.EOL() { return TError("unexpected '{{.Arg0}}'", V{"Arg0": 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 TError("invalid default value '{{.Arg0}}' for argument '{{.Arg1}}'", V{"Arg0": defaultValue, "Arg1": arg.name}) } } } return } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/parser_test.go000066400000000000000000000016101324515047600255200ustar00rootroot00000000000000package kingpin import ( "testing" "github.com/stretchr/testify/assert" ) func cmdElem() *ParseElement { return &ParseElement{ OneOf: OneOfClause{ Cmd: &CmdClause{}, }, } } func TestParseContextPush(t *testing.T) { c := tokenize([]string{"foo", "bar"}, false, nil) 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) } func TestLastCmd(t *testing.T) { e := cmdElem() pc := &ParseContext{ Elements: []*ParseElement{e, cmdElem(), cmdElem()}, } assert.Equal(t, false, pc.LastCmd(e)) pc = &ParseContext{ Elements: []*ParseElement{cmdElem(), e, cmdElem()}, } assert.Equal(t, false, pc.LastCmd(e)) pc = &ParseContext{ Elements: []*ParseElement{cmdElem(), cmdElem(), e}, } assert.Equal(t, true, pc.LastCmd(e)) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/resolver.go000066400000000000000000000105731324515047600250360ustar00rootroot00000000000000package kingpin import ( "encoding/json" "fmt" "os" "regexp" "strings" ) var ( envarTransformRegexp = regexp.MustCompile(`[^a-zA-Z_]+`) ) // A Resolver retrieves flag values from an external source, such as a configuration file or environment variables. type Resolver interface { // Resolve key in the given parse context. // // A nil slice should be returned if the key can not be resolved. Resolve(key string, context *ParseContext) ([]string, error) } // ResolverFunc is a function that is also a Resolver. type ResolverFunc func(key string, context *ParseContext) ([]string, error) func (r ResolverFunc) Resolve(key string, context *ParseContext) ([]string, error) { return r(key, context) } // A resolver that pulls values from the flag defaults. This resolver is always installed in the ParseContext. func defaultsResolver() Resolver { return ResolverFunc(func(key string, context *ParseContext) ([]string, error) { for _, clause := range context.CombinedFlagsAndArgs() { if clause.name == key { return clause.defaultValues, nil } } return nil, nil }) } func parseEnvar(envar, sep string) []string { value, ok := os.LookupEnv(envar) if !ok { return nil } if sep == "" { return []string{value} } return strings.Split(value, sep) } // Resolves a clause value from the envar configured on that clause, if any. func envarResolver(sep string) Resolver { return ResolverFunc(func(key string, context *ParseContext) ([]string, error) { for _, clause := range context.CombinedFlagsAndArgs() { if key == clause.name { if clause.noEnvar || clause.envar == "" { return nil, nil } return parseEnvar(clause.envar, sep), nil } } return nil, nil }) } // MapResolver resolves values from a static map. func MapResolver(values map[string][]string) Resolver { return ResolverFunc(func(key string, context *ParseContext) ([]string, error) { return values[key], nil }) } // JSONResolver returns a Resolver that retrieves values from a JSON source. func JSONResolver(data []byte) (Resolver, error) { values := map[string]interface{}{} err := json.Unmarshal(data, &values) if err != nil { return nil, err } mapping := map[string][]string{} for key, value := range values { sub, err := jsonDecodeValue(value) if err != nil { return nil, err } mapping[key] = sub } return MapResolver(mapping), nil } func jsonDecodeValue(value interface{}) ([]string, error) { switch v := value.(type) { case []interface{}: out := []string{} for _, sv := range v { next, err := jsonDecodeValue(sv) if err != nil { return nil, err } out = append(out, next...) } return out, nil case string: return []string{v}, nil case float64: return []string{fmt.Sprintf("%v", v)}, nil case bool: if v { return []string{"true"}, nil } return []string{"false"}, nil } return nil, fmt.Errorf("unsupported JSON value %v (of type %T)", value, value) } // RenamingResolver creates a resolver for remapping names for a child resolver. // // This is useful if your configuration file uses a naming convention that does not map directly to // flag names. func RenamingResolver(resolver Resolver, rename func(string) string) Resolver { return ResolverFunc(func(key string, context *ParseContext) ([]string, error) { return resolver.Resolve(rename(key), context) }) } // PrefixedEnvarResolver resolves any flag/argument via environment variables. // // "prefix" is the common-prefix for the environment variables. "separator", is the character used to separate // multiple values within a single envar (eg. ";") // // With a prefix of APP_, flags in the form --some-flag will be transformed to APP_SOME_FLAG. func PrefixedEnvarResolver(prefix, separator string) Resolver { return ResolverFunc(func(key string, context *ParseContext) ([]string, error) { key = envarTransform(prefix + key) return parseEnvar(key, separator), nil }) } // DontResolve returns a Resolver that will never return values for the given keys, even if provided. func DontResolve(resolver Resolver, keys ...string) Resolver { disabled := map[string]bool{} for _, key := range keys { disabled[key] = true } return ResolverFunc(func(key string, context *ParseContext) ([]string, error) { if disabled[key] { return nil, nil } return resolver.Resolve(key, context) }) } func envarTransform(name string) string { return strings.ToUpper(envarTransformRegexp.ReplaceAllString(name, "_")) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/resolver_test.go000066400000000000000000000044561324515047600261000ustar00rootroot00000000000000package kingpin import ( "os" "testing" "github.com/stretchr/testify/assert" ) func TestResolverSimple(t *testing.T) { app := newTestApp() app.Resolver(MapResolver(map[string][]string{"hello": []string{"world"}})) f := app.Flag("hello", "help").String() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "world", *f) } func TestResolverSatisfiesRequired(t *testing.T) { app := newTestApp() app.Resolver(MapResolver(map[string][]string{"hello": []string{"world"}})) f := app.Flag("hello", "help").Required().String() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "world", *f) } func TestResolverLowerPriorityThanFlag(t *testing.T) { app := newTestApp() app.Resolver(MapResolver(map[string][]string{"hello": []string{"world"}})) f := app.Flag("hello", "help").String() _, err := app.Parse([]string{"--hello", "there"}) assert.NoError(t, err) assert.Equal(t, "there", *f) } func TestResolverFallbackWithMultipleResolvers(t *testing.T) { app := newTestApp() app.Resolver(MapResolver(map[string][]string{"hello": []string{"there"}, "foo": []string{"bar"}})) app.Resolver(MapResolver(map[string][]string{"hello": []string{"world"}})) f1 := app.Flag("hello", "help").String() f2 := app.Flag("foo", "help").String() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "world", *f1) assert.Equal(t, "bar", *f2) } func TestResolverLowerPriorityThanEnvar(t *testing.T) { os.Setenv("TEST_RESOLVER", "foo") app := newTestApp() app.Resolver(MapResolver(map[string][]string{"hello": []string{"world"}})) f := app.Flag("hello", "help").Envar("TEST_RESOLVER").String() _, err := app.Parse([]string{}) assert.NoError(t, err) assert.Equal(t, "foo", *f) } func TestJSONResolver(t *testing.T) { r, err := JSONResolver([]byte(`{ "str": "string", "num": 1234, "bool": true, "array": ["a", "b"] }`)) assert.NoError(t, err) values, err := r.Resolve("str", nil) assert.NoError(t, err) assert.Equal(t, []string{"string"}, values) values, err = r.Resolve("num", nil) assert.NoError(t, err) assert.Equal(t, []string{"1234"}, values) values, err = r.Resolve("bool", nil) assert.NoError(t, err) assert.Equal(t, []string{"true"}, values) values, err = r.Resolve("array", nil) assert.NoError(t, err) assert.Equal(t, []string{"a", "b"}, values) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/struct.go000066400000000000000000000122141324515047600245130ustar00rootroot00000000000000package kingpin import ( "fmt" "net/url" "reflect" "strings" "time" "unicode/utf8" ) func (c *cmdMixin) fromStruct(clause *CmdClause, v interface{}) error { // nolint: gocyclo urv := reflect.ValueOf(v) rv := reflect.Indirect(reflect.ValueOf(v)) if rv.Kind() != reflect.Struct || !rv.CanSet() { return fmt.Errorf("expected a pointer to a struct but got a " + urv.Type().String()) } for i := 0; i < rv.NumField(); i++ { // Parse out tags field := rv.Field(i) ft := rv.Type().Field(i) if strings.ToLower(ft.Name[0:1]) == ft.Name[0:1] { continue } tag := ft.Tag help := tag.Get("help") if help == "" { help = tag.Get("description") } placeholder := tag.Get("placeholder") if placeholder == "" { placeholder = tag.Get("value-name") } dflt := tag.Get("default") short := tag.Get("short") required := tag.Get("required") hidden := tag.Get("hidden") env := tag.Get("env") enum := tag.Get("enum") name := strings.ToLower(strings.Join(camelCase(ft.Name), "-")) if tag.Get("long") != "" { name = tag.Get("long") } arg := tag.Get("arg") var action Action onMethodName := "On" + strings.ToUpper(ft.Name[0:1]) + ft.Name[1:] if actionMethod := urv.MethodByName(onMethodName); actionMethod.IsValid() { action, _ = actionMethod.Interface().(func(element *ParseElement, context *ParseContext) error) } if field.Kind() == reflect.Struct { if ft.Anonymous { if err := c.fromStruct(clause, field.Addr().Interface()); err != nil { return err } } else { cmd := c.addCommand(name, help) cmd.parent = clause if hidden != "" { cmd = cmd.Hidden() } if err := cmd.Struct(field.Addr().Interface()); err != nil { return err } } continue } // Define flag using extracted tags var clause *Clause if arg != "" { clause = c.Arg(name, help) } else { clause = c.Flag(name, help) } if action != nil { clause.Action(action) } if dflt != "" { clause = clause.Default(dflt) } if short != "" { r, _ := utf8.DecodeRuneInString(short) if r == utf8.RuneError { return fmt.Errorf("invalid short flag %s", short) } clause = clause.Short(r) } if required != "" { clause = clause.Required() } if hidden != "" { clause = clause.Hidden() } if placeholder != "" { clause = clause.PlaceHolder(placeholder) } if env != "" { clause = clause.Envar(env) } ptr := field.Addr().Interface() if ft.Type == reflect.TypeOf(&url.URL{}) { clause.URLVar(ptr.(**url.URL)) } else if ft.Type == reflect.TypeOf(time.Duration(0)) { clause.DurationVar(ptr.(*time.Duration)) } else { switch ft.Type.Kind() { case reflect.String: if enum != "" { clause.EnumVar(ptr.(*string), strings.Split(enum, ",")...) } else { clause.StringVar(ptr.(*string)) } case reflect.Bool: clause.BoolVar(ptr.(*bool)) case reflect.Float32: clause.Float32Var(ptr.(*float32)) case reflect.Float64: clause.Float64Var(ptr.(*float64)) case reflect.Int: clause.IntVar(ptr.(*int)) case reflect.Int8: clause.Int8Var(ptr.(*int8)) case reflect.Int16: clause.Int16Var(ptr.(*int16)) case reflect.Int32: clause.Int32Var(ptr.(*int32)) case reflect.Int64: clause.Int64Var(ptr.(*int64)) case reflect.Uint: clause.UintVar(ptr.(*uint)) case reflect.Uint8: clause.Uint8Var(ptr.(*uint8)) case reflect.Uint16: clause.Uint16Var(ptr.(*uint16)) case reflect.Uint32: clause.Uint32Var(ptr.(*uint32)) case reflect.Uint64: clause.Uint64Var(ptr.(*uint64)) case reflect.Slice: if ft.Type == reflect.TypeOf([]*url.URL{}) { clause.URLListVar(ptr.(*[]*url.URL)) } else if ft.Type == reflect.TypeOf(time.Duration(0)) { clause.DurationListVar(ptr.(*[]time.Duration)) } else { switch ft.Type.Elem().Kind() { case reflect.String: if enum != "" { clause.EnumsVar(field.Addr().Interface().(*[]string), strings.Split(enum, ",")...) } else { clause.StringsVar(field.Addr().Interface().(*[]string)) } case reflect.Bool: clause.BoolListVar(field.Addr().Interface().(*[]bool)) case reflect.Float32: clause.Float32ListVar(ptr.(*[]float32)) case reflect.Float64: clause.Float64ListVar(ptr.(*[]float64)) case reflect.Int: clause.IntsVar(field.Addr().Interface().(*[]int)) case reflect.Int8: clause.Int8ListVar(ptr.(*[]int8)) case reflect.Int16: clause.Int16ListVar(ptr.(*[]int16)) case reflect.Int32: clause.Int32ListVar(ptr.(*[]int32)) case reflect.Int64: clause.Int64ListVar(ptr.(*[]int64)) case reflect.Uint: clause.UintsVar(ptr.(*[]uint)) case reflect.Uint8: clause.HexBytesVar(ptr.(*[]byte)) case reflect.Uint16: clause.Uint16ListVar(ptr.(*[]uint16)) case reflect.Uint32: clause.Uint32ListVar(ptr.(*[]uint32)) case reflect.Uint64: clause.Uint64ListVar(ptr.(*[]uint64)) default: return fmt.Errorf("unsupported field type %s for field %s", ft.Type.String(), ft.Name) } } default: return fmt.Errorf("unsupported field type %s for field %s", ft.Type.String(), ft.Name) } } } return nil } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/struct_test.go000066400000000000000000000073351324515047600255620ustar00rootroot00000000000000package kingpin import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestFlagsInvalidType(t *testing.T) { type MyFlags struct { Debug bool `help:"foo"` } a := newTestApp() err := a.Struct(MyFlags{}) assert.Error(t, err) err = a.Struct(&MyFlags{}) assert.NoError(t, err) } func TestFlagsStruct(t *testing.T) { type MyFlags struct { Debug bool `help:"Enable debug mode."` URL string `help:"URL to connect to." default:"localhost:80"` Names []string `help:"Names of things."` } a := newTestApp() actual := &MyFlags{} err := a.Struct(actual) assert.NoError(t, err) assert.NotNil(t, a.flagGroup.long["debug"]) assert.NotNil(t, a.flagGroup.long["url"]) *actual = MyFlags{} a.Parse([]string{}) assert.Equal(t, &MyFlags{URL: "localhost:80"}, actual) *actual = MyFlags{} a.Parse([]string{"--debug"}) assert.Equal(t, &MyFlags{Debug: true, URL: "localhost:80"}, actual) *actual = MyFlags{} a.Parse([]string{"--url=w3.org"}) assert.Equal(t, &MyFlags{URL: "w3.org"}, actual) *actual = MyFlags{} a.Parse([]string{"--names=alec", "--names=bob"}) assert.Equal(t, &MyFlags{URL: "localhost:80", Names: []string{"alec", "bob"}}, actual) type RequiredFlag struct { Flag bool `help:"A flag." required:"true"` } a = newTestApp() rflags := &RequiredFlag{} err = a.Struct(rflags) assert.NoError(t, err) _, err = a.Parse([]string{}) assert.Error(t, err) _, err = a.Parse([]string{"--flag"}) assert.NoError(t, err) assert.Equal(t, &RequiredFlag{Flag: true}, rflags) type DurationFlag struct { Elapsed time.Duration `help:"Elapsed time."` } a = newTestApp() dflag := &DurationFlag{} err = a.Struct(dflag) assert.NoError(t, err) _, err = a.Parse([]string{"--elapsed=5s"}) assert.NoError(t, err) assert.Equal(t, 5*time.Second, dflag.Elapsed) } func TestNestedStruct(t *testing.T) { type NestedFlags struct { URL string `help:"URL to connect to." default:"localhost:80"` } type MyFlags struct { NestedFlags Debug bool `help:"Enable debug mode"` } a := newTestApp() actual := &MyFlags{} err := a.Struct(actual) assert.NoError(t, err) assert.NotNil(t, a.GetFlag("debug")) assert.NotNil(t, a.GetFlag("url")) _, err = a.Parse([]string{"--debug", "--url=foobar"}) assert.NoError(t, err) assert.True(t, actual.Debug) assert.Equal(t, "foobar", actual.URL) } func TestStructHierarchy(t *testing.T) { type App struct { Login struct { Username string `arg:"true" required:"true"` } Debug bool } a := newTestApp() actual := &App{} err := a.Struct(actual) assert.NoError(t, err) expected := &App{ Login: struct { Username string `arg:"true" required:"true"` }{ Username: "alec", }, Debug: true, } _, err = a.Parse([]string{"--debug", "login", "alec"}) assert.NoError(t, err) assert.Equal(t, expected, actual) } func TestStructEnum(t *testing.T) { type App struct { Enum string `enum:"one,two"` Enums []string `enum:"one,two"` } actual := &App{} a := newTestApp() a.Struct(actual) _, err := a.Parse([]string{"--enum=three"}) assert.Error(t, err) _, err = a.Parse([]string{"--enums=three"}) assert.Error(t, err) _, err = a.Parse([]string{"--enum=one", "--enums=one", "--enums=two"}) assert.NoError(t, err) assert.Equal(t, &App{Enum: "one", Enums: []string{"one", "two"}}, actual) } type onActionStructTest struct { Debug bool called int } func (o *onActionStructTest) OnDebug(element *ParseElement, context *ParseContext) error { o.called++ return nil } func TestStructOnAction(t *testing.T) { actual := &onActionStructTest{} var _ Action = actual.OnDebug a := newTestApp() err := a.Struct(actual) assert.NoError(t, err) _, err = a.Parse([]string{"--debug"}) assert.NoError(t, err) assert.Equal(t, &onActionStructTest{Debug: true, called: 1}, actual) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/templates.go000066400000000000000000000103511324515047600251650ustar00rootroot00000000000000package kingpin // DefaultUsageTemplate is the default usage template. var DefaultUsageTemplate = `{{define "FormatCommands" -}} {{range .FlattenedCommands -}} {{if not .Hidden}} {{.CmdSummary}} {{.Help|Wrap 4}} {{if .Flags -}} {{with .Flags|FlagsToTwoColumns}}{{FormatTwoColumnsWithIndent . 4 2}}{{end}} {{end -}} {{end -}} {{end -}} {{end -}} {{define "FormatUsage" -}} {{.AppSummary}} {{if .Help}} {{.Help|Wrap 0 -}} {{end -}} {{end -}} {{if .Context.SelectedCommand -}} {{T "usage:"}} {{.App.Name}} {{.App.FlagSummary}} {{.Context.SelectedCommand.CmdSummary}} {{else}} {{T "usage:"}} {{template "FormatUsage" .App}} {{end}} {{if .Context.Flags -}} {{T "Flags:"}} {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} {{end -}} {{if .Context.Args -}} {{T "Args:"}} {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} {{end -}} {{if .Context.SelectedCommand -}} {{if len .Context.SelectedCommand.Commands -}} {{T "Subcommands:"}} {{template "FormatCommands" .Context.SelectedCommand}} {{end -}} {{else if .App.Commands -}} {{T "Commands:" -}} {{template "FormatCommands" .App}} {{end -}} ` // CompactUsageTemplate is a template with compactly formatted commands for large command structures. 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 -}} {{T "usage:"}} {{.App.Name}} {{template "FormatUsage" .Context.SelectedCommand}} {{else -}} {{T "usage:"}} {{.App.Name}}{{template "FormatUsage" .App}} {{end -}} {{if .Context.Flags -}} {{T "Flags:"}} {{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}} {{end -}} {{if .Context.Args -}} {{T "Args:"}} {{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}} {{end -}} {{if .Context.SelectedCommand -}} {{if .Context.SelectedCommand.Commands -}} {{T "Commands:"}} {{.Context.SelectedCommand}} {{.Context.SelectedCommand.Commands|CommandsToTwoColumns|FormatTwoColumns}} {{end -}} {{else if .App.Commands -}} {{T "Commands:"}} {{.App.Commands|CommandsToTwoColumns|FormatTwoColumns}} {{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" -}} {{end -}} {{define "FormatCommands" -}} {{range .FlattenedCommands -}} {{if not .Hidden -}} .SS \fB{{.CmdSummary}}\fR .PP {{.Help}} {{template "FormatFlags" . -}} {{end -}} {{end -}} {{end -}} {{define "FormatUsage" -}} {{if .FlagSummary}} {{.FlagSummary}}{{end -}} {{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 -}} ` 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}) ) [[ $COMPREPLY ]] && return compgen -f return 0 } complete -F _{{.App.Name}}_bash_autocomplete {{.App.Name}} ` golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/usage.go000066400000000000000000000162441324515047600243020ustar00rootroot00000000000000package kingpin import ( "bytes" "fmt" "go/doc" "io" "strings" "text/template" ) var ( preIndent = " " ) // UsageContext contains all of the context used to render a usage message. type UsageContext struct { // The text/template body to use. Template string // Indentation multiplier (defaults to 2 of omitted). Indent int // Width of wrap. Defaults wraps to the terminal. Width int // Funcs available in the template. Funcs template.FuncMap // Vars available in the template. Vars map[string]interface{} } 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 Writer. 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(a.defaultUsage, context); 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, " ") } // haveShort will be true if there are short flags present at all in the help. Useful for column alignment. func formatFlag(haveShort bool, flag *ClauseModel) string { flagString := "" name := flag.Name isBool := flag.IsBoolFlag() if flag.IsNegatable() { name = "[no-]" + name } if flag.Short != 0 { flagString += fmt.Sprintf("-%c, --%s", flag.Short, name) } else { if haveShort { flagString += fmt.Sprintf(" --%s", name) } else { flagString += fmt.Sprintf("--%s", name) } } if !isBool { flagString += fmt.Sprintf("=%s", flag.FormatPlaceHolder()) } if v, ok := flag.Value.(cumulativeValue); ok && v.IsCumulative() { flagString += " ..." } return flagString } type templateParseContext struct { SelectedCommand *CmdModel *FlagGroupModel *ArgGroupModel } // 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(a.defaultUsage, context) } // UsageForContextWithTemplate is for fine-grained control over usage messages. You generally don't // need to use this. func (a *Application) UsageForContextWithTemplate(usageContext *UsageContext, parseContext *ParseContext) error { // nolint: gocyclo indent := usageContext.Indent if indent == 0 { indent = 2 } width := usageContext.Width if width == 0 { width = guessWidth(a.output) } tmpl := usageContext.Template if tmpl == "" { tmpl = a.defaultUsage.Template if tmpl == "" { tmpl = DefaultUsageTemplate } } funcs := template.FuncMap{ "T": T, "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 []*ClauseModel) [][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 []*ClauseModel) []*ClauseModel { requiredFlags := []*ClauseModel{} for _, flag := range f { if flag.Required { requiredFlags = append(requiredFlags, flag) } } return requiredFlags }, "OptionalFlags": func(f []*ClauseModel) []*ClauseModel { optionalFlags := []*ClauseModel{} for _, flag := range f { if !flag.Required { optionalFlags = append(optionalFlags, flag) } } return optionalFlags }, "ArgsToTwoColumns": func(a []*ClauseModel) [][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 }, "CommandsToTwoColumns": func(c []*CmdModel) [][2]string { return commandsToColumns(indent, c) }, "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.(cumulativeValue) return ok && r.IsCumulative() }, "Char": func(c rune) string { return string(c) }, } for name, fn := range usageContext.Funcs { funcs[name] = fn } t, err := template.New("usage").Funcs(funcs).Parse(tmpl) if err != nil { return err } appModel := a.Model() var selectedCommand *CmdModel if parseContext.SelectedCommand != nil { selectedCommand = appModel.FindModelForCommand(parseContext.SelectedCommand) } ctx := map[string]interface{}{ "App": appModel, "Width": width, "Context": &templateParseContext{ SelectedCommand: selectedCommand, FlagGroupModel: parseContext.flags.Model(), ArgGroupModel: parseContext.arguments.Model(), }, } for k, v := range usageContext.Vars { ctx[k] = v } return t.Execute(a.output, ctx) } func commandsToColumns(indent int, cmds []*CmdModel) [][2]string { out := [][2]string{} for _, cmd := range cmds { if cmd.Hidden { continue } left := cmd.Name if cmd.FlagSummary() != "" { left += " " + cmd.FlagSummary() } args := []string{} for _, arg := range cmd.Args { if arg.Required { argText := "<" + arg.Name + ">" if _, ok := arg.Value.(cumulativeValue); ok { argText += " ..." } args = append(args, argText) } } if len(args) != 0 { left += " " + strings.Join(args, " ") } out = append(out, [2]string{strings.Repeat(" ", cmd.Depth*indent-1) + left, cmd.Help}) out = append(out, commandsToColumns(indent, cmd.Commands)...) } return out } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/usage_test.go000066400000000000000000000056121324515047600253360ustar00rootroot00000000000000package kingpin import ( "bytes" "io/ioutil" "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 TestRequiredSubcommandsUsage(t *testing.T) { var buf bytes.Buffer a := New("test", "Test").Writers(&buf, ioutil.Discard).Terminate(nil) c0 := a.Command("c0", "c0info") c0.Command("c1", "c1info") _, err := a.Parse(nil) assert.Error(t, err) expectedStr := ` usage: test [] Test Flags: --help Show context-sensitive help. Commands: help [ ...] Show help. c0 c1 c1info ` assert.Equal(t, expectedStr, buf.String()) } func TestOptionalSubcommandsUsage(t *testing.T) { var buf bytes.Buffer a := New("test", "Test").Writers(&buf, ioutil.Discard).Terminate(nil) c0 := a.Command("c0", "c0info").OptionalSubcommands() c0.Command("c1", "c1info") _, err := a.Parse(nil) assert.Error(t, err) expectedStr := ` usage: test [] Test Flags: --help Show context-sensitive help. Commands: help [ ...] Show help. c0 c0info c0 c1 c1info ` assert.Equal(t, expectedStr, 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}, {"Man", ManPageTemplate}, } var buf bytes.Buffer a := New("test", "Test").Writers(&buf, ioutil.Discard).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") } } func TestIssue169MultipleUsageCorruption(t *testing.T) { buf := &bytes.Buffer{} app := newTestApp() cmd := app.Command("cmd", "") cmd.Flag("flag", "").Default("false").Bool() app.Writers(buf, ioutil.Discard) _, err := app.Parse([]string{"help", "cmd"}) assert.NoError(t, err) expected := buf.String() buf.Reset() _, err = app.Parse([]string{"help"}) assert.NoError(t, err) actual := buf.String() assert.NotEqual(t, expected, actual) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/values.go000066400000000000000000000252361324515047600244760ustar00rootroot00000000000000package kingpin //go:generate go run ./cmd/genvalues/main.go import ( "fmt" "net" "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. // // This is for compatibility with the stdlib. type boolFlag interface { Value IsBoolFlag() bool } // BoolFlag is an optional interface to specify that a flag is a boolean flag. type BoolFlag interface { // Specify if the flag is negatable (ie. supports both --no- and --name). BoolFlagIsNegatable() bool } // Optional interface for values that cumulatively consume all remaining // input. type cumulativeValue interface { Value Reset() IsCumulative() bool } type accumulatorOptions struct { separator string } func (a *accumulatorOptions) split(value string) []string { if a.separator == "" { return []string{value} } return strings.Split(value, a.separator) } func newAccumulatorOptions(options ...AccumulatorOption) *accumulatorOptions { out := &accumulatorOptions{} for _, option := range options { option(out) } return out } // AccumulatorOption are used to modify the behaviour of values that accumulate into slices, maps, etc. // // eg. Separator(',') type AccumulatorOption func(a *accumulatorOptions) // Separator configures an accumulating value to split on this value. func Separator(separator string) AccumulatorOption { return func(a *accumulatorOptions) { a.separator = separator } } type accumulator struct { element func(value interface{}) Value typ reflect.Type slice reflect.Value accumulatorOptions } func isBoolFlag(f Value) bool { if bf, ok := f.(boolFlag); ok { return bf.IsBoolFlag() } _, ok := f.(BoolFlag) return ok } // Use reflection to accumulate values into a slice. // // target := []string{} // newAccumulator(&target, func (value interface{}) Value { // return newStringValue(value.(*string)) // }) func newAccumulator(slice interface{}, options []AccumulatorOption, element func(value interface{}) Value) *accumulator { typ := reflect.TypeOf(slice) if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Slice { panic(T("expected a pointer to a slice")) } return &accumulator{ element: element, typ: typ.Elem().Elem(), slice: reflect.ValueOf(slice), accumulatorOptions: *newAccumulatorOptions(options...), } } 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 { values := []string{} if a.separator == "" { values = append(values, value) } else { values = append(values, strings.Split(value, a.separator)...) } for _, v := range values { e := reflect.New(a.typ) if err := a.element(e.Interface()).Set(v); 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 (a *accumulator) Reset() { if a.slice.Kind() == reflect.Ptr { a.slice.Elem().Set(reflect.MakeSlice(a.slice.Type().Elem(), 0, 0)) } else { a.slice.Set(reflect.MakeSlice(a.slice.Type(), 0, 0)) } } func (b *boolValue) BoolFlagIsNegatable() bool { return false } // -- A boolean flag that can not be negated. func (n *negatableBoolValue) BoolFlagIsNegatable() bool { return true } // -- map[string]string Value type stringMapValue struct { values *map[string]string accumulatorOptions } func newStringMapValue(p *map[string]string, options ...AccumulatorOption) *stringMapValue { return &stringMapValue{ values: p, accumulatorOptions: *newAccumulatorOptions(options...), } } var stringMapRegex = regexp.MustCompile("[:=]") func (s *stringMapValue) Set(value string) error { values := []string{} if s.separator == "" { values = append(values, value) } else { values = append(values, strings.Split(value, s.separator)...) } for _, v := range values { parts := stringMapRegex.Split(v, 2) if len(parts) != 2 { return TError("expected KEY=VALUE got '{{.Arg0}}'", V{"Arg0": v}) } (*s.values)[parts[0]] = parts[1] } return nil } func (s *stringMapValue) Get() interface{} { return *s.values } func (s *stringMapValue) String() string { return fmt.Sprintf("%s", *s.values) } func (s *stringMapValue) IsCumulative() bool { return true } func (s *stringMapValue) Reset() { *s.values = map[string]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 (f *fileStatValue) Set(value string) error { if s, err := os.Stat(value); os.IsNotExist(err) { return TError("path '{{.Arg0}}' does not exist", V{"Arg0": value}) } else if err != nil { return err } else if err := f.predicate(s); err != nil { return err } *f.path = value return nil } func (f *fileStatValue) Get() interface{} { return (string)(*f.path) } func (f *fileStatValue) String() string { return *f.path } // -- net.IP Value type ipValue net.IP func newIPValue(p *net.IP) *ipValue { return (*ipValue)(p) } func (i *ipValue) Set(value string) error { ip := net.ParseIP(value) if ip == nil { return fmt.Errorf("'%s' is not an IP address", value) } *i = *(*ipValue)(&ip) return nil } func (i *ipValue) Get() interface{} { return (net.IP)(*i) } func (i *ipValue) String() string { return (*net.IP)(i).String() } // 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 (e *enumValue) String() string { return *e.value } func (e *enumValue) Set(value string) error { for _, v := range e.options { if v == value { *e.value = value return nil } } return TError("enum value must be one of {{.Arg0}}, got '{{.Arg1}}'", V{"Arg0": strings.Join(e.options, T(",")), "Arg1": value}) } func (e *enumValue) Get() interface{} { return (string)(*e.value) } // -- []string Enum Value type enumsValue struct { value *[]string options []string accumulatorOptions } func newEnumsFlag(target *[]string, options ...string) *enumsValue { return &enumsValue{ value: target, options: options, } } func (e *enumsValue) Set(value string) error { nextValue: for _, v := range e.split(value) { for _, o := range e.options { if o == v { *e.value = append(*e.value, v) continue nextValue } } return TError("enum value must be one of {{.Arg0}}, got '{{.Arg1}}'", V{"Arg0": strings.Join(e.options, T(",")), "Arg1": v}) } return nil } func (e *enumsValue) Get() interface{} { return ([]string)(*e.value) } func (e *enumsValue) String() string { return strings.Join(*e.value, ",") } func (e *enumsValue) IsCumulative() bool { return true } func (e *enumsValue) Reset() { *e.value = []string{} } // -- 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 TError("'{{.Arg0}}' is a directory", V{"Arg0": s.Name()}) } return nil }) } func newExistingDirValue(target *string) *fileStatValue { return newFileStatValue(target, func(s os.FileInfo) error { if !s.IsDir() { return TError("'{{.Arg0}}' is a file", V{"Arg0": 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 (c *counterValue) Reset() { *c = 0 } // -- time.Time Value type timeValue struct { format string v *time.Time } func newTimeValue(format string, p *time.Time) *timeValue { return &timeValue{format, p} } func (f *timeValue) Set(s string) error { v, err := time.Parse(f.format, s) if err == nil { *f.v = (time.Time)(v) } return err } func (f *timeValue) Get() interface{} { return (time.Time)(*f.v) } func (f *timeValue) String() string { return f.v.String() } // Time parses a time.Time. // // Format is the layout as specified at https://golang.org/pkg/time/#Parse func (p *Clause) Time(format string) (target *time.Time) { target = new(time.Time) p.TimeVar(format, target) return } func (p *Clause) TimeVar(format string, target *time.Time) { p.SetValue(newTimeValue(format, target)) } // TimeList accumulates time.Time values into a slice. func (p *Clause) TimeList(format string, options ...AccumulatorOption) (target *[]time.Time) { target = new([]time.Time) p.TimeListVar(format, target, options...) return } func (p *Clause) TimeListVar(format string, target *[]time.Time, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newTimeValue(format, v.(*time.Time)) })) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/values.json000066400000000000000000000033031324515047600250310ustar00rootroot00000000000000[ {"name": "Duration", "type": "time.Duration", "parser": "time.ParseDuration(s)", "help": "Time duration."}, {"name": "ExistingDir", "type": "string", "plural": "ExistingDirs", "no_value_parser": true}, {"name": "ExistingFile", "type": "string", "plural": "ExistingFiles", "no_value_parser": true}, {"name": "ExistingFileOrDir", "type": "string", "plural": "ExistingFilesOrDirs", "no_value_parser": true}, {"name": "HexBytes", "type": "[]byte", "parser": "hex.DecodeString(s)", "help": "Bytes as a hex string."}, {"name": "IP", "type": "net.IP", "no_value_parser": true}, {"name": "NegatableBool", "type": "bool", "parser": "strconv.ParseBool(s)"}, {"name": "Regexp", "type": "*regexp.Regexp", "parser": "regexp.Compile(s)"}, {"name": "URL", "type": "*url.URL", "parser": "url.Parse(s)"}, {"type": "bool", "parser": "strconv.ParseBool(s)"}, {"type": "float32", "parser": "strconv.ParseFloat(s, 32)"}, {"type": "float64", "parser": "strconv.ParseFloat(s, 64)"}, {"type": "int", "parser": "strconv.ParseFloat(s, 64)", "plural": "Ints"}, {"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": "int8", "parser": "strconv.ParseInt(s, 0, 8)"}, {"type": "string", "parser": "s, error(nil)", "format": "string(*f.v)", "plural": "Strings"}, {"type": "uint", "parser": "strconv.ParseUint(s, 0, 64)", "plural": "Uints"}, {"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": "uint8", "parser": "strconv.ParseUint(s, 0, 8)"} ] golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/values_generated.go000066400000000000000000000521661324515047600265160ustar00rootroot00000000000000package kingpin import ( "encoding/hex" "fmt" "net" "net/url" "regexp" "strconv" "time" ) // This file is autogenerated by "go generate .". Do not modify. // -- time.Duration Value type durationValue struct{ v *time.Duration } func newDurationValue(p *time.Duration) *durationValue { return &durationValue{p} } func (f *durationValue) Set(s string) error { v, err := time.ParseDuration(s) if err == nil { *f.v = (time.Duration)(v) } return err } func (f *durationValue) Get() interface{} { return (time.Duration)(*f.v) } func (f *durationValue) String() string { return fmt.Sprintf("%v", *f.v) } // Time duration. func (p *Clause) Duration() (target *time.Duration) { target = new(time.Duration) p.DurationVar(target) return } func (p *Clause) DurationVar(target *time.Duration) { p.SetValue(newDurationValue(target)) } // DurationList accumulates time.Duration values into a slice. func (p *Clause) DurationList(options ...AccumulatorOption) (target *[]time.Duration) { target = new([]time.Duration) p.DurationListVar(target, options...) return } func (p *Clause) DurationListVar(target *[]time.Duration, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newDurationValue(v.(*time.Duration)) })) } // ExistingDirs accumulates string values into a slice. func (p *Clause) ExistingDirs(options ...AccumulatorOption) (target *[]string) { target = new([]string) p.ExistingDirsVar(target, options...) return } func (p *Clause) ExistingDirsVar(target *[]string, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newExistingDirValue(v.(*string)) })) } // ExistingFiles accumulates string values into a slice. func (p *Clause) ExistingFiles(options ...AccumulatorOption) (target *[]string) { target = new([]string) p.ExistingFilesVar(target, options...) return } func (p *Clause) ExistingFilesVar(target *[]string, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newExistingFileValue(v.(*string)) })) } // ExistingFilesOrDirs accumulates string values into a slice. func (p *Clause) ExistingFilesOrDirs(options ...AccumulatorOption) (target *[]string) { target = new([]string) p.ExistingFilesOrDirsVar(target, options...) return } func (p *Clause) ExistingFilesOrDirsVar(target *[]string, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newExistingFileOrDirValue(v.(*string)) })) } // -- []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 *Clause) HexBytes() (target *[]byte) { target = new([]byte) p.HexBytesVar(target) return } func (p *Clause) HexBytesVar(target *[]byte) { p.SetValue(newHexBytesValue(target)) } // HexBytesList accumulates []byte values into a slice. func (p *Clause) HexBytesList(options ...AccumulatorOption) (target *[][]byte) { target = new([][]byte) p.HexBytesListVar(target, options...) return } func (p *Clause) HexBytesListVar(target *[][]byte, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newHexBytesValue(v.(*[]byte)) })) } // IPList accumulates net.IP values into a slice. func (p *Clause) IPList(options ...AccumulatorOption) (target *[]net.IP) { target = new([]net.IP) p.IPListVar(target, options...) return } func (p *Clause) IPListVar(target *[]net.IP, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newIPValue(v.(*net.IP)) })) } // -- bool Value type negatableBoolValue struct{ v *bool } func newNegatableBoolValue(p *bool) *negatableBoolValue { return &negatableBoolValue{p} } func (f *negatableBoolValue) Set(s string) error { v, err := strconv.ParseBool(s) if err == nil { *f.v = (bool)(v) } return err } func (f *negatableBoolValue) Get() interface{} { return (bool)(*f.v) } func (f *negatableBoolValue) String() string { return fmt.Sprintf("%v", *f.v) } // NegatableBool parses the next command-line value as bool. func (p *Clause) NegatableBool() (target *bool) { target = new(bool) p.NegatableBoolVar(target) return } func (p *Clause) NegatableBoolVar(target *bool) { p.SetValue(newNegatableBoolValue(target)) } // NegatableBoolList accumulates bool values into a slice. func (p *Clause) NegatableBoolList(options ...AccumulatorOption) (target *[]bool) { target = new([]bool) p.NegatableBoolListVar(target, options...) return } func (p *Clause) NegatableBoolListVar(target *[]bool, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newNegatableBoolValue(v.(*bool)) })) } // -- *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 *Clause) Regexp() (target **regexp.Regexp) { target = new(*regexp.Regexp) p.RegexpVar(target) return } func (p *Clause) RegexpVar(target **regexp.Regexp) { p.SetValue(newRegexpValue(target)) } // RegexpList accumulates *regexp.Regexp values into a slice. func (p *Clause) RegexpList(options ...AccumulatorOption) (target *[]*regexp.Regexp) { target = new([]*regexp.Regexp) p.RegexpListVar(target, options...) return } func (p *Clause) RegexpListVar(target *[]*regexp.Regexp, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newRegexpValue(v.(**regexp.Regexp)) })) } // -- *url.URL Value type uRLValue struct{ v **url.URL } func newURLValue(p **url.URL) *uRLValue { return &uRLValue{p} } func (f *uRLValue) Set(s string) error { v, err := url.Parse(s) if err == nil { *f.v = (*url.URL)(v) } return err } func (f *uRLValue) Get() interface{} { return (*url.URL)(*f.v) } func (f *uRLValue) String() string { return fmt.Sprintf("%v", *f.v) } // URL parses the next command-line value as *url.URL. func (p *Clause) URL() (target **url.URL) { target = new(*url.URL) p.URLVar(target) return } func (p *Clause) URLVar(target **url.URL) { p.SetValue(newURLValue(target)) } // URLList accumulates *url.URL values into a slice. func (p *Clause) URLList(options ...AccumulatorOption) (target *[]*url.URL) { target = new([]*url.URL) p.URLListVar(target, options...) return } func (p *Clause) URLListVar(target *[]*url.URL, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newURLValue(v.(**url.URL)) })) } // -- 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 *Clause) Bool() (target *bool) { target = new(bool) p.BoolVar(target) return } func (p *Clause) BoolVar(target *bool) { p.SetValue(newBoolValue(target)) } // BoolList accumulates bool values into a slice. func (p *Clause) BoolList(options ...AccumulatorOption) (target *[]bool) { target = new([]bool) p.BoolListVar(target, options...) return } func (p *Clause) BoolListVar(target *[]bool, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newBoolValue(v.(*bool)) })) } // -- 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 *Clause) Float32() (target *float32) { target = new(float32) p.Float32Var(target) return } func (p *Clause) Float32Var(target *float32) { p.SetValue(newFloat32Value(target)) } // Float32List accumulates float32 values into a slice. func (p *Clause) Float32List(options ...AccumulatorOption) (target *[]float32) { target = new([]float32) p.Float32ListVar(target, options...) return } func (p *Clause) Float32ListVar(target *[]float32, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newFloat32Value(v.(*float32)) })) } // -- 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 *Clause) Float64() (target *float64) { target = new(float64) p.Float64Var(target) return } func (p *Clause) Float64Var(target *float64) { p.SetValue(newFloat64Value(target)) } // Float64List accumulates float64 values into a slice. func (p *Clause) Float64List(options ...AccumulatorOption) (target *[]float64) { target = new([]float64) p.Float64ListVar(target, options...) return } func (p *Clause) Float64ListVar(target *[]float64, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newFloat64Value(v.(*float64)) })) } // -- 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 *Clause) Int() (target *int) { target = new(int) p.IntVar(target) return } func (p *Clause) IntVar(target *int) { p.SetValue(newIntValue(target)) } // Ints accumulates int values into a slice. func (p *Clause) Ints(options ...AccumulatorOption) (target *[]int) { target = new([]int) p.IntsVar(target, options...) return } func (p *Clause) IntsVar(target *[]int, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newIntValue(v.(*int)) })) } // -- 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 *Clause) Int16() (target *int16) { target = new(int16) p.Int16Var(target) return } func (p *Clause) Int16Var(target *int16) { p.SetValue(newInt16Value(target)) } // Int16List accumulates int16 values into a slice. func (p *Clause) Int16List(options ...AccumulatorOption) (target *[]int16) { target = new([]int16) p.Int16ListVar(target, options...) return } func (p *Clause) Int16ListVar(target *[]int16, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, 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 *Clause) Int32() (target *int32) { target = new(int32) p.Int32Var(target) return } func (p *Clause) Int32Var(target *int32) { p.SetValue(newInt32Value(target)) } // Int32List accumulates int32 values into a slice. func (p *Clause) Int32List(options ...AccumulatorOption) (target *[]int32) { target = new([]int32) p.Int32ListVar(target, options...) return } func (p *Clause) Int32ListVar(target *[]int32, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, 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 *Clause) Int64() (target *int64) { target = new(int64) p.Int64Var(target) return } func (p *Clause) Int64Var(target *int64) { p.SetValue(newInt64Value(target)) } // Int64List accumulates int64 values into a slice. func (p *Clause) Int64List(options ...AccumulatorOption) (target *[]int64) { target = new([]int64) p.Int64ListVar(target, options...) return } func (p *Clause) Int64ListVar(target *[]int64, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newInt64Value(v.(*int64)) })) } // -- 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 *Clause) Int8() (target *int8) { target = new(int8) p.Int8Var(target) return } func (p *Clause) Int8Var(target *int8) { p.SetValue(newInt8Value(target)) } // Int8List accumulates int8 values into a slice. func (p *Clause) Int8List(options ...AccumulatorOption) (target *[]int8) { target = new([]int8) p.Int8ListVar(target, options...) return } func (p *Clause) Int8ListVar(target *[]int8, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newInt8Value(v.(*int8)) })) } // -- 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 *Clause) String() (target *string) { target = new(string) p.StringVar(target) return } func (p *Clause) StringVar(target *string) { p.SetValue(newStringValue(target)) } // Strings accumulates string values into a slice. func (p *Clause) Strings(options ...AccumulatorOption) (target *[]string) { target = new([]string) p.StringsVar(target, options...) return } func (p *Clause) StringsVar(target *[]string, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, 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 *Clause) Uint() (target *uint) { target = new(uint) p.UintVar(target) return } func (p *Clause) UintVar(target *uint) { p.SetValue(newUintValue(target)) } // Uints accumulates uint values into a slice. func (p *Clause) Uints(options ...AccumulatorOption) (target *[]uint) { target = new([]uint) p.UintsVar(target, options...) return } func (p *Clause) UintsVar(target *[]uint, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newUintValue(v.(*uint)) })) } // -- 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 *Clause) Uint16() (target *uint16) { target = new(uint16) p.Uint16Var(target) return } func (p *Clause) Uint16Var(target *uint16) { p.SetValue(newUint16Value(target)) } // Uint16List accumulates uint16 values into a slice. func (p *Clause) Uint16List(options ...AccumulatorOption) (target *[]uint16) { target = new([]uint16) p.Uint16ListVar(target, options...) return } func (p *Clause) Uint16ListVar(target *[]uint16, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, 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 *Clause) Uint32() (target *uint32) { target = new(uint32) p.Uint32Var(target) return } func (p *Clause) Uint32Var(target *uint32) { p.SetValue(newUint32Value(target)) } // Uint32List accumulates uint32 values into a slice. func (p *Clause) Uint32List(options ...AccumulatorOption) (target *[]uint32) { target = new([]uint32) p.Uint32ListVar(target, options...) return } func (p *Clause) Uint32ListVar(target *[]uint32, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, 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 *Clause) Uint64() (target *uint64) { target = new(uint64) p.Uint64Var(target) return } func (p *Clause) Uint64Var(target *uint64) { p.SetValue(newUint64Value(target)) } // Uint64List accumulates uint64 values into a slice. func (p *Clause) Uint64List(options ...AccumulatorOption) (target *[]uint64) { target = new([]uint64) p.Uint64ListVar(target, options...) return } func (p *Clause) Uint64ListVar(target *[]uint64, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newUint64Value(v.(*uint64)) })) } // -- 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 *Clause) Uint8() (target *uint8) { target = new(uint8) p.Uint8Var(target) return } func (p *Clause) Uint8Var(target *uint8) { p.SetValue(newUint8Value(target)) } // Uint8List accumulates uint8 values into a slice. func (p *Clause) Uint8List(options ...AccumulatorOption) (target *[]uint8) { target = new([]uint8) p.Uint8ListVar(target, options...) return } func (p *Clause) Uint8ListVar(target *[]uint8, options ...AccumulatorOption) { p.SetValue(newAccumulator(target, options, func(v interface{}) Value { return newUint8Value(v.(*uint8)) })) } golang-gopkg-alecthomas-kingpin.v3-3.0~git20180227.b8d601d/values_test.go000066400000000000000000000053751324515047600255370ustar00rootroot00000000000000package kingpin import ( "net" "github.com/stretchr/testify/assert" "testing" ) func TestAccumulatorStrings(t *testing.T) { target := []string{} acc := newAccumulator(&target, nil, 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 TestAccumulatorSeparator(t *testing.T) { target := []string{} acc := newAccumulator(&target, []AccumulatorOption{Separator(",")}, func(v interface{}) Value { return newStringValue(v.(*string)) }) acc.Set("a,b") assert.Equal(t, []string{"a", "b"}, target) acc.Set("c,d") assert.Equal(t, []string{"a", "b", "c", "d"}, 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 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) } func TestIPv4Addr(t *testing.T) { app := newTestApp() flag := app.Flag("addr", "").IP() _, 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", "").IP() _, err := app.Parse([]string{"--addr", "1.2.3.256"}) assert.Error(t, err) } func TestIPv6Addr(t *testing.T) { app := newTestApp() flag := app.Flag("addr", "").IP() _, err := app.Parse([]string{"--addr", net.IPv6interfacelocalallnodes.String()}) assert.NoError(t, err) assert.NotNil(t, *flag) assert.Equal(t, net.IPv6interfacelocalallnodes, *flag) }