mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-29 12:42:46 +00:00
gb vendor fetch github.com/alecthomas/gometalinter
This commit is contained in:
parent
643d05b157
commit
a26d7c2899
630 changed files with 176389 additions and 0 deletions
19
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/COPYING
vendored
Normal file
19
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/COPYING
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (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.
|
732
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/README.md
vendored
Normal file
732
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/README.md
vendored
Normal file
|
@ -0,0 +1,732 @@
|
|||
# Kingpin - A Go (golang) command line and flag parser [](http://godoc.org/github.com/alecthomas/kingpin) [](https://travis-ci.org/alecthomas/kingpin)
|
||||
|
||||
<!-- MarkdownTOC -->
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Features](#features)
|
||||
- [User-visible changes between v1 and v2](#user-visible-changes-between-v1-and-v2)
|
||||
- [Flags can be used at any point after their definition.](#flags-can-be-used-at-any-point-after-their-definition)
|
||||
- [Short flags can be combined with their parameters](#short-flags-can-be-combined-with-their-parameters)
|
||||
- [API changes between v1 and v2](#api-changes-between-v1-and-v2)
|
||||
- [Versions](#versions)
|
||||
- [V2 is the current stable version](#v2-is-the-current-stable-version)
|
||||
- [V1 is the OLD stable version](#v1-is-the-old-stable-version)
|
||||
- [Change History](#change-history)
|
||||
- [Examples](#examples)
|
||||
- [Simple Example](#simple-example)
|
||||
- [Complex Example](#complex-example)
|
||||
- [Reference Documentation](#reference-documentation)
|
||||
- [Displaying errors and usage information](#displaying-errors-and-usage-information)
|
||||
- [Sub-commands](#sub-commands)
|
||||
- [Custom Parsers](#custom-parsers)
|
||||
- [Repeatable flags](#repeatable-flags)
|
||||
- [Boolean values](#boolean-values)
|
||||
- [Default Values](#default-values)
|
||||
- [Place-holders in Help](#place-holders-in-help)
|
||||
- [Consuming all remaining arguments](#consuming-all-remaining-arguments)
|
||||
- [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)
|
||||
|
||||
<!-- /MarkdownTOC -->
|
||||
|
||||
## 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 (`@<file>`).
|
||||
- Automatically generate man pages (`--help-man`).
|
||||
|
||||
## User-visible changes between v1 and v2
|
||||
|
||||
### Flags can be used at any point after their definition.
|
||||
|
||||
Flags can be specified at any point after their definition, not just
|
||||
*immediately after their associated command*. From the chat example below, the
|
||||
following used to be required:
|
||||
|
||||
```
|
||||
$ chat --server=chat.server.com:8080 post --image=~/Downloads/owls.jpg pics
|
||||
```
|
||||
|
||||
But the following will now work:
|
||||
|
||||
```
|
||||
$ chat post --server=chat.server.com:8080 --image=~/Downloads/owls.jpg pics
|
||||
```
|
||||
|
||||
### Short flags can be combined with their parameters
|
||||
|
||||
Previously, if a short flag was used, any argument to that flag would have to
|
||||
be separated by a space. That is no longer the case.
|
||||
|
||||
## API changes between v1 and v2
|
||||
|
||||
- `ParseWithFileExpansion()` is gone. The new parser directly supports expanding `@<file>`.
|
||||
- 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 @<file>).
|
||||
- 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>] <ip> [<count>]
|
||||
|
||||
Flags:
|
||||
--debug Enable debug mode.
|
||||
--help Show help.
|
||||
-t, --timeout=5s Timeout waiting for ping.
|
||||
|
||||
Args:
|
||||
<ip> IP address to ping.
|
||||
[<count>] Number of packets to send
|
||||
$ ping 1.2.3.4 5
|
||||
Would ping: 1.2.3.4 with timeout 5s 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 [<flags>] <command> [<flags>] [<args> ...]
|
||||
|
||||
A command-line chat application.
|
||||
|
||||
Flags:
|
||||
--help Show help.
|
||||
--debug Enable debug mode.
|
||||
--server=127.0.0.1 Server address.
|
||||
|
||||
Commands:
|
||||
help [<command>]
|
||||
Show help for a command.
|
||||
|
||||
register <nick> <name>
|
||||
Register a new user.
|
||||
|
||||
post [<flags>] <channel> [<text>]
|
||||
Post a message to a channel.
|
||||
|
||||
$ chat help post
|
||||
usage: chat [<flags>] post [<flags>] <channel> [<text>]
|
||||
|
||||
Post a message to a channel.
|
||||
|
||||
Flags:
|
||||
--image=IMAGE Image to post.
|
||||
|
||||
Args:
|
||||
<channel> Channel to post to.
|
||||
[<text>] Text to post.
|
||||
|
||||
$ chat post --image=~/Downloads/owls.jpg pics
|
||||
...
|
||||
```
|
||||
|
||||
From this code:
|
||||
|
||||
```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:
|
||||
|
||||
<app>: error: <message>
|
||||
|
||||
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:
|
||||
`--<name>` and `--no-<name>`.
|
||||
|
||||
### 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."))
|
||||
```
|
||||
|
||||
### 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 [<flags>] <command> [<args> ...]
|
||||
|
||||
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 [<command>...]
|
||||
Show help.
|
||||
|
||||
get url <url>
|
||||
Retrieve a URL.
|
||||
|
||||
get file <file>
|
||||
Retrieve a file.
|
||||
|
||||
post [<flags>] <url>
|
||||
POST a resource.
|
||||
```
|
||||
|
||||
#### Compact help template
|
||||
|
||||
```
|
||||
$ go run ./examples/curl/curl.go --help
|
||||
usage: curl [<flags>] <command> [<args> ...]
|
||||
|
||||
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 [<command>...]
|
||||
get [<flags>]
|
||||
url <url>
|
||||
file <file>
|
||||
post [<flags>] <url>
|
||||
```
|
20
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/chat1/main.go
vendored
Normal file
20
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/chat1/main.go
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
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)
|
||||
}
|
38
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/chat2/main.go
vendored
Normal file
38
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/chat2/main.go
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
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)
|
||||
}
|
||||
}
|
96
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/completion/main.go
vendored
Normal file
96
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/completion/main.go
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
package 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:]))
|
||||
}
|
109
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/curl/main.go
vendored
Normal file
109
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/curl/main.go
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
// 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")
|
||||
}
|
||||
}
|
30
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/modular/main.go
vendored
Normal file
30
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/modular/main.go
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
package 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:]))
|
||||
}
|
20
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/ping/main.go
vendored
Normal file
20
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/_examples/ping/main.go
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
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.").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)
|
||||
}
|
45
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/actions.go
vendored
Normal file
45
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/actions.go
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
package kingpin
|
||||
|
||||
// Action callback triggered during parsing.
|
||||
//
|
||||
// "element" is the flag, argument or command associated with the callback. It contains the Clause
|
||||
// and the string value.
|
||||
//
|
||||
// "context" contains the full parse context, including all other elements that have been parsed.
|
||||
type Action func(app *Application, element *ParseElement, context *ParseContext) error
|
||||
|
||||
type actionApplier interface {
|
||||
applyActions(*Application, *ParseElement, *ParseContext) error
|
||||
applyPreActions(*Application, *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(app *Application, element *ParseElement, context *ParseContext) error {
|
||||
for _, action := range a.actions {
|
||||
if err := action(app, element, context); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *actionMixin) applyPreActions(app *Application, element *ParseElement, context *ParseContext) error {
|
||||
for _, preAction := range a.preActions {
|
||||
if err := preAction(app, element, context); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
55
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/actions_test.go
vendored
Normal file
55
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/actions_test.go
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFlagPreAction(t *testing.T) {
|
||||
a := newTestApp()
|
||||
actual := ""
|
||||
flag := a.Flag("flag", "").PreAction(func(_ *Application, e *ParseElement, c *ParseContext) error {
|
||||
actual = *e.Value
|
||||
return nil
|
||||
}).Bool()
|
||||
|
||||
_, 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(_ *Application, e *ParseElement, c *ParseContext) error {
|
||||
actual = *e.Value
|
||||
return nil
|
||||
}).Bool()
|
||||
|
||||
_, 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)
|
||||
}
|
651
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/app.go
vendored
Normal file
651
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/app.go
vendored
Normal file
|
@ -0,0 +1,651 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
errCommandNotSpecified = TError("command not specified")
|
||||
envarTransformRegexp = regexp.MustCompile(`[^a-zA-Z_]+`)
|
||||
)
|
||||
|
||||
// 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)
|
||||
defaultEnvars bool
|
||||
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,
|
||||
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(a *Application, e *ParseElement, c *ParseContext) error {
|
||||
a.UsageForContext(c)
|
||||
a.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(_ *Application, 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(_ *Application, 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 "<app>_<flag>".
|
||||
//
|
||||
// For example, if the application is named "foo" and a flag is named "bar-
|
||||
// waz" the environment variable: "FOO_BAR_WAZ".
|
||||
func (a *Application) DefaultEnvars() *Application {
|
||||
a.defaultEnvars = true
|
||||
return a
|
||||
}
|
||||
|
||||
// Terminate specifies the termination handler. Defaults to os.Exit(status).
|
||||
// If nil is passed, a no-op function will be used.
|
||||
func (a *Application) Terminate(terminate func(int)) *Application {
|
||||
if terminate == nil {
|
||||
terminate = func(int) {}
|
||||
}
|
||||
a.terminate = terminate
|
||||
return a
|
||||
}
|
||||
|
||||
// Writer specifies the writer to use for usage and errors. Defaults to os.Stderr.
|
||||
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)
|
||||
err := parse(context, a)
|
||||
return context, err
|
||||
}
|
||||
|
||||
// Parse parses command-line arguments. It returns the selected command and an
|
||||
// error. The selected command will be a space separated subcommand, if
|
||||
// subcommands have been configured.
|
||||
//
|
||||
// This will populate all flag and argument values, call all callbacks, and so
|
||||
// on.
|
||||
func (a *Application) Parse(args []string) (command string, err error) {
|
||||
context, parseErr := a.ParseContext(args)
|
||||
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(*Application, *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) defaultEnvarPrefix() string {
|
||||
if a.defaultEnvars {
|
||||
return a.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
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(_ *Application, 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(a.defaultEnvarPrefix()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.cmdGroup.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.argGroup.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, cmd := range a.commands {
|
||||
if err := cmd.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
flagGroups := []*flagGroup{a.flagGroup}
|
||||
for _, cmd := range a.commandOrder {
|
||||
if err := checkDuplicateFlags(cmd, flagGroups); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
a.initialized = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Recursively check commands for duplicate flags.
|
||||
func checkDuplicateFlags(current *CmdClause, flagGroups []*flagGroup) error {
|
||||
// Check for duplicates.
|
||||
for _, flags := range flagGroups {
|
||||
for _, flag := range current.flagOrder {
|
||||
if flag.shorthand != 0 {
|
||||
if _, ok := flags.short[string(flag.shorthand)]; ok {
|
||||
return 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(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
flag.reset()
|
||||
}
|
||||
}
|
||||
|
||||
for _, arg := range context.arguments.args {
|
||||
if argElements[arg.name] == nil {
|
||||
if err := arg.setDefault(); 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() {
|
||||
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() {
|
||||
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 "<appname>: error: <message>".
|
||||
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(a, nil, context); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, element := range context.Elements {
|
||||
if err := a.actionMixin.applyPreActions(a, 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(a, element, context); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Application) applyActions(context *ParseContext) error {
|
||||
if err := a.actionMixin.applyActions(a, nil, context); err != nil {
|
||||
return err
|
||||
}
|
||||
// Dispatch to actions.
|
||||
for _, element := range context.Elements {
|
||||
if err := a.actionMixin.applyActions(a, 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(a, element, context); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func envarTransform(name string) string {
|
||||
return strings.ToUpper(envarTransformRegexp.ReplaceAllString(name, "_"))
|
||||
}
|
428
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/app_test.go
vendored
Normal file
428
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/app_test.go
vendored
Normal file
|
@ -0,0 +1,428 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func newTestApp() *Application {
|
||||
return New("test", "").Terminate(nil)
|
||||
}
|
||||
|
||||
func TestCommander(t *testing.T) {
|
||||
c := newTestApp()
|
||||
ping := c.Command("ping", "Ping an IP address.")
|
||||
pingTTL := ping.Flag("ttl", "TTL for ICMP packets").Short('t').Default("5s").Duration()
|
||||
|
||||
selected, err := c.Parse([]string{"ping"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "ping", selected)
|
||||
assert.Equal(t, 5*time.Second, *pingTTL)
|
||||
|
||||
selected, err = c.Parse([]string{"ping", "--ttl=10s"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "ping", selected)
|
||||
assert.Equal(t, 10*time.Second, *pingTTL)
|
||||
}
|
||||
|
||||
func TestRequiredFlags(t *testing.T) {
|
||||
c := newTestApp()
|
||||
c.Flag("a", "a").String()
|
||||
c.Flag("b", "b").Required().String()
|
||||
|
||||
_, err := c.Parse([]string{"--a=foo"})
|
||||
assert.Error(t, err)
|
||||
_, err = c.Parse([]string{"--b=foo"})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRepeatableFlags(t *testing.T) {
|
||||
c := newTestApp()
|
||||
c.Flag("a", "a").String()
|
||||
c.Flag("b", "b").Strings()
|
||||
_, err := c.Parse([]string{"--a=foo", "--a=bar"})
|
||||
assert.Error(t, err)
|
||||
_, err = c.Parse([]string{"--b=foo", "--b=bar"})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestInvalidDefaultFlagValueErrors(t *testing.T) {
|
||||
c := newTestApp()
|
||||
c.Flag("foo", "foo").Default("a").Int()
|
||||
_, err := c.Parse([]string{})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestInvalidDefaultArgValueErrors(t *testing.T) {
|
||||
c := newTestApp()
|
||||
cmd := c.Command("cmd", "cmd")
|
||||
cmd.Arg("arg", "arg").Default("one").Int()
|
||||
_, err := c.Parse([]string{"cmd"})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestArgsRequiredAfterNonRequiredErrors(t *testing.T) {
|
||||
c := newTestApp()
|
||||
cmd := c.Command("cmd", "")
|
||||
cmd.Arg("a", "a").String()
|
||||
cmd.Arg("b", "b").Required().String()
|
||||
_, err := c.Parse([]string{"cmd"})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestArgsMultipleRequiredThenNonRequired(t *testing.T) {
|
||||
c := newTestApp().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(_ *Application, 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()
|
||||
f0 := a.Flag("some-flag", "")
|
||||
f0.Bool()
|
||||
f1 := a.Flag("some-other-flag", "").NoEnvar()
|
||||
f1.Bool()
|
||||
_, err := a.Parse([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "SOME_APP_SOME_FLAG", f0.envar)
|
||||
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(_ *Application, element *ParseElement, context *ParseContext) error {
|
||||
preValues = append(preValues, *element.Value)
|
||||
return nil
|
||||
})
|
||||
values := []string{}
|
||||
a.Action(func(_ *Application, element *ParseElement, context *ParseContext) error {
|
||||
values = append(values, *element.Value)
|
||||
return nil
|
||||
})
|
||||
}
|
60
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/args.go
vendored
Normal file
60
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/args.go
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
package 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
|
||||
}
|
82
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/args_test.go
vendored
Normal file
82
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/args_test.go
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
package 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)
|
||||
}
|
90
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/camelcase.go
vendored
Normal file
90
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/camelcase.go
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
package 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
|
||||
}
|
363
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/clause.go
vendored
Normal file
363
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/clause.go
vendored
Normal file
|
@ -0,0 +1,363 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/alecthomas/units"
|
||||
)
|
||||
|
||||
var (
|
||||
envVarValuesSeparator = "\r?\n"
|
||||
envVarValuesTrimmer = regexp.MustCompile(envVarValuesSeparator + "$")
|
||||
envVarValuesSplitter = regexp.MustCompile(envVarValuesSeparator)
|
||||
)
|
||||
|
||||
type Settings interface {
|
||||
SetValue(value Value)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// UsageAction adds a PreAction() that will display the given UsageContext.
|
||||
func (c *Clause) UsageAction(context *UsageContext) *Clause {
|
||||
c.PreAction(func(a *Application, e *ParseElement, c *ParseContext) error {
|
||||
a.UsageForContextWithTemplate(context, c)
|
||||
a.terminate(0)
|
||||
return nil
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Clause) UsageActionTemplate(template string) *Clause {
|
||||
return c.UsageAction(&UsageContext{Template: template})
|
||||
}
|
||||
|
||||
func (c *Clause) Action(action Action) *Clause {
|
||||
c.actions = append(c.actions, action)
|
||||
return c
|
||||
}
|
||||
|
||||
// PreAction callback executed
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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 app.DefaultEnvars().
|
||||
func (c *Clause) NoEnvar() *Clause {
|
||||
c.envar = ""
|
||||
c.noEnvar = true
|
||||
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() bool {
|
||||
haveDefault := len(c.defaultValues) > 0
|
||||
return c.required && !(haveDefault || c.HasEnvarValue())
|
||||
}
|
||||
|
||||
func (c *Clause) reset() {
|
||||
if c, ok := c.value.(cumulativeValue); ok {
|
||||
c.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Clause) setDefault() error {
|
||||
if c.HasEnvarValue() {
|
||||
c.reset()
|
||||
if v, ok := c.value.(cumulativeValue); !ok || !v.IsCumulative() {
|
||||
// Use the value as-is
|
||||
return c.value.Set(c.GetEnvarValue())
|
||||
}
|
||||
for _, value := range c.GetSplitEnvarValue() {
|
||||
if err := c.value.Set(value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
} else if len(c.defaultValues) > 0 {
|
||||
c.reset()
|
||||
for _, defaultValue := range c.defaultValues {
|
||||
if err := c.value.Set(defaultValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Clause) HasEnvarValue() bool {
|
||||
return c.GetEnvarValue() != ""
|
||||
}
|
||||
|
||||
func (c *Clause) GetEnvarValue() string {
|
||||
if c.noEnvar || c.envar == "" {
|
||||
return ""
|
||||
}
|
||||
return os.Getenv(c.envar)
|
||||
}
|
||||
|
||||
func (c *Clause) GetSplitEnvarValue() []string {
|
||||
values := make([]string, 0)
|
||||
|
||||
envarValue := c.GetEnvarValue()
|
||||
if envarValue == "" {
|
||||
return values
|
||||
}
|
||||
|
||||
// Split by new line to extract multiple values, if any.
|
||||
trimmed := envVarValuesTrimmer.ReplaceAllString(envarValue, "")
|
||||
values = append(values, envVarValuesSplitter.Split(trimmed, -1)...)
|
||||
return values
|
||||
}
|
||||
|
||||
func (c *Clause) SetValue(value Value) {
|
||||
c.value = value
|
||||
c.setDefault()
|
||||
}
|
||||
|
||||
// StringMap provides key=value parsing into a map.
|
||||
func (c *Clause) StringMap() (target *map[string]string) {
|
||||
target = &(map[string]string{})
|
||||
c.StringMapVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// URL provides a valid, parsed url.URL.
|
||||
func (c *Clause) URL() (target **url.URL) {
|
||||
target = new(*url.URL)
|
||||
c.URLVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
// StringMap provides key=value parsing into a map.
|
||||
func (c *Clause) StringMapVar(target *map[string]string) {
|
||||
c.SetValue(newStringMapValue(target))
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
// URL provides a valid, parsed url.URL.
|
||||
func (c *Clause) URLVar(target **url.URL) {
|
||||
c.SetValue(newURLValue(target))
|
||||
}
|
||||
|
||||
// URLList provides a parsed list of url.URL values.
|
||||
func (c *Clause) URLList() (target *[]*url.URL) {
|
||||
target = new([]*url.URL)
|
||||
c.URLListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
// URLListVar provides a parsed list of url.URL values.
|
||||
func (c *Clause) URLListVar(target *[]*url.URL) {
|
||||
c.SetValue(newURLListValue(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
|
||||
}
|
||||
|
||||
// EnumVar allows a value from a set of options.
|
||||
func (c *Clause) EnumsVar(target *[]string, options ...string) {
|
||||
c.SetValue(newEnumsFlag(target, options...))
|
||||
}
|
||||
|
||||
// A 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))
|
||||
}
|
95
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/clause_test.go
vendored
Normal file
95
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/clause_test.go
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
package 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, 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 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 TestDefaultScalarValueIsSetBeforeParse(t *testing.T) {
|
||||
app := newTestApp()
|
||||
v := app.Flag("a", "").Default("123").Int()
|
||||
assert.Equal(t, *v, 123)
|
||||
_, err := app.Parse([]string{"--a", "456"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, *v, 456)
|
||||
}
|
||||
|
||||
func TestDefaultCumulativeValueIsSetBeforeParse(t *testing.T) {
|
||||
app := newTestApp()
|
||||
v := app.Flag("a", "").Default("123", "456").Ints()
|
||||
assert.Equal(t, *v, []int{123, 456})
|
||||
_, err := app.Parse([]string{"--a", "789", "--a", "123"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, *v, []int{789, 123})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
320
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd.go
vendored
Normal file
320
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd.go
vendored
Normal file
|
@ -0,0 +1,320 @@
|
|||
package 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 <username> <email>"
|
||||
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(c.app.defaultEnvarPrefix()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.checkArgCommandMixing(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.argGroup.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.cmdGroup.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CmdClause) Hidden() *CmdClause {
|
||||
c.hidden = true
|
||||
return c
|
||||
}
|
48
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd/embedi18n/main.go
vendored
Normal file
48
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd/embedi18n/main.go
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package 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)
|
||||
}
|
133
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd/genvalues/main.go
vendored
Normal file
133
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd/genvalues/main.go
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
package 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}}
|
||||
// {{.|Plural}} accumulates {{.Type}} values into a slice.
|
||||
func (p *Clause) {{.|Plural}}() (target *[]{{.Type}}) {
|
||||
target = new([]{{.Type}})
|
||||
p.{{.|Plural}}Var(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) {{.|Plural}}Var(target *[]{{.Type}}) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return new{{.|Name}}Value(v.(*{{.Type}}))
|
||||
}))
|
||||
}
|
||||
|
||||
{{end}}
|
||||
`
|
||||
)
|
||||
|
||||
type Value struct {
|
||||
Name string `json:"name"`
|
||||
NoValueParser bool `json:"no_value_parser"`
|
||||
Type string `json:"type"`
|
||||
Parser string `json:"parser"`
|
||||
Format string `json:"format"`
|
||||
Plural string `json:"plural"`
|
||||
Help string `json:"help"`
|
||||
}
|
||||
|
||||
func fatalIfError(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
r, err := os.Open("values.json")
|
||||
fatalIfError(err)
|
||||
defer r.Close()
|
||||
|
||||
v := []Value{}
|
||||
err = json.NewDecoder(r).Decode(&v)
|
||||
fatalIfError(err)
|
||||
|
||||
valueName := func(v *Value) string {
|
||||
if v.Name != "" {
|
||||
return v.Name
|
||||
}
|
||||
return strings.Title(v.Type)
|
||||
}
|
||||
|
||||
t, err := template.New("genvalues").Funcs(template.FuncMap{
|
||||
"Lower": strings.ToLower,
|
||||
"Format": func(v *Value) string {
|
||||
if v.Format != "" {
|
||||
return v.Format
|
||||
}
|
||||
return "fmt.Sprintf(\"%v\", *f.v)"
|
||||
},
|
||||
"ValueName": func(v *Value) string {
|
||||
name := valueName(v)
|
||||
return strings.ToLower(name[0:1]) + name[1:] + "Value"
|
||||
},
|
||||
"Name": valueName,
|
||||
"Plural": func(v *Value) string {
|
||||
if v.Plural != "" {
|
||||
return v.Plural
|
||||
}
|
||||
return valueName(v) + "List"
|
||||
},
|
||||
}).Parse(tmpl)
|
||||
fatalIfError(err)
|
||||
|
||||
w, err := os.Create("values_generated.go")
|
||||
fatalIfError(err)
|
||||
defer w.Close()
|
||||
|
||||
err = t.Execute(w, v)
|
||||
fatalIfError(err)
|
||||
|
||||
err = exec.Command("goimports", "-w", "values_generated.go").Run()
|
||||
fatalIfError(err)
|
||||
}
|
398
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd_test.go
vendored
Normal file
398
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/cmd_test.go
vendored
Normal file
|
@ -0,0 +1,398 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func parseAndExecute(app *Application, context *ParseContext) (string, error) {
|
||||
if err := parse(context, app); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
selected, err := app.setValues(context)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return app.execute(context, selected)
|
||||
}
|
||||
|
||||
func complete(t *testing.T, app *Application, args ...string) []string {
|
||||
context, err := app.ParseContext(args)
|
||||
assert.NoError(t, err)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
completions := app.completionOptions(context)
|
||||
sort.Strings(completions)
|
||||
|
||||
return completions
|
||||
}
|
||||
|
||||
func TestNestedCommands(t *testing.T) {
|
||||
app := New("app", "")
|
||||
sub1 := app.Command("sub1", "")
|
||||
sub1.Flag("sub1", "")
|
||||
subsub1 := sub1.Command("sub1sub1", "")
|
||||
subsub1.Command("sub1sub1end", "")
|
||||
|
||||
sub2 := app.Command("sub2", "")
|
||||
sub2.Flag("sub2", "")
|
||||
sub2.Command("sub2sub1", "")
|
||||
|
||||
context := tokenize([]string{"sub1", "sub1sub1", "sub1sub1end"}, false)
|
||||
selected, err := parseAndExecute(app, context)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, context.EOL())
|
||||
assert.Equal(t, "sub1 sub1sub1 sub1sub1end", selected)
|
||||
}
|
||||
|
||||
func TestNestedCommandsWithArgs(t *testing.T) {
|
||||
app := New("app", "")
|
||||
cmd := app.Command("a", "").Command("b", "")
|
||||
a := cmd.Arg("a", "").String()
|
||||
b := cmd.Arg("b", "").String()
|
||||
context := tokenize([]string{"a", "b", "c", "d"}, false)
|
||||
selected, err := parseAndExecute(app, context)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, context.EOL())
|
||||
assert.Equal(t, "a b", selected)
|
||||
assert.Equal(t, "c", *a)
|
||||
assert.Equal(t, "d", *b)
|
||||
}
|
||||
|
||||
func TestNestedCommandsWithFlags(t *testing.T) {
|
||||
app := New("app", "")
|
||||
cmd := app.Command("a", "").Command("b", "")
|
||||
a := cmd.Flag("aaa", "").Short('a').String()
|
||||
b := cmd.Flag("bbb", "").Short('b').String()
|
||||
err := app.init()
|
||||
assert.NoError(t, err)
|
||||
context := tokenize(strings.Fields("a b --aaa x -b x"), false)
|
||||
selected, err := parseAndExecute(app, context)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, context.EOL())
|
||||
assert.Equal(t, "a b", selected)
|
||||
assert.Equal(t, "x", *a)
|
||||
assert.Equal(t, "x", *b)
|
||||
}
|
||||
|
||||
func TestNestedCommandWithMergedFlags(t *testing.T) {
|
||||
app := New("app", "")
|
||||
cmd0 := app.Command("a", "")
|
||||
cmd0f0 := cmd0.Flag("aflag", "").Bool()
|
||||
// cmd1 := app.Command("b", "")
|
||||
// cmd1f0 := cmd0.Flag("bflag", "").Bool()
|
||||
cmd00 := cmd0.Command("aa", "")
|
||||
cmd00f0 := cmd00.Flag("aaflag", "").Bool()
|
||||
err := app.init()
|
||||
assert.NoError(t, err)
|
||||
context := tokenize(strings.Fields("a aa --aflag --aaflag"), false)
|
||||
selected, err := parseAndExecute(app, context)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, *cmd0f0)
|
||||
assert.True(t, *cmd00f0)
|
||||
assert.Equal(t, "a aa", selected)
|
||||
}
|
||||
|
||||
func TestNestedCommandWithDuplicateFlagErrors(t *testing.T) {
|
||||
app := New("app", "")
|
||||
app.Flag("test", "").Bool()
|
||||
app.Command("cmd0", "").Flag("test", "").Bool()
|
||||
err := app.init()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNestedCommandWithArgAndMergedFlags(t *testing.T) {
|
||||
app := New("app", "")
|
||||
cmd0 := app.Command("a", "")
|
||||
cmd0f0 := cmd0.Flag("aflag", "").Bool()
|
||||
// cmd1 := app.Command("b", "")
|
||||
// cmd1f0 := cmd0.Flag("bflag", "").Bool()
|
||||
cmd00 := cmd0.Command("aa", "")
|
||||
cmd00a0 := cmd00.Arg("arg", "").String()
|
||||
cmd00f0 := cmd00.Flag("aaflag", "").Bool()
|
||||
err := app.init()
|
||||
assert.NoError(t, err)
|
||||
context := tokenize(strings.Fields("a aa hello --aflag --aaflag"), false)
|
||||
selected, err := parseAndExecute(app, context)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, *cmd0f0)
|
||||
assert.True(t, *cmd00f0)
|
||||
assert.Equal(t, "a aa", selected)
|
||||
assert.Equal(t, "hello", *cmd00a0)
|
||||
}
|
||||
|
||||
func TestDefaultSubcommandEOL(t *testing.T) {
|
||||
app := newTestApp()
|
||||
c0 := app.Command("c0", "").Default()
|
||||
c0.Command("c01", "").Default()
|
||||
c0.Command("c02", "")
|
||||
|
||||
cmd, err := app.Parse([]string{"c0"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "c0 c01", cmd)
|
||||
}
|
||||
|
||||
func TestDefaultSubcommandWithArg(t *testing.T) {
|
||||
app := newTestApp()
|
||||
c0 := app.Command("c0", "").Default()
|
||||
c01 := c0.Command("c01", "").Default()
|
||||
c012 := c01.Command("c012", "").Default()
|
||||
a0 := c012.Arg("a0", "").String()
|
||||
c0.Command("c02", "")
|
||||
|
||||
cmd, err := app.Parse([]string{"c0", "hello"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "c0 c01 c012", cmd)
|
||||
assert.Equal(t, "hello", *a0)
|
||||
}
|
||||
|
||||
func TestDefaultSubcommandWithFlags(t *testing.T) {
|
||||
app := newTestApp()
|
||||
c0 := app.Command("c0", "").Default()
|
||||
_ = c0.Flag("f0", "").Int()
|
||||
c0c1 := c0.Command("c1", "").Default()
|
||||
c0c1f1 := c0c1.Flag("f1", "").Int()
|
||||
selected, err := app.Parse([]string{"--f1=2"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "c0 c1", selected)
|
||||
assert.Equal(t, 2, *c0c1f1)
|
||||
_, err = app.Parse([]string{"--f2"})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMultipleDefaultCommands(t *testing.T) {
|
||||
app := newTestApp()
|
||||
app.Command("c0", "").Default()
|
||||
app.Command("c1", "").Default()
|
||||
_, err := app.Parse([]string{})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAliasedCommand(t *testing.T) {
|
||||
app := newTestApp()
|
||||
app.Command("one", "").Alias("two")
|
||||
selected, _ := app.Parse([]string{"one"})
|
||||
assert.Equal(t, "one", selected)
|
||||
selected, _ = app.Parse([]string{"two"})
|
||||
assert.Equal(t, "one", selected)
|
||||
// 2 due to "help" and "one"
|
||||
assert.Equal(t, 2, len(app.Model().FlattenedCommands()))
|
||||
}
|
||||
|
||||
func TestDuplicateAlias(t *testing.T) {
|
||||
app := newTestApp()
|
||||
app.Command("one", "")
|
||||
app.Command("two", "").Alias("one")
|
||||
_, err := app.Parse([]string{"one"})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFlagCompletion(t *testing.T) {
|
||||
app := newTestApp()
|
||||
app.Command("one", "")
|
||||
two := app.Command("two", "")
|
||||
two.Flag("flag-1", "")
|
||||
two.Flag("flag-2", "").HintOptions("opt1", "opt2", "opt3")
|
||||
two.Flag("flag-3", "")
|
||||
|
||||
cases := []struct {
|
||||
target cmdMixin
|
||||
flagName string
|
||||
flagValue string
|
||||
expectedFlagMatch bool
|
||||
expectedOptionMatch bool
|
||||
expectedFlags []string
|
||||
}{
|
||||
{
|
||||
// Test top level flags
|
||||
target: app.cmdMixin,
|
||||
flagName: "",
|
||||
flagValue: "",
|
||||
expectedFlagMatch: false,
|
||||
expectedOptionMatch: false,
|
||||
expectedFlags: []string{"--help"},
|
||||
},
|
||||
{
|
||||
// Test no flag passed
|
||||
target: two.cmdMixin,
|
||||
flagName: "",
|
||||
flagValue: "",
|
||||
expectedFlagMatch: false,
|
||||
expectedOptionMatch: false,
|
||||
expectedFlags: []string{"--flag-1", "--flag-2", "--flag-3"},
|
||||
},
|
||||
{
|
||||
// Test an incomplete flag. Should still give all options as if the flag wasn't given at all.
|
||||
target: two.cmdMixin,
|
||||
flagName: "flag-",
|
||||
flagValue: "",
|
||||
expectedFlagMatch: false,
|
||||
expectedOptionMatch: false,
|
||||
expectedFlags: []string{"--flag-1", "--flag-2", "--flag-3"},
|
||||
},
|
||||
{
|
||||
// Test with a complete flag. Should show available choices for the flag
|
||||
// This flag has no options. No options should be produced.
|
||||
// Should also report an option was matched
|
||||
target: two.cmdMixin,
|
||||
flagName: "flag-1",
|
||||
flagValue: "",
|
||||
expectedFlagMatch: true,
|
||||
expectedOptionMatch: true,
|
||||
expectedFlags: []string(nil),
|
||||
},
|
||||
{
|
||||
// Test with a complete flag. Should show available choices for the flag
|
||||
target: two.cmdMixin,
|
||||
flagName: "flag-2",
|
||||
flagValue: "",
|
||||
expectedFlagMatch: true,
|
||||
expectedOptionMatch: false,
|
||||
expectedFlags: []string{"opt1", "opt2", "opt3"},
|
||||
},
|
||||
{
|
||||
// Test with a complete flag and complete option for that flag.
|
||||
target: two.cmdMixin,
|
||||
flagName: "flag-2",
|
||||
flagValue: "opt1",
|
||||
expectedFlagMatch: true,
|
||||
expectedOptionMatch: true,
|
||||
expectedFlags: []string{"opt1", "opt2", "opt3"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
choices, flagMatch, optionMatch := c.target.FlagCompletion(c.flagName, c.flagValue)
|
||||
assert.Equal(t, c.expectedFlags, choices, "Test case %d: expectedFlags != actual flags", i+1)
|
||||
assert.Equal(t, c.expectedFlagMatch, flagMatch, "Test case %d: expectedFlagMatch != flagMatch", i+1)
|
||||
assert.Equal(t, c.expectedOptionMatch, optionMatch, "Test case %d: expectedOptionMatch != optionMatch", i+1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCmdCompletion(t *testing.T) {
|
||||
app := newTestApp()
|
||||
app.Command("one", "")
|
||||
two := app.Command("two", "")
|
||||
two.Command("sub1", "")
|
||||
two.Command("sub2", "")
|
||||
|
||||
assert.Equal(t, []string{"help", "one", "two"}, complete(t, app))
|
||||
assert.Equal(t, []string{"sub1", "sub2"}, complete(t, app, "two"))
|
||||
}
|
||||
|
||||
func TestHiddenCmdCompletion(t *testing.T) {
|
||||
app := newTestApp()
|
||||
|
||||
// top level visible & hidden cmds, with no sub-cmds
|
||||
app.Command("visible1", "")
|
||||
app.Command("hidden1", "").Hidden()
|
||||
|
||||
// visible cmd with visible & hidden sub-cmds
|
||||
visible2 := app.Command("visible2", "")
|
||||
visible2.Command("visible2-visible", "")
|
||||
visible2.Command("visible2-hidden", "").Hidden()
|
||||
|
||||
// hidden cmd with visible & hidden sub-cmds
|
||||
hidden2 := app.Command("hidden2", "").Hidden()
|
||||
hidden2.Command("hidden2-visible", "")
|
||||
hidden2.Command("hidden2-hidden", "").Hidden()
|
||||
|
||||
// Only top level visible cmds should show
|
||||
assert.Equal(t, []string{"help", "visible1", "visible2"}, complete(t, app))
|
||||
|
||||
// Only visible sub-cmds should show
|
||||
assert.Equal(t, []string{"visible2-visible"}, complete(t, app, "visible2"))
|
||||
|
||||
// Hidden commands should still complete visible sub-cmds
|
||||
assert.Equal(t, []string{"hidden2-visible"}, complete(t, app, "hidden2"))
|
||||
}
|
||||
|
||||
func TestDefaultCmdCompletion(t *testing.T) {
|
||||
app := newTestApp()
|
||||
|
||||
cmd1 := app.Command("cmd1", "")
|
||||
|
||||
cmd1Sub1 := cmd1.Command("cmd1-sub1", "")
|
||||
cmd1Sub1.Arg("cmd1-sub1-arg1", "").HintOptions("cmd1-arg1").String()
|
||||
|
||||
cmd2 := app.Command("cmd2", "").Default()
|
||||
|
||||
cmd2.Command("cmd2-sub1", "")
|
||||
|
||||
cmd2Sub2 := cmd2.Command("cmd2-sub2", "").Default()
|
||||
|
||||
cmd2Sub2Sub1 := cmd2Sub2.Command("cmd2-sub2-sub1", "").Default()
|
||||
cmd2Sub2Sub1.Arg("cmd2-sub2-sub1-arg1", "").HintOptions("cmd2-sub2-sub1-arg1").String()
|
||||
cmd2Sub2Sub1.Arg("cmd2-sub2-sub1-arg2", "").HintOptions("cmd2-sub2-sub1-arg2").String()
|
||||
|
||||
// Without args, should get:
|
||||
// - root cmds (incuding 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)
|
||||
}
|
34
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/completions.go
vendored
Normal file
34
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/completions.go
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package 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
|
||||
}
|
78
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/completions_test.go
vendored
Normal file
78
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/completions_test.go
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
package 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)
|
||||
}
|
68
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/doc.go
vendored
Normal file
68
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/doc.go
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Package kingpin provides command line interfaces like this:
|
||||
//
|
||||
// $ chat
|
||||
// usage: chat [<flags>] <command> [<flags>] [<args> ...]
|
||||
//
|
||||
// Flags:
|
||||
// --debug enable debug mode
|
||||
// --help Show help.
|
||||
// --server=127.0.0.1 server address
|
||||
//
|
||||
// Commands:
|
||||
// help <command>
|
||||
// Show help for a command.
|
||||
//
|
||||
// post [<flags>] <channel>
|
||||
// Post a message to a channel.
|
||||
//
|
||||
// register <nick> <name>
|
||||
// Register a new user.
|
||||
//
|
||||
// $ chat help post
|
||||
// usage: chat [<flags>] post [<flags>] <channel> [<text>]
|
||||
//
|
||||
// Post a message to a channel.
|
||||
//
|
||||
// Flags:
|
||||
// --image=IMAGE image to post
|
||||
//
|
||||
// Args:
|
||||
// <channel> channel to post to
|
||||
// [<text>] text to post
|
||||
// $ chat post --image=~/Downloads/owls.jpg pics
|
||||
//
|
||||
// From 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
|
46
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/examples_test.go
vendored
Normal file
46
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/examples_test.go
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HTTPHeaderValue http.Header
|
||||
|
||||
func (h *HTTPHeaderValue) Set(value string) error {
|
||||
parts := strings.SplitN(value, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("expected HEADER:VALUE got '%s'", value)
|
||||
}
|
||||
(*http.Header)(h).Add(parts[0], parts[1])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HTTPHeaderValue) Get() interface{} {
|
||||
return (http.Header)(*h)
|
||||
}
|
||||
|
||||
func (h *HTTPHeaderValue) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func HTTPHeader(s Settings) (target *http.Header) {
|
||||
target = new(http.Header)
|
||||
s.SetValue((*HTTPHeaderValue)(target))
|
||||
return
|
||||
}
|
||||
|
||||
// This example ilustrates how to define custom parsers. HTTPHeader
|
||||
// cumulatively parses each encountered --header flag into a http.Header struct.
|
||||
func ExampleValue() {
|
||||
var (
|
||||
curl = New("curl", "transfer a URL")
|
||||
headers = HTTPHeader(curl.Flag("headers", "Add HTTP headers to the request.").Short('H').PlaceHolder("HEADER:VALUE"))
|
||||
)
|
||||
|
||||
curl.Parse([]string{"-H Content-Type:application/octet-stream"})
|
||||
for key, value := range *headers {
|
||||
fmt.Printf("%s = %s\n", key, value)
|
||||
}
|
||||
}
|
139
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/flags.go
vendored
Normal file
139
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/flags.go
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
package 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(defaultEnvarPrefix string) error {
|
||||
if err := f.checkDuplicates(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, flag := range f.long {
|
||||
if defaultEnvarPrefix != "" && !flag.noEnvar && flag.envar == "" {
|
||||
flag.envar = envarTransform(defaultEnvarPrefix + "_" + flag.name)
|
||||
}
|
||||
if err := flag.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
if flag.shorthand != 0 {
|
||||
f.short[string(flag.shorthand)] = flag
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *flagGroup) checkDuplicates() error {
|
||||
seenShort := map[rune]bool{}
|
||||
seenLong := map[string]bool{}
|
||||
for _, flag := range f.flagOrder {
|
||||
if flag.shorthand != 0 {
|
||||
if _, ok := seenShort[flag.shorthand]; ok {
|
||||
return 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]
|
||||
} 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 fb, ok := flag.value.(boolFlag); ok && fb.IsBoolFlag() {
|
||||
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
|
||||
}
|
328
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/flags_test.go
vendored
Normal file
328
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/flags_test.go
vendored
Normal file
|
@ -0,0 +1,328 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"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 TestNoBool(t *testing.T) {
|
||||
app := newTestApp()
|
||||
f := app.Flag("b", "").Default("true")
|
||||
b := f.Bool()
|
||||
_, 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 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\n456\n")
|
||||
_, err := app.Parse([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"123", "456"}, *a)
|
||||
}
|
||||
|
||||
func TestFlagMultipleValuesDefaultEnvarWindows(t *testing.T) {
|
||||
app := newTestApp()
|
||||
a := app.Flag("a", "").Envar("TEST_MULTIPLE_VALUES").Strings()
|
||||
os.Setenv("TEST_MULTIPLE_VALUES", "123\r\n456\r\n")
|
||||
_, err := app.Parse([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{"123", "456"}, *a)
|
||||
}
|
||||
|
||||
func TestFlagMultipleValuesDefaultEnvarNonRepeatable(t *testing.T) {
|
||||
c := newTestApp()
|
||||
a := c.Flag("foo", "foo").Envar("TEST_MULTIPLE_VALUES_NON_REPEATABLE").String()
|
||||
os.Setenv("TEST_MULTIPLE_VALUES_NON_REPEATABLE", "123\n456")
|
||||
_, err := c.Parse([]string{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "123\n456", *a)
|
||||
}
|
||||
|
||||
func TestFlagHintAction(t *testing.T) {
|
||||
c := newTestApp()
|
||||
|
||||
action := func() []string {
|
||||
return []string{"opt1", "opt2"}
|
||||
}
|
||||
|
||||
a := c.Flag("foo", "foo").HintAction(action)
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
}
|
||||
|
||||
func TestFlagHintOptions(t *testing.T) {
|
||||
c := newTestApp()
|
||||
|
||||
a := c.Flag("foo", "foo").HintOptions("opt1", "opt2")
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
}
|
||||
|
||||
func TestFlagEnumVar(t *testing.T) {
|
||||
c := newTestApp()
|
||||
var bar string
|
||||
|
||||
a := c.Flag("foo", "foo")
|
||||
a.Enum("opt1", "opt2")
|
||||
b := c.Flag("bar", "bar")
|
||||
b.EnumVar(&bar, "opt3", "opt4")
|
||||
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
|
||||
args = b.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt3", "opt4"}, args)
|
||||
}
|
||||
|
||||
func TestMultiHintOptions(t *testing.T) {
|
||||
c := newTestApp()
|
||||
|
||||
a := c.Flag("foo", "foo").HintOptions("opt1").HintOptions("opt2")
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
}
|
||||
func TestMultiHintActions(t *testing.T) {
|
||||
c := newTestApp()
|
||||
|
||||
a := c.Flag("foo", "foo").
|
||||
HintAction(func() []string {
|
||||
return []string{"opt1"}
|
||||
}).
|
||||
HintAction(func() []string {
|
||||
return []string{"opt2"}
|
||||
})
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
}
|
||||
|
||||
func TestCombinationHintActionsOptions(t *testing.T) {
|
||||
c := newTestApp()
|
||||
|
||||
a := c.Flag("foo", "foo").HintAction(func() []string {
|
||||
return []string{"opt1"}
|
||||
}).HintOptions("opt2")
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
}
|
||||
|
||||
func TestCombinationEnumActions(t *testing.T) {
|
||||
c := newTestApp()
|
||||
var foo string
|
||||
|
||||
a := c.Flag("foo", "foo").
|
||||
HintAction(func() []string {
|
||||
return []string{"opt1", "opt2"}
|
||||
})
|
||||
a.Enum("opt3", "opt4")
|
||||
|
||||
b := c.Flag("bar", "bar").
|
||||
HintAction(func() []string {
|
||||
return []string{"opt5", "opt6"}
|
||||
})
|
||||
b.EnumVar(&foo, "opt3", "opt4")
|
||||
|
||||
// Provided HintActions should override automatically generated Enum options.
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
|
||||
args = b.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt5", "opt6"}, args)
|
||||
}
|
||||
|
||||
func TestCombinationEnumOptions(t *testing.T) {
|
||||
c := newTestApp()
|
||||
var foo string
|
||||
|
||||
a := c.Flag("foo", "foo").HintOptions("opt1", "opt2")
|
||||
a.Enum("opt3", "opt4")
|
||||
|
||||
b := c.Flag("bar", "bar").HintOptions("opt5", "opt6")
|
||||
b.EnumVar(&foo, "opt3", "opt4")
|
||||
|
||||
// Provided HintOptions should override automatically generated Enum options.
|
||||
args := a.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt1", "opt2"}, args)
|
||||
|
||||
args = b.resolveCompletions()
|
||||
assert.Equal(t, []string{"opt5", "opt6"}, args)
|
||||
|
||||
}
|
96
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/global.go
vendored
Normal file
96
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/global.go
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
package 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)
|
||||
}
|
9
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/guesswidth.go
vendored
Normal file
9
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/guesswidth.go
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build appengine !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd
|
||||
|
||||
package kingpin
|
||||
|
||||
import "io"
|
||||
|
||||
func guessWidth(w io.Writer) int {
|
||||
return 80
|
||||
}
|
38
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/guesswidth_unix.go
vendored
Normal file
38
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/guesswidth_unix.go
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// +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
|
||||
}
|
16
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n/README.md
vendored
Normal file
16
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n/README.md
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
# 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 `<lang>.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.
|
230
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n/en-AU.all.json
vendored
Normal file
230
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n/en-AU.all.json
vendored
Normal file
|
@ -0,0 +1,230 @@
|
|||
[
|
||||
{
|
||||
"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:"
|
||||
}
|
||||
]
|
30
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n/fr.all.json
vendored
Normal file
30
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n/fr.all.json
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
[
|
||||
{
|
||||
"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."
|
||||
}
|
||||
]
|
3
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_en_AU.go
vendored
Normal file
3
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_en_AU.go
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
package 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\xe8<h3\nrPb%5\xeb\xe0Ӵ\xb4\xd9\xe3I\x9br\xfd%@\t\xa1\xdcR\x88!\x12\x12}\x87\x0f\xe5\n\xabU\xbe\f\x8dJH\xb9\xc6X\u007f@\xe5K\xd1(R\nu\xb7\x85\x9dP\x1d¶s\xfd\xb8a4\x82\xa9\xce鸆ڜ\xb6\xe0\a~\xdf.\xa2\xa2M\x85\x11\x90S\xe9\xd7x\x18;YF\xe7J|j\xb1\xf0X\xc2\xef\xf7\u007f\xfd\xf4\xe7\xdd\xc3\xd7\xfb\xb1\xd3\xc8a\xcd\x00\xc6\x05Og<\xdc\xda\xfd\x96M\x10\x8d\x83\xe3\xc2\xc7c\x1fj:XN\x1d\xaf\f )\xf8\xdeV\x98kC\x9f\xdb XlQx\xb6'\xe5 II\xa9wB\xc9\x12\xbe\xfe\xf1\xb0N\xfe/&8J|\xec\x96!\xed\xf3Q9ϯaHS\xb8R\x9dԵ¡\"\x12\xda\xd3\xf9\xb2\xec\r\xc58\xce`\x10x\xdfU#%\xfd\tB\xd2\xe0\xa9\a2z\xe7u\x12\xbe5\x16\xc17B\xf7\x8d\x85\xb8\xb2\xfaqƥ\xf7\xfc\x02\"\xdaP\xe8s\x0e\x15\x16\x1e\xc4\x18o\xaa\x8c2\xceE\x93\xd2ڀ\u007fn\xf1x\xff\xf6\x1b1:9\xb0\xc0\xfa\x06n\x1e\xbd\x95\xba^,\x97\x8c\x85\xa9,\xa4\x95V\xf8\xe6͡(\r\xba~\x96\xe9\xd3\xc8H\xa7P\xa4\x94\xc5\xff:iǝo\xcc\x10\xc0\xc7Y\x85Q\x9d@\x90g <\xb7:]\x82\xa8<Z\xd0F\xaf\x8e!\xb9\x0e\"\fq\vC\u007f\x1c\xb7\x8ba2}[\xad\xbe\x11\x1e\xf6R)иC\x1b\xbag\xe7\xd2\xee>G\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")
|
3
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_fr.go
vendored
Normal file
3
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_fr.go
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
package 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")
|
82
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_init.go
vendored
Normal file
82
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_init.go
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
package 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{}
|
17
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_init_test.go
vendored
Normal file
17
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/i18n_init_test.go
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
package 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."),
|
||||
)
|
||||
}
|
294
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/model.go
vendored
Normal file
294
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/model.go
vendored
Normal file
|
@ -0,0 +1,294 @@
|
|||
// 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() {
|
||||
out = append(out, fmt.Sprintf("--[no-]%s", flag.Name))
|
||||
} else {
|
||||
out = append(out, fmt.Sprintf("--%s=%s", flag.Name, flag.FormatPlaceHolder()))
|
||||
}
|
||||
}
|
||||
}
|
||||
if count != len(out) {
|
||||
out = append(out, T("[<flags>]"))
|
||||
}
|
||||
return strings.Join(out, " ")
|
||||
}
|
||||
|
||||
type ClauseModel struct {
|
||||
Name string
|
||||
Help string
|
||||
Short rune
|
||||
Default []string
|
||||
Envar 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 {
|
||||
if fl, ok := c.Value.(boolFlag); ok {
|
||||
return fl.IsBoolFlag()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
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 += " <command>"
|
||||
}
|
||||
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,
|
||||
Envar: f.envar,
|
||||
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
|
||||
}
|
48
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/model_test.go
vendored
Normal file
48
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/model_test.go
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"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 <arg>", cmdModel.CmdSummary())
|
||||
}
|
||||
|
||||
func TestModelValue(t *testing.T) {
|
||||
app := newTestApp()
|
||||
value := app.Flag("test", "").Bool()
|
||||
*value = true
|
||||
model := app.Model()
|
||||
flag := model.FlagByName("test")
|
||||
fmt.Println(reflect.TypeOf(flag.Value))
|
||||
assert.Equal(t, "true", flag.Value.String())
|
||||
}
|
423
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/parser.go
vendored
Normal file
423
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/parser.go
vendored
Normal file
|
@ -0,0 +1,423 @@
|
|||
package 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("<EOL>")
|
||||
}
|
||||
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("<EOL>")
|
||||
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 {
|
||||
SelectedCommand *CmdClause
|
||||
ignoreDefault bool
|
||||
argsOnly bool
|
||||
peek []*Token
|
||||
argi int // Index of current command-line arg we're processing.
|
||||
args []string
|
||||
rawArgs []string
|
||||
flags *flagGroup
|
||||
arguments *argGroup
|
||||
argumenti int // Cursor into arguments
|
||||
// Flags, arguments and commands encountered and collected during parse.
|
||||
Elements ParseElements
|
||||
}
|
||||
|
||||
// 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) *ParseContext {
|
||||
return &ParseContext{
|
||||
ignoreDefault: ignoreDefault,
|
||||
args: args,
|
||||
rawArgs: args,
|
||||
flags: newFlagGroup(),
|
||||
arguments: newArgGroup(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ParseContext) mergeFlags(flags *flagGroup) {
|
||||
for _, flag := range flags.flagOrder {
|
||||
if flag.shorthand != 0 {
|
||||
p.flags.short[string(flag.shorthand)] = flag
|
||||
}
|
||||
p.flags.long[flag.name] = flag
|
||||
p.flags.flagOrder = append(p.flags.flagOrder, flag)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ParseContext) mergeArgs(args *argGroup) {
|
||||
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 fb, ok := flag.value.(boolFlag); ok && fb.IsBoolFlag() {
|
||||
// Bool short flag.
|
||||
} else {
|
||||
// Short flag with combined argument: -fARG
|
||||
token := &Token{p.argi, TokenShort, short}
|
||||
if len(arg) > 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
|
||||
}
|
47
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/parser_test.go
vendored
Normal file
47
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/parser_test.go
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package 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)
|
||||
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))
|
||||
}
|
196
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/struct.go
vendored
Normal file
196
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/struct.go
vendored
Normal file
|
@ -0,0 +1,196 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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 {
|
||||
return fmt.Errorf("expected a struct but received " + reflect.TypeOf(v).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(*Application, *ParseElement, *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(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(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
|
||||
}
|
151
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/struct_test.go
vendored
Normal file
151
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/struct_test.go
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
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(app *Application, 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)
|
||||
}
|
171
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/templates.go
vendored
Normal file
171
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/templates.go
vendored
Normal file
|
@ -0,0 +1,171 @@
|
|||
package 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}} <command> [<args> ...]{{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}} <command> [<args> ...]{{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}}
|
||||
`
|
273
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/usage.go
vendored
Normal file
273
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/usage.go
vendored
Normal file
|
@ -0,0 +1,273 @@
|
|||
package 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, " ")
|
||||
}
|
||||
|
||||
func formatFlag(haveShort bool, flag *ClauseModel) string {
|
||||
flagString := ""
|
||||
if flag.Short != 0 {
|
||||
flagString += fmt.Sprintf("-%c, --%s", flag.Short, flag.Name)
|
||||
} else {
|
||||
if haveShort {
|
||||
flagString += fmt.Sprintf(" --%s", flag.Name)
|
||||
} else {
|
||||
flagString += fmt.Sprintf("--%s", flag.Name)
|
||||
}
|
||||
}
|
||||
if !flag.IsBoolFlag() {
|
||||
flagString += fmt.Sprintf("=%s", flag.FormatPlaceHolder())
|
||||
}
|
||||
if v, ok := flag.Value.(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
|
||||
}
|
148
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/usage_test.go
vendored
Normal file
148
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/usage_test.go
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
package 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 [<flags>] <command>
|
||||
|
||||
Test
|
||||
|
||||
|
||||
Flags:
|
||||
--help Show context-sensitive help.
|
||||
|
||||
Commands:
|
||||
help [<command> ...]
|
||||
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 [<flags>] <command>
|
||||
|
||||
Test
|
||||
|
||||
|
||||
Flags:
|
||||
--help Show context-sensitive help.
|
||||
|
||||
Commands:
|
||||
help [<command> ...]
|
||||
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)
|
||||
}
|
365
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values.go
vendored
Normal file
365
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values.go
vendored
Normal file
|
@ -0,0 +1,365 @@
|
|||
package kingpin
|
||||
|
||||
//go:generate go run ./cmd/genvalues/main.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"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-<x> negation counterpart.
|
||||
type boolFlag interface {
|
||||
Value
|
||||
IsBoolFlag() bool
|
||||
}
|
||||
|
||||
// Optional interface for values that cumulatively consume all remaining
|
||||
// input.
|
||||
type cumulativeValue interface {
|
||||
Value
|
||||
Reset()
|
||||
IsCumulative() bool
|
||||
}
|
||||
|
||||
type accumulator struct {
|
||||
element func(value interface{}) Value
|
||||
typ reflect.Type
|
||||
slice reflect.Value
|
||||
}
|
||||
|
||||
// Use reflection to accumulate values into a slice.
|
||||
//
|
||||
// target := []string{}
|
||||
// newAccumulator(&target, func (value interface{}) Value {
|
||||
// return newStringValue(value.(*string))
|
||||
// })
|
||||
func newAccumulator(slice interface{}, element func(value interface{}) Value) *accumulator {
|
||||
typ := reflect.TypeOf(slice)
|
||||
if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Slice {
|
||||
panic(T("expected a pointer to a slice"))
|
||||
}
|
||||
return &accumulator{
|
||||
element: element,
|
||||
typ: typ.Elem().Elem(),
|
||||
slice: reflect.ValueOf(slice),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *accumulator) String() string {
|
||||
out := []string{}
|
||||
s := a.slice.Elem()
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
out = append(out, a.element(s.Index(i).Addr().Interface()).String())
|
||||
}
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
|
||||
func (a *accumulator) Set(value string) error {
|
||||
e := reflect.New(a.typ)
|
||||
if err := a.element(e.Interface()).Set(value); err != nil {
|
||||
return err
|
||||
}
|
||||
slice := reflect.Append(a.slice.Elem(), e.Elem())
|
||||
a.slice.Elem().Set(slice)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *accumulator) Get() interface{} {
|
||||
return a.slice.Interface()
|
||||
}
|
||||
|
||||
func (a *accumulator) IsCumulative() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (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) IsBoolFlag() bool { return true }
|
||||
|
||||
// -- map[string]string Value
|
||||
type stringMapValue map[string]string
|
||||
|
||||
func newStringMapValue(p *map[string]string) *stringMapValue {
|
||||
return (*stringMapValue)(p)
|
||||
}
|
||||
|
||||
var stringMapRegex = regexp.MustCompile("[:=]")
|
||||
|
||||
func (s *stringMapValue) Set(value string) error {
|
||||
parts := stringMapRegex.Split(value, 2)
|
||||
if len(parts) != 2 {
|
||||
return TError("expected KEY=VALUE got '{{.Arg0}}'", V{"Arg0": value})
|
||||
}
|
||||
(*s)[parts[0]] = parts[1]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stringMapValue) Get() interface{} {
|
||||
return (map[string]string)(*s)
|
||||
}
|
||||
|
||||
func (s *stringMapValue) String() string {
|
||||
return fmt.Sprintf("%s", map[string]string(*s))
|
||||
}
|
||||
|
||||
func (s *stringMapValue) IsCumulative() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *stringMapValue) Reset() {
|
||||
*s = 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
|
||||
}
|
||||
|
||||
// -- url.URL Value
|
||||
type urlValue struct {
|
||||
u **url.URL
|
||||
}
|
||||
|
||||
func newURLValue(p **url.URL) *urlValue {
|
||||
return &urlValue{p}
|
||||
}
|
||||
|
||||
func (u *urlValue) Set(value string) error {
|
||||
url, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return TError("invalid URL: {{.Arg0}}", V{"Arg0": err})
|
||||
}
|
||||
*u.u = url
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *urlValue) Get() interface{} {
|
||||
return (*url.URL)(*u.u)
|
||||
}
|
||||
|
||||
func (u *urlValue) String() string {
|
||||
if *u.u == nil {
|
||||
return T("<nil>")
|
||||
}
|
||||
return (*u.u).String()
|
||||
}
|
||||
|
||||
// -- []*url.URL Value
|
||||
type urlListValue []*url.URL
|
||||
|
||||
func newURLListValue(p *[]*url.URL) *urlListValue {
|
||||
return (*urlListValue)(p)
|
||||
}
|
||||
|
||||
func (u *urlListValue) Set(value string) error {
|
||||
url, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return TError("invalid URL: {{.Arg0}}", V{"Arg0": err})
|
||||
}
|
||||
*u = append(*u, url)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *urlListValue) Get() interface{} {
|
||||
return ([]*url.URL)(*u)
|
||||
}
|
||||
|
||||
func (u *urlListValue) String() string {
|
||||
out := []string{}
|
||||
for _, url := range *u {
|
||||
out = append(out, url.String())
|
||||
}
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func newEnumsFlag(target *[]string, options ...string) *enumsValue {
|
||||
return &enumsValue{
|
||||
value: target,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *enumsValue) Set(value string) error {
|
||||
for _, v := range e.options {
|
||||
if v == value {
|
||||
*e.value = append(*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 *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 }
|
22
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values.json
vendored
Normal file
22
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values.json
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{"type": "bool", "parser": "strconv.ParseBool(s)"},
|
||||
{"type": "string", "parser": "s, error(nil)", "format": "string(*f.v)", "plural": "Strings"},
|
||||
{"type": "uint", "parser": "strconv.ParseUint(s, 0, 64)", "plural": "Uints"},
|
||||
{"type": "uint8", "parser": "strconv.ParseUint(s, 0, 8)"},
|
||||
{"type": "uint16", "parser": "strconv.ParseUint(s, 0, 16)"},
|
||||
{"type": "uint32", "parser": "strconv.ParseUint(s, 0, 32)"},
|
||||
{"type": "uint64", "parser": "strconv.ParseUint(s, 0, 64)"},
|
||||
{"type": "int", "parser": "strconv.ParseFloat(s, 64)", "plural": "Ints"},
|
||||
{"type": "int8", "parser": "strconv.ParseInt(s, 0, 8)"},
|
||||
{"type": "int16", "parser": "strconv.ParseInt(s, 0, 16)"},
|
||||
{"type": "int32", "parser": "strconv.ParseInt(s, 0, 32)"},
|
||||
{"type": "int64", "parser": "strconv.ParseInt(s, 0, 64)"},
|
||||
{"type": "float64", "parser": "strconv.ParseFloat(s, 64)"},
|
||||
{"type": "float32", "parser": "strconv.ParseFloat(s, 32)"},
|
||||
{"name": "ExistingFile", "type": "string", "plural": "ExistingFiles", "no_value_parser": true},
|
||||
{"name": "ExistingDir", "type": "string", "plural": "ExistingDirs", "no_value_parser": true},
|
||||
{"name": "ExistingFileOrDir", "type": "string", "plural": "ExistingFilesOrDirs", "no_value_parser": true},
|
||||
{"name": "Regexp", "type": "*regexp.Regexp", "parser": "regexp.Compile(s)"},
|
||||
{"name": "HexBytes", "type": "[]byte", "parser": "hex.DecodeString(s)", "help": "Bytes as a hex string."},
|
||||
{"name": "Duration", "type": "time.Duration", "parser": "time.ParseDuration(s)", "help": "Time duration."}
|
||||
]
|
781
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values_generated.go
vendored
Normal file
781
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values_generated.go
vendored
Normal file
|
@ -0,0 +1,781 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This file is autogenerated by "go generate .". Do not modify.
|
||||
|
||||
// -- bool Value
|
||||
type boolValue struct{ v *bool }
|
||||
|
||||
func newBoolValue(p *bool) *boolValue {
|
||||
return &boolValue{p}
|
||||
}
|
||||
|
||||
func (f *boolValue) Set(s string) error {
|
||||
v, err := strconv.ParseBool(s)
|
||||
if err == nil {
|
||||
*f.v = (bool)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *boolValue) Get() interface{} { return (bool)(*f.v) }
|
||||
|
||||
func (f *boolValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Bool parses the next command-line value as bool.
|
||||
func (p *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() (target *[]bool) {
|
||||
target = new([]bool)
|
||||
p.BoolListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) BoolListVar(target *[]bool) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newBoolValue(v.(*bool))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- string Value
|
||||
type stringValue struct{ v *string }
|
||||
|
||||
func newStringValue(p *string) *stringValue {
|
||||
return &stringValue{p}
|
||||
}
|
||||
|
||||
func (f *stringValue) Set(s string) error {
|
||||
v, err := s, error(nil)
|
||||
if err == nil {
|
||||
*f.v = (string)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *stringValue) Get() interface{} { return (string)(*f.v) }
|
||||
|
||||
func (f *stringValue) String() string { return string(*f.v) }
|
||||
|
||||
// String parses the next command-line value as string.
|
||||
func (p *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() (target *[]string) {
|
||||
target = new([]string)
|
||||
p.StringsVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) StringsVar(target *[]string) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newStringValue(v.(*string))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- uint Value
|
||||
type uintValue struct{ v *uint }
|
||||
|
||||
func newUintValue(p *uint) *uintValue {
|
||||
return &uintValue{p}
|
||||
}
|
||||
|
||||
func (f *uintValue) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
if err == nil {
|
||||
*f.v = (uint)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *uintValue) Get() interface{} { return (uint)(*f.v) }
|
||||
|
||||
func (f *uintValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint parses the next command-line value as uint.
|
||||
func (p *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() (target *[]uint) {
|
||||
target = new([]uint)
|
||||
p.UintsVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) UintsVar(target *[]uint) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newUintValue(v.(*uint))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- uint8 Value
|
||||
type uint8Value struct{ v *uint8 }
|
||||
|
||||
func newUint8Value(p *uint8) *uint8Value {
|
||||
return &uint8Value{p}
|
||||
}
|
||||
|
||||
func (f *uint8Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 8)
|
||||
if err == nil {
|
||||
*f.v = (uint8)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *uint8Value) Get() interface{} { return (uint8)(*f.v) }
|
||||
|
||||
func (f *uint8Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint8 parses the next command-line value as uint8.
|
||||
func (p *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() (target *[]uint8) {
|
||||
target = new([]uint8)
|
||||
p.Uint8ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Uint8ListVar(target *[]uint8) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newUint8Value(v.(*uint8))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- uint16 Value
|
||||
type uint16Value struct{ v *uint16 }
|
||||
|
||||
func newUint16Value(p *uint16) *uint16Value {
|
||||
return &uint16Value{p}
|
||||
}
|
||||
|
||||
func (f *uint16Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 16)
|
||||
if err == nil {
|
||||
*f.v = (uint16)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *uint16Value) Get() interface{} { return (uint16)(*f.v) }
|
||||
|
||||
func (f *uint16Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint16 parses the next command-line value as uint16.
|
||||
func (p *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() (target *[]uint16) {
|
||||
target = new([]uint16)
|
||||
p.Uint16ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Uint16ListVar(target *[]uint16) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newUint16Value(v.(*uint16))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- uint32 Value
|
||||
type uint32Value struct{ v *uint32 }
|
||||
|
||||
func newUint32Value(p *uint32) *uint32Value {
|
||||
return &uint32Value{p}
|
||||
}
|
||||
|
||||
func (f *uint32Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 32)
|
||||
if err == nil {
|
||||
*f.v = (uint32)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *uint32Value) Get() interface{} { return (uint32)(*f.v) }
|
||||
|
||||
func (f *uint32Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint32 parses the next command-line value as uint32.
|
||||
func (p *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() (target *[]uint32) {
|
||||
target = new([]uint32)
|
||||
p.Uint32ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Uint32ListVar(target *[]uint32) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newUint32Value(v.(*uint32))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- uint64 Value
|
||||
type uint64Value struct{ v *uint64 }
|
||||
|
||||
func newUint64Value(p *uint64) *uint64Value {
|
||||
return &uint64Value{p}
|
||||
}
|
||||
|
||||
func (f *uint64Value) Set(s string) error {
|
||||
v, err := strconv.ParseUint(s, 0, 64)
|
||||
if err == nil {
|
||||
*f.v = (uint64)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *uint64Value) Get() interface{} { return (uint64)(*f.v) }
|
||||
|
||||
func (f *uint64Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Uint64 parses the next command-line value as uint64.
|
||||
func (p *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() (target *[]uint64) {
|
||||
target = new([]uint64)
|
||||
p.Uint64ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Uint64ListVar(target *[]uint64) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newUint64Value(v.(*uint64))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- int Value
|
||||
type intValue struct{ v *int }
|
||||
|
||||
func newIntValue(p *int) *intValue {
|
||||
return &intValue{p}
|
||||
}
|
||||
|
||||
func (f *intValue) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
if err == nil {
|
||||
*f.v = (int)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *intValue) Get() interface{} { return (int)(*f.v) }
|
||||
|
||||
func (f *intValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int parses the next command-line value as int.
|
||||
func (p *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() (target *[]int) {
|
||||
target = new([]int)
|
||||
p.IntsVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) IntsVar(target *[]int) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newIntValue(v.(*int))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- int8 Value
|
||||
type int8Value struct{ v *int8 }
|
||||
|
||||
func newInt8Value(p *int8) *int8Value {
|
||||
return &int8Value{p}
|
||||
}
|
||||
|
||||
func (f *int8Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 8)
|
||||
if err == nil {
|
||||
*f.v = (int8)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *int8Value) Get() interface{} { return (int8)(*f.v) }
|
||||
|
||||
func (f *int8Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int8 parses the next command-line value as int8.
|
||||
func (p *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() (target *[]int8) {
|
||||
target = new([]int8)
|
||||
p.Int8ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Int8ListVar(target *[]int8) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newInt8Value(v.(*int8))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- int16 Value
|
||||
type int16Value struct{ v *int16 }
|
||||
|
||||
func newInt16Value(p *int16) *int16Value {
|
||||
return &int16Value{p}
|
||||
}
|
||||
|
||||
func (f *int16Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 16)
|
||||
if err == nil {
|
||||
*f.v = (int16)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *int16Value) Get() interface{} { return (int16)(*f.v) }
|
||||
|
||||
func (f *int16Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int16 parses the next command-line value as int16.
|
||||
func (p *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() (target *[]int16) {
|
||||
target = new([]int16)
|
||||
p.Int16ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Int16ListVar(target *[]int16) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newInt16Value(v.(*int16))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- int32 Value
|
||||
type int32Value struct{ v *int32 }
|
||||
|
||||
func newInt32Value(p *int32) *int32Value {
|
||||
return &int32Value{p}
|
||||
}
|
||||
|
||||
func (f *int32Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 32)
|
||||
if err == nil {
|
||||
*f.v = (int32)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *int32Value) Get() interface{} { return (int32)(*f.v) }
|
||||
|
||||
func (f *int32Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int32 parses the next command-line value as int32.
|
||||
func (p *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() (target *[]int32) {
|
||||
target = new([]int32)
|
||||
p.Int32ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Int32ListVar(target *[]int32) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newInt32Value(v.(*int32))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- int64 Value
|
||||
type int64Value struct{ v *int64 }
|
||||
|
||||
func newInt64Value(p *int64) *int64Value {
|
||||
return &int64Value{p}
|
||||
}
|
||||
|
||||
func (f *int64Value) Set(s string) error {
|
||||
v, err := strconv.ParseInt(s, 0, 64)
|
||||
if err == nil {
|
||||
*f.v = (int64)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *int64Value) Get() interface{} { return (int64)(*f.v) }
|
||||
|
||||
func (f *int64Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Int64 parses the next command-line value as int64.
|
||||
func (p *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() (target *[]int64) {
|
||||
target = new([]int64)
|
||||
p.Int64ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Int64ListVar(target *[]int64) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newInt64Value(v.(*int64))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- float64 Value
|
||||
type float64Value struct{ v *float64 }
|
||||
|
||||
func newFloat64Value(p *float64) *float64Value {
|
||||
return &float64Value{p}
|
||||
}
|
||||
|
||||
func (f *float64Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 64)
|
||||
if err == nil {
|
||||
*f.v = (float64)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float64Value) Get() interface{} { return (float64)(*f.v) }
|
||||
|
||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Float64 parses the next command-line value as float64.
|
||||
func (p *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() (target *[]float64) {
|
||||
target = new([]float64)
|
||||
p.Float64ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Float64ListVar(target *[]float64) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newFloat64Value(v.(*float64))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- float32 Value
|
||||
type float32Value struct{ v *float32 }
|
||||
|
||||
func newFloat32Value(p *float32) *float32Value {
|
||||
return &float32Value{p}
|
||||
}
|
||||
|
||||
func (f *float32Value) Set(s string) error {
|
||||
v, err := strconv.ParseFloat(s, 32)
|
||||
if err == nil {
|
||||
*f.v = (float32)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *float32Value) Get() interface{} { return (float32)(*f.v) }
|
||||
|
||||
func (f *float32Value) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Float32 parses the next command-line value as float32.
|
||||
func (p *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() (target *[]float32) {
|
||||
target = new([]float32)
|
||||
p.Float32ListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) Float32ListVar(target *[]float32) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newFloat32Value(v.(*float32))
|
||||
}))
|
||||
}
|
||||
|
||||
// ExistingFiles accumulates string values into a slice.
|
||||
func (p *Clause) ExistingFiles() (target *[]string) {
|
||||
target = new([]string)
|
||||
p.ExistingFilesVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) ExistingFilesVar(target *[]string) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newExistingFileValue(v.(*string))
|
||||
}))
|
||||
}
|
||||
|
||||
// ExistingDirs accumulates string values into a slice.
|
||||
func (p *Clause) ExistingDirs() (target *[]string) {
|
||||
target = new([]string)
|
||||
p.ExistingDirsVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) ExistingDirsVar(target *[]string) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newExistingDirValue(v.(*string))
|
||||
}))
|
||||
}
|
||||
|
||||
// ExistingFilesOrDirs accumulates string values into a slice.
|
||||
func (p *Clause) ExistingFilesOrDirs() (target *[]string) {
|
||||
target = new([]string)
|
||||
p.ExistingFilesOrDirsVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) ExistingFilesOrDirsVar(target *[]string) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newExistingFileOrDirValue(v.(*string))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- *regexp.Regexp Value
|
||||
type regexpValue struct{ v **regexp.Regexp }
|
||||
|
||||
func newRegexpValue(p **regexp.Regexp) *regexpValue {
|
||||
return ®expValue{p}
|
||||
}
|
||||
|
||||
func (f *regexpValue) Set(s string) error {
|
||||
v, err := regexp.Compile(s)
|
||||
if err == nil {
|
||||
*f.v = (*regexp.Regexp)(v)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *regexpValue) Get() interface{} { return (*regexp.Regexp)(*f.v) }
|
||||
|
||||
func (f *regexpValue) String() string { return fmt.Sprintf("%v", *f.v) }
|
||||
|
||||
// Regexp parses the next command-line value as *regexp.Regexp.
|
||||
func (p *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() (target *[]*regexp.Regexp) {
|
||||
target = new([]*regexp.Regexp)
|
||||
p.RegexpListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) RegexpListVar(target *[]*regexp.Regexp) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newRegexpValue(v.(**regexp.Regexp))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- []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() (target *[][]byte) {
|
||||
target = new([][]byte)
|
||||
p.HexBytesListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) HexBytesListVar(target *[][]byte) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newHexBytesValue(v.(*[]byte))
|
||||
}))
|
||||
}
|
||||
|
||||
// -- 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() (target *[]time.Duration) {
|
||||
target = new([]time.Duration)
|
||||
p.DurationListVar(target)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Clause) DurationListVar(target *[]time.Duration) {
|
||||
p.SetValue(newAccumulator(target, func(v interface{}) Value {
|
||||
return newDurationValue(v.(*time.Duration))
|
||||
}))
|
||||
}
|
71
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values_test.go
vendored
Normal file
71
vendor/src/gopkg.in/alecthomas/kingpin.v3-unstable/values_test.go
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
package kingpin
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAccumulatorStrings(t *testing.T) {
|
||||
target := []string{}
|
||||
acc := newAccumulator(&target, func(v interface{}) Value { return newStringValue(v.(*string)) })
|
||||
acc.Set("a")
|
||||
assert.Equal(t, []string{"a"}, target)
|
||||
acc.Set("b")
|
||||
assert.Equal(t, []string{"a", "b"}, target)
|
||||
}
|
||||
|
||||
func TestStrings(t *testing.T) {
|
||||
app := New("", "")
|
||||
app.Arg("a", "").Required().String()
|
||||
app.Arg("b", "").Required().String()
|
||||
c := app.Arg("c", "").Required().Strings()
|
||||
app.Parse([]string{"a", "b", "a", "b"})
|
||||
assert.Equal(t, []string{"a", "b"}, *c)
|
||||
}
|
||||
|
||||
func TestEnum(t *testing.T) {
|
||||
app := New("", "")
|
||||
a := app.Arg("a", "").Enum("one", "two", "three")
|
||||
_, err := app.Parse([]string{"moo"})
|
||||
assert.Error(t, err)
|
||||
_, err = app.Parse([]string{"one"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "one", *a)
|
||||
}
|
||||
|
||||
func TestEnumVar(t *testing.T) {
|
||||
app := New("", "")
|
||||
var a string
|
||||
app.Arg("a", "").EnumVar(&a, "one", "two", "three")
|
||||
_, err := app.Parse([]string{"moo"})
|
||||
assert.Error(t, err)
|
||||
_, err = app.Parse([]string{"one"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "one", a)
|
||||
}
|
||||
|
||||
func TestCounter(t *testing.T) {
|
||||
app := New("", "")
|
||||
c := app.Flag("f", "").Counter()
|
||||
_, err := app.Parse([]string{"--f", "--f", "--f"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, *c)
|
||||
}
|
||||
|
||||
func 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)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue