mirror of
https://github.com/rumanzo/bt2qbt.git
synced 2024-11-22 10:22:38 +01:00
vendor update
This commit is contained in:
parent
7e57318c2e
commit
4002b2ad4e
44
vendor/github.com/jessevdk/go-flags/.travis.yml
generated
vendored
Normal file
44
vendor/github.com/jessevdk/go-flags/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.x
|
||||||
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
|
||||||
|
install:
|
||||||
|
# go-flags
|
||||||
|
- go get -d -v ./...
|
||||||
|
- go build -v ./...
|
||||||
|
|
||||||
|
# linting
|
||||||
|
- go get github.com/golang/lint/golint
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
|
- go get github.com/onsi/ginkgo/ginkgo
|
||||||
|
- go get github.com/modocache/gover
|
||||||
|
- if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then go get github.com/mattn/goveralls; fi
|
||||||
|
|
||||||
|
script:
|
||||||
|
# go-flags
|
||||||
|
- $(exit $(gofmt -l . | wc -l))
|
||||||
|
- go test -v ./...
|
||||||
|
|
||||||
|
# linting
|
||||||
|
- go tool vet -all=true -v=true . || true
|
||||||
|
- $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/golint ./...
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
- $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/ginkgo -r -cover
|
||||||
|
- $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/gover
|
||||||
|
- if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/goveralls -coverprofile=gover.coverprofile -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
|
||||||
|
|
||||||
|
env:
|
||||||
|
# coveralls.io
|
||||||
|
secure: "RCYbiB4P0RjQRIoUx/vG/AjP3mmYCbzOmr86DCww1Z88yNcy3hYr3Cq8rpPtYU5v0g7wTpu4adaKIcqRE9xknYGbqj3YWZiCoBP1/n4Z+9sHW3Dsd9D/GRGeHUus0laJUGARjWoCTvoEtOgTdGQDoX7mH+pUUY0FBltNYUdOiiU="
|
26
vendor/github.com/jessevdk/go-flags/LICENSE
generated
vendored
Normal file
26
vendor/github.com/jessevdk/go-flags/LICENSE
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) 2012 Jesse van den Kieboom. All rights reserved.
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
134
vendor/github.com/jessevdk/go-flags/README.md
generated
vendored
Normal file
134
vendor/github.com/jessevdk/go-flags/README.md
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
go-flags: a go library for parsing command line arguments
|
||||||
|
=========================================================
|
||||||
|
|
||||||
|
[![GoDoc](https://godoc.org/github.com/jessevdk/go-flags?status.png)](https://godoc.org/github.com/jessevdk/go-flags) [![Build Status](https://travis-ci.org/jessevdk/go-flags.svg?branch=master)](https://travis-ci.org/jessevdk/go-flags) [![Coverage Status](https://img.shields.io/coveralls/jessevdk/go-flags.svg)](https://coveralls.io/r/jessevdk/go-flags?branch=master)
|
||||||
|
|
||||||
|
This library provides similar functionality to the builtin flag library of
|
||||||
|
go, but provides much more functionality and nicer formatting. From the
|
||||||
|
documentation:
|
||||||
|
|
||||||
|
Package flags provides an extensive command line option parser.
|
||||||
|
The flags package is similar in functionality to the go builtin flag package
|
||||||
|
but provides more options and uses reflection to provide a convenient and
|
||||||
|
succinct way of specifying command line options.
|
||||||
|
|
||||||
|
Supported features:
|
||||||
|
* Options with short names (-v)
|
||||||
|
* Options with long names (--verbose)
|
||||||
|
* Options with and without arguments (bool v.s. other type)
|
||||||
|
* Options with optional arguments and default values
|
||||||
|
* Multiple option groups each containing a set of options
|
||||||
|
* Generate and print well-formatted help message
|
||||||
|
* Passing remaining command line arguments after -- (optional)
|
||||||
|
* Ignoring unknown command line options (optional)
|
||||||
|
* Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
|
||||||
|
* Supports multiple short options -aux
|
||||||
|
* Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
|
||||||
|
* Supports same option multiple times (can store in slice or last option counts)
|
||||||
|
* Supports maps
|
||||||
|
* Supports function callbacks
|
||||||
|
* Supports namespaces for (nested) option groups
|
||||||
|
|
||||||
|
The flags package uses structs, reflection and struct field tags
|
||||||
|
to allow users to specify command line options. This results in very simple
|
||||||
|
and concise specification of your application options. For example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Options struct {
|
||||||
|
Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This specifies one option with a short name -v and a long name --verbose.
|
||||||
|
When either -v or --verbose is found on the command line, a 'true' value
|
||||||
|
will be appended to the Verbose field. e.g. when specifying -vvv, the
|
||||||
|
resulting value of Verbose will be {[true, true, true]}.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
--------
|
||||||
|
```go
|
||||||
|
var opts struct {
|
||||||
|
// Slice of bool will append 'true' each time the option
|
||||||
|
// is encountered (can be set multiple times, like -vvv)
|
||||||
|
Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
|
||||||
|
|
||||||
|
// Example of automatic marshalling to desired type (uint)
|
||||||
|
Offset uint `long:"offset" description:"Offset"`
|
||||||
|
|
||||||
|
// Example of a callback, called each time the option is found.
|
||||||
|
Call func(string) `short:"c" description:"Call phone number"`
|
||||||
|
|
||||||
|
// Example of a required flag
|
||||||
|
Name string `short:"n" long:"name" description:"A name" required:"true"`
|
||||||
|
|
||||||
|
// Example of a value name
|
||||||
|
File string `short:"f" long:"file" description:"A file" value-name:"FILE"`
|
||||||
|
|
||||||
|
// Example of a pointer
|
||||||
|
Ptr *int `short:"p" description:"A pointer to an integer"`
|
||||||
|
|
||||||
|
// Example of a slice of strings
|
||||||
|
StringSlice []string `short:"s" description:"A slice of strings"`
|
||||||
|
|
||||||
|
// Example of a slice of pointers
|
||||||
|
PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"`
|
||||||
|
|
||||||
|
// Example of a map
|
||||||
|
IntMap map[string]int `long:"intmap" description:"A map from string to int"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback which will invoke callto:<argument> to call a number.
|
||||||
|
// Note that this works just on OS X (and probably only with
|
||||||
|
// Skype) but it shows the idea.
|
||||||
|
opts.Call = func(num string) {
|
||||||
|
cmd := exec.Command("open", "callto:"+num)
|
||||||
|
cmd.Start()
|
||||||
|
cmd.Process.Release()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make some fake arguments to parse.
|
||||||
|
args := []string{
|
||||||
|
"-vv",
|
||||||
|
"--offset=5",
|
||||||
|
"-n", "Me",
|
||||||
|
"-p", "3",
|
||||||
|
"-s", "hello",
|
||||||
|
"-s", "world",
|
||||||
|
"--ptrslice", "hello",
|
||||||
|
"--ptrslice", "world",
|
||||||
|
"--intmap", "a:1",
|
||||||
|
"--intmap", "b:5",
|
||||||
|
"arg1",
|
||||||
|
"arg2",
|
||||||
|
"arg3",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse flags from `args'. Note that here we use flags.ParseArgs for
|
||||||
|
// the sake of making a working example. Normally, you would simply use
|
||||||
|
// flags.Parse(&opts) which uses os.Args
|
||||||
|
args, err := flags.ParseArgs(&opts, args)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Verbosity: %v\n", opts.Verbose)
|
||||||
|
fmt.Printf("Offset: %d\n", opts.Offset)
|
||||||
|
fmt.Printf("Name: %s\n", opts.Name)
|
||||||
|
fmt.Printf("Ptr: %d\n", *opts.Ptr)
|
||||||
|
fmt.Printf("StringSlice: %v\n", opts.StringSlice)
|
||||||
|
fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1])
|
||||||
|
fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"])
|
||||||
|
fmt.Printf("Remaining args: %s\n", strings.Join(args, " "))
|
||||||
|
|
||||||
|
// Output: Verbosity: [true true]
|
||||||
|
// Offset: 5
|
||||||
|
// Name: Me
|
||||||
|
// Ptr: 3
|
||||||
|
// StringSlice: [hello world]
|
||||||
|
// PtrSlice: [hello world]
|
||||||
|
// IntMap: [a:1 b:5]
|
||||||
|
// Remaining args: arg1 arg2 arg3
|
||||||
|
```
|
||||||
|
|
||||||
|
More information can be found in the godocs: <http://godoc.org/github.com/jessevdk/go-flags>
|
27
vendor/github.com/jessevdk/go-flags/arg.go
generated
vendored
Normal file
27
vendor/github.com/jessevdk/go-flags/arg.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Arg represents a positional argument on the command line.
|
||||||
|
type Arg struct {
|
||||||
|
// The name of the positional argument (used in the help)
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// A description of the positional argument (used in the help)
|
||||||
|
Description string
|
||||||
|
|
||||||
|
// The minimal number of required positional arguments
|
||||||
|
Required int
|
||||||
|
|
||||||
|
// The maximum number of required positional arguments
|
||||||
|
RequiredMaximum int
|
||||||
|
|
||||||
|
value reflect.Value
|
||||||
|
tag multiTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Arg) isRemaining() bool {
|
||||||
|
return a.value.Type().Kind() == reflect.Slice
|
||||||
|
}
|
16
vendor/github.com/jessevdk/go-flags/check_crosscompile.sh
generated
vendored
Normal file
16
vendor/github.com/jessevdk/go-flags/check_crosscompile.sh
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo '# linux arm7'
|
||||||
|
GOARM=7 GOARCH=arm GOOS=linux go build
|
||||||
|
echo '# linux arm5'
|
||||||
|
GOARM=5 GOARCH=arm GOOS=linux go build
|
||||||
|
echo '# windows 386'
|
||||||
|
GOARCH=386 GOOS=windows go build
|
||||||
|
echo '# windows amd64'
|
||||||
|
GOARCH=amd64 GOOS=windows go build
|
||||||
|
echo '# darwin'
|
||||||
|
GOARCH=amd64 GOOS=darwin go build
|
||||||
|
echo '# freebsd'
|
||||||
|
GOARCH=amd64 GOOS=freebsd go build
|
59
vendor/github.com/jessevdk/go-flags/closest.go
generated
vendored
Normal file
59
vendor/github.com/jessevdk/go-flags/closest.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
func levenshtein(s string, t string) int {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return len(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(t) == 0 {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
dists := make([][]int, len(s)+1)
|
||||||
|
for i := range dists {
|
||||||
|
dists[i] = make([]int, len(t)+1)
|
||||||
|
dists[i][0] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := range t {
|
||||||
|
dists[0][j] = j
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, sc := range s {
|
||||||
|
for j, tc := range t {
|
||||||
|
if sc == tc {
|
||||||
|
dists[i+1][j+1] = dists[i][j]
|
||||||
|
} else {
|
||||||
|
dists[i+1][j+1] = dists[i][j] + 1
|
||||||
|
if dists[i+1][j] < dists[i+1][j+1] {
|
||||||
|
dists[i+1][j+1] = dists[i+1][j] + 1
|
||||||
|
}
|
||||||
|
if dists[i][j+1] < dists[i+1][j+1] {
|
||||||
|
dists[i+1][j+1] = dists[i][j+1] + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dists[len(s)][len(t)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func closestChoice(cmd string, choices []string) (string, int) {
|
||||||
|
if len(choices) == 0 {
|
||||||
|
return "", 0
|
||||||
|
}
|
||||||
|
|
||||||
|
mincmd := -1
|
||||||
|
mindist := -1
|
||||||
|
|
||||||
|
for i, c := range choices {
|
||||||
|
l := levenshtein(cmd, c)
|
||||||
|
|
||||||
|
if mincmd < 0 || l < mindist {
|
||||||
|
mindist = l
|
||||||
|
mincmd = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return choices[mincmd], mindist
|
||||||
|
}
|
465
vendor/github.com/jessevdk/go-flags/command.go
generated
vendored
Normal file
465
vendor/github.com/jessevdk/go-flags/command.go
generated
vendored
Normal file
@ -0,0 +1,465 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command represents an application command. Commands can be added to the
|
||||||
|
// parser (which itself is a command) and are selected/executed when its name
|
||||||
|
// is specified on the command line. The Command type embeds a Group and
|
||||||
|
// therefore also carries a set of command specific options.
|
||||||
|
type Command struct {
|
||||||
|
// Embedded, see Group for more information
|
||||||
|
*Group
|
||||||
|
|
||||||
|
// The name by which the command can be invoked
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// The active sub command (set by parsing) or nil
|
||||||
|
Active *Command
|
||||||
|
|
||||||
|
// Whether subcommands are optional
|
||||||
|
SubcommandsOptional bool
|
||||||
|
|
||||||
|
// Aliases for the command
|
||||||
|
Aliases []string
|
||||||
|
|
||||||
|
// Whether positional arguments are required
|
||||||
|
ArgsRequired bool
|
||||||
|
|
||||||
|
commands []*Command
|
||||||
|
hasBuiltinHelpGroup bool
|
||||||
|
args []*Arg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commander is an interface which can be implemented by any command added in
|
||||||
|
// the options. When implemented, the Execute method will be called for the last
|
||||||
|
// specified (sub)command providing the remaining command line arguments.
|
||||||
|
type Commander interface {
|
||||||
|
// Execute will be called for the last active (sub)command. The
|
||||||
|
// args argument contains the remaining command line arguments. The
|
||||||
|
// error that Execute returns will be eventually passed out of the
|
||||||
|
// Parse method of the Parser.
|
||||||
|
Execute(args []string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage is an interface which can be implemented to show a custom usage string
|
||||||
|
// in the help message shown for a command.
|
||||||
|
type Usage interface {
|
||||||
|
// Usage is called for commands to allow customized printing of command
|
||||||
|
// usage in the generated help message.
|
||||||
|
Usage() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type lookup struct {
|
||||||
|
shortNames map[string]*Option
|
||||||
|
longNames map[string]*Option
|
||||||
|
|
||||||
|
commands map[string]*Command
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCommand adds a new command to the parser with the given name and data. The
|
||||||
|
// data needs to be a pointer to a struct from which the fields indicate which
|
||||||
|
// options are in the command. The provided data can implement the Command and
|
||||||
|
// Usage interfaces.
|
||||||
|
func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) {
|
||||||
|
cmd := newCommand(command, shortDescription, longDescription, data)
|
||||||
|
|
||||||
|
cmd.parent = c
|
||||||
|
|
||||||
|
if err := cmd.scan(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.commands = append(c.commands, cmd)
|
||||||
|
return cmd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGroup adds a new group to the command with the given name and data. The
|
||||||
|
// data needs to be a pointer to a struct from which the fields indicate which
|
||||||
|
// options are in the group.
|
||||||
|
func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) {
|
||||||
|
group := newGroup(shortDescription, longDescription, data)
|
||||||
|
|
||||||
|
group.parent = c
|
||||||
|
|
||||||
|
if err := group.scanType(c.scanSubcommandHandler(group)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.groups = append(c.groups, group)
|
||||||
|
return group, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commands returns a list of subcommands of this command.
|
||||||
|
func (c *Command) Commands() []*Command {
|
||||||
|
return c.commands
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find locates the subcommand with the given name and returns it. If no such
|
||||||
|
// command can be found Find will return nil.
|
||||||
|
func (c *Command) Find(name string) *Command {
|
||||||
|
for _, cc := range c.commands {
|
||||||
|
if cc.match(name) {
|
||||||
|
return cc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindOptionByLongName finds an option that is part of the command, or any of
|
||||||
|
// its parent commands, by matching its long name (including the option
|
||||||
|
// namespace).
|
||||||
|
func (c *Command) FindOptionByLongName(longName string) (option *Option) {
|
||||||
|
for option == nil && c != nil {
|
||||||
|
option = c.Group.FindOptionByLongName(longName)
|
||||||
|
|
||||||
|
c, _ = c.parent.(*Command)
|
||||||
|
}
|
||||||
|
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindOptionByShortName finds an option that is part of the command, or any of
|
||||||
|
// its parent commands, by matching its long name (including the option
|
||||||
|
// namespace).
|
||||||
|
func (c *Command) FindOptionByShortName(shortName rune) (option *Option) {
|
||||||
|
for option == nil && c != nil {
|
||||||
|
option = c.Group.FindOptionByShortName(shortName)
|
||||||
|
|
||||||
|
c, _ = c.parent.(*Command)
|
||||||
|
}
|
||||||
|
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
|
||||||
|
// Args returns a list of positional arguments associated with this command.
|
||||||
|
func (c *Command) Args() []*Arg {
|
||||||
|
ret := make([]*Arg, len(c.args))
|
||||||
|
copy(ret, c.args)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command {
|
||||||
|
return &Command{
|
||||||
|
Group: newGroup(shortDescription, longDescription, data),
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler {
|
||||||
|
f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
|
||||||
|
mtag := newMultiTag(string(sfield.Tag))
|
||||||
|
|
||||||
|
if err := mtag.Parse(); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
positional := mtag.Get("positional-args")
|
||||||
|
|
||||||
|
if len(positional) != 0 {
|
||||||
|
stype := realval.Type()
|
||||||
|
|
||||||
|
for i := 0; i < stype.NumField(); i++ {
|
||||||
|
field := stype.Field(i)
|
||||||
|
|
||||||
|
m := newMultiTag((string(field.Tag)))
|
||||||
|
|
||||||
|
if err := m.Parse(); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := m.Get("positional-arg-name")
|
||||||
|
|
||||||
|
if len(name) == 0 {
|
||||||
|
name = field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
required := -1
|
||||||
|
requiredMaximum := -1
|
||||||
|
|
||||||
|
sreq := m.Get("required")
|
||||||
|
|
||||||
|
if sreq != "" {
|
||||||
|
required = 1
|
||||||
|
|
||||||
|
rng := strings.SplitN(sreq, "-", 2)
|
||||||
|
|
||||||
|
if len(rng) > 1 {
|
||||||
|
if preq, err := strconv.ParseInt(rng[0], 10, 32); err == nil {
|
||||||
|
required = int(preq)
|
||||||
|
}
|
||||||
|
|
||||||
|
if preq, err := strconv.ParseInt(rng[1], 10, 32); err == nil {
|
||||||
|
requiredMaximum = int(preq)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil {
|
||||||
|
required = int(preq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arg := &Arg{
|
||||||
|
Name: name,
|
||||||
|
Description: m.Get("description"),
|
||||||
|
Required: required,
|
||||||
|
RequiredMaximum: requiredMaximum,
|
||||||
|
|
||||||
|
value: realval.Field(i),
|
||||||
|
tag: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.args = append(c.args, arg)
|
||||||
|
|
||||||
|
if len(mtag.Get("required")) != 0 {
|
||||||
|
c.ArgsRequired = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
subcommand := mtag.Get("command")
|
||||||
|
|
||||||
|
if len(subcommand) != 0 {
|
||||||
|
var ptrval reflect.Value
|
||||||
|
|
||||||
|
if realval.Kind() == reflect.Ptr {
|
||||||
|
ptrval = realval
|
||||||
|
|
||||||
|
if ptrval.IsNil() {
|
||||||
|
ptrval.Set(reflect.New(ptrval.Type().Elem()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptrval = realval.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
shortDescription := mtag.Get("description")
|
||||||
|
longDescription := mtag.Get("long-description")
|
||||||
|
subcommandsOptional := mtag.Get("subcommands-optional")
|
||||||
|
aliases := mtag.GetMany("alias")
|
||||||
|
|
||||||
|
subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
subc.Hidden = mtag.Get("hidden") != ""
|
||||||
|
|
||||||
|
if len(subcommandsOptional) > 0 {
|
||||||
|
subc.SubcommandsOptional = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(aliases) > 0 {
|
||||||
|
subc.Aliases = aliases
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentg.scanSubGroupHandler(realval, sfield)
|
||||||
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) scan() error {
|
||||||
|
return c.scanType(c.scanSubcommandHandler(c.Group))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) eachOption(f func(*Command, *Group, *Option)) {
|
||||||
|
c.eachCommand(func(c *Command) {
|
||||||
|
c.eachGroup(func(g *Group) {
|
||||||
|
for _, option := range g.options {
|
||||||
|
f(c, g, option)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) eachCommand(f func(*Command), recurse bool) {
|
||||||
|
f(c)
|
||||||
|
|
||||||
|
for _, cc := range c.commands {
|
||||||
|
if recurse {
|
||||||
|
cc.eachCommand(f, true)
|
||||||
|
} else {
|
||||||
|
f(cc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) eachActiveGroup(f func(cc *Command, g *Group)) {
|
||||||
|
c.eachGroup(func(g *Group) {
|
||||||
|
f(c, g)
|
||||||
|
})
|
||||||
|
|
||||||
|
if c.Active != nil {
|
||||||
|
c.Active.eachActiveGroup(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) addHelpGroups(showHelp func() error) {
|
||||||
|
if !c.hasBuiltinHelpGroup {
|
||||||
|
c.addHelpGroup(showHelp)
|
||||||
|
c.hasBuiltinHelpGroup = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cc := range c.commands {
|
||||||
|
cc.addHelpGroups(showHelp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) makeLookup() lookup {
|
||||||
|
ret := lookup{
|
||||||
|
shortNames: make(map[string]*Option),
|
||||||
|
longNames: make(map[string]*Option),
|
||||||
|
commands: make(map[string]*Command),
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := c.parent
|
||||||
|
|
||||||
|
var parents []*Command
|
||||||
|
|
||||||
|
for parent != nil {
|
||||||
|
if cmd, ok := parent.(*Command); ok {
|
||||||
|
parents = append(parents, cmd)
|
||||||
|
parent = cmd.parent
|
||||||
|
} else {
|
||||||
|
parent = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(parents) - 1; i >= 0; i-- {
|
||||||
|
parents[i].fillLookup(&ret, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.fillLookup(&ret, false)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) fillLookup(ret *lookup, onlyOptions bool) {
|
||||||
|
c.eachGroup(func(g *Group) {
|
||||||
|
for _, option := range g.options {
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
ret.shortNames[string(option.ShortName)] = option
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(option.LongName) > 0 {
|
||||||
|
ret.longNames[option.LongNameWithNamespace()] = option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if onlyOptions {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subcommand := range c.commands {
|
||||||
|
ret.commands[subcommand.Name] = subcommand
|
||||||
|
|
||||||
|
for _, a := range subcommand.Aliases {
|
||||||
|
ret.commands[a] = subcommand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) groupByName(name string) *Group {
|
||||||
|
if grp := c.Group.groupByName(name); grp != nil {
|
||||||
|
return grp
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subc := range c.commands {
|
||||||
|
prefix := subc.Name + "."
|
||||||
|
|
||||||
|
if strings.HasPrefix(name, prefix) {
|
||||||
|
if grp := subc.groupByName(name[len(prefix):]); grp != nil {
|
||||||
|
return grp
|
||||||
|
}
|
||||||
|
} else if name == subc.Name {
|
||||||
|
return subc.Group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandList []*Command
|
||||||
|
|
||||||
|
func (c commandList) Less(i, j int) bool {
|
||||||
|
return c[i].Name < c[j].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c commandList) Len() int {
|
||||||
|
return len(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c commandList) Swap(i, j int) {
|
||||||
|
c[i], c[j] = c[j], c[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) sortedVisibleCommands() []*Command {
|
||||||
|
ret := commandList(c.visibleCommands())
|
||||||
|
sort.Sort(ret)
|
||||||
|
|
||||||
|
return []*Command(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) visibleCommands() []*Command {
|
||||||
|
ret := make([]*Command, 0, len(c.commands))
|
||||||
|
|
||||||
|
for _, cmd := range c.commands {
|
||||||
|
if !cmd.Hidden {
|
||||||
|
ret = append(ret, cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) match(name string) bool {
|
||||||
|
if c.Name == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range c.Aliases {
|
||||||
|
if v == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) hasCliOptions() bool {
|
||||||
|
ret := false
|
||||||
|
|
||||||
|
c.eachGroup(func(g *Group) {
|
||||||
|
if g.isBuiltinHelp {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range g.options {
|
||||||
|
if opt.canCli() {
|
||||||
|
ret = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) fillParseState(s *parseState) {
|
||||||
|
s.positional = make([]*Arg, len(c.args))
|
||||||
|
copy(s.positional, c.args)
|
||||||
|
|
||||||
|
s.lookup = c.makeLookup()
|
||||||
|
s.command = c
|
||||||
|
}
|
309
vendor/github.com/jessevdk/go-flags/completion.go
generated
vendored
Normal file
309
vendor/github.com/jessevdk/go-flags/completion.go
generated
vendored
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Completion is a type containing information of a completion.
|
||||||
|
type Completion struct {
|
||||||
|
// The completed item
|
||||||
|
Item string
|
||||||
|
|
||||||
|
// A description of the completed item (optional)
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
type completions []Completion
|
||||||
|
|
||||||
|
func (c completions) Len() int {
|
||||||
|
return len(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c completions) Less(i, j int) bool {
|
||||||
|
return c[i].Item < c[j].Item
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c completions) Swap(i, j int) {
|
||||||
|
c[i], c[j] = c[j], c[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Completer is an interface which can be implemented by types
|
||||||
|
// to provide custom command line argument completion.
|
||||||
|
type Completer interface {
|
||||||
|
// Complete receives a prefix representing a (partial) value
|
||||||
|
// for its type and should provide a list of possible valid
|
||||||
|
// completions.
|
||||||
|
Complete(match string) []Completion
|
||||||
|
}
|
||||||
|
|
||||||
|
type completion struct {
|
||||||
|
parser *Parser
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filename is a string alias which provides filename completion.
|
||||||
|
type Filename string
|
||||||
|
|
||||||
|
func completionsWithoutDescriptions(items []string) []Completion {
|
||||||
|
ret := make([]Completion, len(items))
|
||||||
|
|
||||||
|
for i, v := range items {
|
||||||
|
ret[i].Item = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete returns a list of existing files with the given
|
||||||
|
// prefix.
|
||||||
|
func (f *Filename) Complete(match string) []Completion {
|
||||||
|
ret, _ := filepath.Glob(match + "*")
|
||||||
|
return completionsWithoutDescriptions(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) skipPositional(s *parseState, n int) {
|
||||||
|
if n >= len(s.positional) {
|
||||||
|
s.positional = nil
|
||||||
|
} else {
|
||||||
|
s.positional = s.positional[n:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) completeOptionNames(s *parseState, prefix string, match string, short bool) []Completion {
|
||||||
|
if short && len(match) != 0 {
|
||||||
|
return []Completion{
|
||||||
|
Completion{
|
||||||
|
Item: prefix + match,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []Completion
|
||||||
|
repeats := map[string]bool{}
|
||||||
|
|
||||||
|
for name, opt := range s.lookup.longNames {
|
||||||
|
if strings.HasPrefix(name, match) && !opt.Hidden {
|
||||||
|
results = append(results, Completion{
|
||||||
|
Item: defaultLongOptDelimiter + name,
|
||||||
|
Description: opt.Description,
|
||||||
|
})
|
||||||
|
|
||||||
|
if short {
|
||||||
|
repeats[string(opt.ShortName)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if short {
|
||||||
|
for name, opt := range s.lookup.shortNames {
|
||||||
|
if _, exist := repeats[name]; !exist && strings.HasPrefix(name, match) && !opt.Hidden {
|
||||||
|
results = append(results, Completion{
|
||||||
|
Item: string(defaultShortOptDelimiter) + name,
|
||||||
|
Description: opt.Description,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) completeNamesForLongPrefix(s *parseState, prefix string, match string) []Completion {
|
||||||
|
return c.completeOptionNames(s, prefix, match, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) completeNamesForShortPrefix(s *parseState, prefix string, match string) []Completion {
|
||||||
|
return c.completeOptionNames(s, prefix, match, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) completeCommands(s *parseState, match string) []Completion {
|
||||||
|
n := make([]Completion, 0, len(s.command.commands))
|
||||||
|
|
||||||
|
for _, cmd := range s.command.commands {
|
||||||
|
if cmd.data != c && strings.HasPrefix(cmd.Name, match) {
|
||||||
|
n = append(n, Completion{
|
||||||
|
Item: cmd.Name,
|
||||||
|
Description: cmd.ShortDescription,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion {
|
||||||
|
if value.Kind() == reflect.Slice {
|
||||||
|
value = reflect.New(value.Type().Elem())
|
||||||
|
}
|
||||||
|
i := value.Interface()
|
||||||
|
|
||||||
|
var ret []Completion
|
||||||
|
|
||||||
|
if cmp, ok := i.(Completer); ok {
|
||||||
|
ret = cmp.Complete(match)
|
||||||
|
} else if value.CanAddr() {
|
||||||
|
if cmp, ok = value.Addr().Interface().(Completer); ok {
|
||||||
|
ret = cmp.Complete(match)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range ret {
|
||||||
|
ret[i].Item = prefix + v.Item
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) complete(args []string) []Completion {
|
||||||
|
if len(args) == 0 {
|
||||||
|
args = []string{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &parseState{
|
||||||
|
args: args,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.parser.fillParseState(s)
|
||||||
|
|
||||||
|
var opt *Option
|
||||||
|
|
||||||
|
for len(s.args) > 1 {
|
||||||
|
arg := s.pop()
|
||||||
|
|
||||||
|
if (c.parser.Options&PassDoubleDash) != None && arg == "--" {
|
||||||
|
opt = nil
|
||||||
|
c.skipPositional(s, len(s.args)-1)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if argumentIsOption(arg) {
|
||||||
|
prefix, optname, islong := stripOptionPrefix(arg)
|
||||||
|
optname, _, argument := splitOption(prefix, optname, islong)
|
||||||
|
|
||||||
|
if argument == nil {
|
||||||
|
var o *Option
|
||||||
|
canarg := true
|
||||||
|
|
||||||
|
if islong {
|
||||||
|
o = s.lookup.longNames[optname]
|
||||||
|
} else {
|
||||||
|
for i, r := range optname {
|
||||||
|
sname := string(r)
|
||||||
|
o = s.lookup.shortNames[sname]
|
||||||
|
|
||||||
|
if o == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 0 && o.canArgument() && len(optname) != len(sname) {
|
||||||
|
canarg = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if o == nil && (c.parser.Options&PassAfterNonOption) != None {
|
||||||
|
opt = nil
|
||||||
|
c.skipPositional(s, len(s.args)-1)
|
||||||
|
|
||||||
|
break
|
||||||
|
} else if o != nil && o.canArgument() && !o.OptionalArgument && canarg {
|
||||||
|
if len(s.args) > 1 {
|
||||||
|
s.pop()
|
||||||
|
} else {
|
||||||
|
opt = o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(s.positional) > 0 {
|
||||||
|
if !s.positional[0].isRemaining() {
|
||||||
|
// Don't advance beyond a remaining positional arg (because
|
||||||
|
// it consumes all subsequent args).
|
||||||
|
s.positional = s.positional[1:]
|
||||||
|
}
|
||||||
|
} else if cmd, ok := s.lookup.commands[arg]; ok {
|
||||||
|
cmd.fillParseState(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastarg := s.args[len(s.args)-1]
|
||||||
|
var ret []Completion
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
// Completion for the argument of 'opt'
|
||||||
|
ret = c.completeValue(opt.value, "", lastarg)
|
||||||
|
} else if argumentStartsOption(lastarg) {
|
||||||
|
// Complete the option
|
||||||
|
prefix, optname, islong := stripOptionPrefix(lastarg)
|
||||||
|
optname, split, argument := splitOption(prefix, optname, islong)
|
||||||
|
|
||||||
|
if argument == nil && !islong {
|
||||||
|
rname, n := utf8.DecodeRuneInString(optname)
|
||||||
|
sname := string(rname)
|
||||||
|
|
||||||
|
if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() {
|
||||||
|
ret = c.completeValue(opt.value, prefix+sname, optname[n:])
|
||||||
|
} else {
|
||||||
|
ret = c.completeNamesForShortPrefix(s, prefix, optname)
|
||||||
|
}
|
||||||
|
} else if argument != nil {
|
||||||
|
if islong {
|
||||||
|
opt = s.lookup.longNames[optname]
|
||||||
|
} else {
|
||||||
|
opt = s.lookup.shortNames[optname]
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
ret = c.completeValue(opt.value, prefix+optname+split, *argument)
|
||||||
|
}
|
||||||
|
} else if islong {
|
||||||
|
ret = c.completeNamesForLongPrefix(s, prefix, optname)
|
||||||
|
} else {
|
||||||
|
ret = c.completeNamesForShortPrefix(s, prefix, optname)
|
||||||
|
}
|
||||||
|
} else if len(s.positional) > 0 {
|
||||||
|
// Complete for positional argument
|
||||||
|
ret = c.completeValue(s.positional[0].value, "", lastarg)
|
||||||
|
} else if len(s.command.commands) > 0 {
|
||||||
|
// Complete for command
|
||||||
|
ret = c.completeCommands(s, lastarg)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(completions(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *completion) print(items []Completion, showDescriptions bool) {
|
||||||
|
if showDescriptions && len(items) > 1 {
|
||||||
|
maxl := 0
|
||||||
|
|
||||||
|
for _, v := range items {
|
||||||
|
if len(v.Item) > maxl {
|
||||||
|
maxl = len(v.Item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range items {
|
||||||
|
fmt.Printf("%s", v.Item)
|
||||||
|
|
||||||
|
if len(v.Description) > 0 {
|
||||||
|
fmt.Printf("%s # %s", strings.Repeat(" ", maxl-len(v.Item)), v.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range items {
|
||||||
|
fmt.Println(v.Item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
348
vendor/github.com/jessevdk/go-flags/convert.go
generated
vendored
Normal file
348
vendor/github.com/jessevdk/go-flags/convert.go
generated
vendored
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
// Copyright 2012 Jesse van den Kieboom. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Marshaler is the interface implemented by types that can marshal themselves
|
||||||
|
// to a string representation of the flag.
|
||||||
|
type Marshaler interface {
|
||||||
|
// MarshalFlag marshals a flag value to its string representation.
|
||||||
|
MarshalFlag() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is the interface implemented by types that can unmarshal a flag
|
||||||
|
// argument to themselves. The provided value is directly passed from the
|
||||||
|
// command line.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
// UnmarshalFlag unmarshals a string value representation to the flag
|
||||||
|
// value (which therefore needs to be a pointer receiver).
|
||||||
|
UnmarshalFlag(value string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBase(options multiTag, base int) (int, error) {
|
||||||
|
sbase := options.Get("base")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var ivbase int64
|
||||||
|
|
||||||
|
if sbase != "" {
|
||||||
|
ivbase, err = strconv.ParseInt(sbase, 10, 32)
|
||||||
|
base = int(ivbase)
|
||||||
|
}
|
||||||
|
|
||||||
|
return base, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertMarshal(val reflect.Value) (bool, string, error) {
|
||||||
|
// Check first for the Marshaler interface
|
||||||
|
if val.Type().NumMethod() > 0 && val.CanInterface() {
|
||||||
|
if marshaler, ok := val.Interface().(Marshaler); ok {
|
||||||
|
ret, err := marshaler.MarshalFlag()
|
||||||
|
return true, ret, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertToString(val reflect.Value, options multiTag) (string, error) {
|
||||||
|
if ok, ret, err := convertMarshal(val); ok {
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := val.Type()
|
||||||
|
|
||||||
|
// Support for time.Duration
|
||||||
|
if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
|
||||||
|
stringer := val.Interface().(fmt.Stringer)
|
||||||
|
return stringer.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tp.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return val.String(), nil
|
||||||
|
case reflect.Bool:
|
||||||
|
if val.Bool() {
|
||||||
|
return "true", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "false", nil
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
base, err := getBase(options, 10)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.FormatInt(val.Int(), base), nil
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
base, err := getBase(options, 10)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.FormatUint(val.Uint(), base), nil
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil
|
||||||
|
case reflect.Slice:
|
||||||
|
if val.Len() == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := "["
|
||||||
|
|
||||||
|
for i := 0; i < val.Len(); i++ {
|
||||||
|
if i != 0 {
|
||||||
|
ret += ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := convertToString(val.Index(i), options)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += item
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret + "]", nil
|
||||||
|
case reflect.Map:
|
||||||
|
ret := "{"
|
||||||
|
|
||||||
|
for i, key := range val.MapKeys() {
|
||||||
|
if i != 0 {
|
||||||
|
ret += ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
keyitem, err := convertToString(key, options)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := convertToString(val.MapIndex(key), options)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += keyitem + ":" + item
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret + "}", nil
|
||||||
|
case reflect.Ptr:
|
||||||
|
return convertToString(reflect.Indirect(val), options)
|
||||||
|
case reflect.Interface:
|
||||||
|
if !val.IsNil() {
|
||||||
|
return convertToString(val.Elem(), options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertUnmarshal(val string, retval reflect.Value) (bool, error) {
|
||||||
|
if retval.Type().NumMethod() > 0 && retval.CanInterface() {
|
||||||
|
if unmarshaler, ok := retval.Interface().(Unmarshaler); ok {
|
||||||
|
if retval.IsNil() {
|
||||||
|
retval.Set(reflect.New(retval.Type().Elem()))
|
||||||
|
|
||||||
|
// Re-assign from the new value
|
||||||
|
unmarshaler = retval.Interface().(Unmarshaler)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, unmarshaler.UnmarshalFlag(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() {
|
||||||
|
return convertUnmarshal(val, retval.Addr())
|
||||||
|
}
|
||||||
|
|
||||||
|
if retval.Type().Kind() == reflect.Interface && !retval.IsNil() {
|
||||||
|
return convertUnmarshal(val, retval.Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert(val string, retval reflect.Value, options multiTag) error {
|
||||||
|
if ok, err := convertUnmarshal(val, retval); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := retval.Type()
|
||||||
|
|
||||||
|
// Support for time.Duration
|
||||||
|
if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
|
||||||
|
parsed, err := time.ParseDuration(val)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.SetInt(int64(parsed))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tp.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
retval.SetString(val)
|
||||||
|
case reflect.Bool:
|
||||||
|
if val == "" {
|
||||||
|
retval.SetBool(true)
|
||||||
|
} else {
|
||||||
|
b, err := strconv.ParseBool(val)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.SetBool(b)
|
||||||
|
}
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
base, err := getBase(options, 10)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := strconv.ParseInt(val, base, tp.Bits())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.SetInt(parsed)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
base, err := getBase(options, 10)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed, err := strconv.ParseUint(val, base, tp.Bits())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.SetUint(parsed)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
parsed, err := strconv.ParseFloat(val, tp.Bits())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.SetFloat(parsed)
|
||||||
|
case reflect.Slice:
|
||||||
|
elemtp := tp.Elem()
|
||||||
|
|
||||||
|
elemvalptr := reflect.New(elemtp)
|
||||||
|
elemval := reflect.Indirect(elemvalptr)
|
||||||
|
|
||||||
|
if err := convert(val, elemval, options); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.Set(reflect.Append(retval, elemval))
|
||||||
|
case reflect.Map:
|
||||||
|
parts := strings.SplitN(val, ":", 2)
|
||||||
|
|
||||||
|
key := parts[0]
|
||||||
|
var value string
|
||||||
|
|
||||||
|
if len(parts) == 2 {
|
||||||
|
value = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
keytp := tp.Key()
|
||||||
|
keyval := reflect.New(keytp)
|
||||||
|
|
||||||
|
if err := convert(key, keyval, options); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
valuetp := tp.Elem()
|
||||||
|
valueval := reflect.New(valuetp)
|
||||||
|
|
||||||
|
if err := convert(value, valueval, options); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if retval.IsNil() {
|
||||||
|
retval.Set(reflect.MakeMap(tp))
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval))
|
||||||
|
case reflect.Ptr:
|
||||||
|
if retval.IsNil() {
|
||||||
|
retval.Set(reflect.New(retval.Type().Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return convert(val, reflect.Indirect(retval), options)
|
||||||
|
case reflect.Interface:
|
||||||
|
if !retval.IsNil() {
|
||||||
|
return convert(val, retval.Elem(), options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPrint(s string) bool {
|
||||||
|
for _, c := range s {
|
||||||
|
if !strconv.IsPrint(c) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteIfNeeded(s string) string {
|
||||||
|
if !isPrint(s) {
|
||||||
|
return strconv.Quote(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteIfNeededV(s []string) []string {
|
||||||
|
ret := make([]string, len(s))
|
||||||
|
|
||||||
|
for i, v := range s {
|
||||||
|
ret[i] = quoteIfNeeded(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func quoteV(s []string) []string {
|
||||||
|
ret := make([]string, len(s))
|
||||||
|
|
||||||
|
for i, v := range s {
|
||||||
|
ret[i] = strconv.Quote(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquoteIfPossible(s string) (string, error) {
|
||||||
|
if len(s) == 0 || s[0] != '"' {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.Unquote(s)
|
||||||
|
}
|
134
vendor/github.com/jessevdk/go-flags/error.go
generated
vendored
Normal file
134
vendor/github.com/jessevdk/go-flags/error.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorType represents the type of error.
|
||||||
|
type ErrorType uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ErrUnknown indicates a generic error.
|
||||||
|
ErrUnknown ErrorType = iota
|
||||||
|
|
||||||
|
// ErrExpectedArgument indicates that an argument was expected.
|
||||||
|
ErrExpectedArgument
|
||||||
|
|
||||||
|
// ErrUnknownFlag indicates an unknown flag.
|
||||||
|
ErrUnknownFlag
|
||||||
|
|
||||||
|
// ErrUnknownGroup indicates an unknown group.
|
||||||
|
ErrUnknownGroup
|
||||||
|
|
||||||
|
// ErrMarshal indicates a marshalling error while converting values.
|
||||||
|
ErrMarshal
|
||||||
|
|
||||||
|
// ErrHelp indicates that the built-in help was shown (the error
|
||||||
|
// contains the help message).
|
||||||
|
ErrHelp
|
||||||
|
|
||||||
|
// ErrNoArgumentForBool indicates that an argument was given for a
|
||||||
|
// boolean flag (which don't not take any arguments).
|
||||||
|
ErrNoArgumentForBool
|
||||||
|
|
||||||
|
// ErrRequired indicates that a required flag was not provided.
|
||||||
|
ErrRequired
|
||||||
|
|
||||||
|
// ErrShortNameTooLong indicates that a short flag name was specified,
|
||||||
|
// longer than one character.
|
||||||
|
ErrShortNameTooLong
|
||||||
|
|
||||||
|
// ErrDuplicatedFlag indicates that a short or long flag has been
|
||||||
|
// defined more than once
|
||||||
|
ErrDuplicatedFlag
|
||||||
|
|
||||||
|
// ErrTag indicates an error while parsing flag tags.
|
||||||
|
ErrTag
|
||||||
|
|
||||||
|
// ErrCommandRequired indicates that a command was required but not
|
||||||
|
// specified
|
||||||
|
ErrCommandRequired
|
||||||
|
|
||||||
|
// ErrUnknownCommand indicates that an unknown command was specified.
|
||||||
|
ErrUnknownCommand
|
||||||
|
|
||||||
|
// ErrInvalidChoice indicates an invalid option value which only allows
|
||||||
|
// a certain number of choices.
|
||||||
|
ErrInvalidChoice
|
||||||
|
|
||||||
|
// ErrInvalidTag indicates an invalid tag or invalid use of an existing tag
|
||||||
|
ErrInvalidTag
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e ErrorType) String() string {
|
||||||
|
switch e {
|
||||||
|
case ErrUnknown:
|
||||||
|
return "unknown"
|
||||||
|
case ErrExpectedArgument:
|
||||||
|
return "expected argument"
|
||||||
|
case ErrUnknownFlag:
|
||||||
|
return "unknown flag"
|
||||||
|
case ErrUnknownGroup:
|
||||||
|
return "unknown group"
|
||||||
|
case ErrMarshal:
|
||||||
|
return "marshal"
|
||||||
|
case ErrHelp:
|
||||||
|
return "help"
|
||||||
|
case ErrNoArgumentForBool:
|
||||||
|
return "no argument for bool"
|
||||||
|
case ErrRequired:
|
||||||
|
return "required"
|
||||||
|
case ErrShortNameTooLong:
|
||||||
|
return "short name too long"
|
||||||
|
case ErrDuplicatedFlag:
|
||||||
|
return "duplicated flag"
|
||||||
|
case ErrTag:
|
||||||
|
return "tag"
|
||||||
|
case ErrCommandRequired:
|
||||||
|
return "command required"
|
||||||
|
case ErrUnknownCommand:
|
||||||
|
return "unknown command"
|
||||||
|
case ErrInvalidChoice:
|
||||||
|
return "invalid choice"
|
||||||
|
case ErrInvalidTag:
|
||||||
|
return "invalid tag"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unrecognized error type"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error represents a parser error. The error returned from Parse is of this
|
||||||
|
// type. The error contains both a Type and Message.
|
||||||
|
type Error struct {
|
||||||
|
// The type of error
|
||||||
|
Type ErrorType
|
||||||
|
|
||||||
|
// The error message
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the error's message
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func newError(tp ErrorType, message string) *Error {
|
||||||
|
return &Error{
|
||||||
|
Type: tp,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newErrorf(tp ErrorType, format string, args ...interface{}) *Error {
|
||||||
|
return newError(tp, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapError(err error) *Error {
|
||||||
|
ret, ok := err.(*Error)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return newError(ErrUnknown, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
258
vendor/github.com/jessevdk/go-flags/flags.go
generated
vendored
Normal file
258
vendor/github.com/jessevdk/go-flags/flags.go
generated
vendored
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Copyright 2012 Jesse van den Kieboom. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package flags provides an extensive command line option parser.
|
||||||
|
The flags package is similar in functionality to the go built-in flag package
|
||||||
|
but provides more options and uses reflection to provide a convenient and
|
||||||
|
succinct way of specifying command line options.
|
||||||
|
|
||||||
|
|
||||||
|
Supported features
|
||||||
|
|
||||||
|
The following features are supported in go-flags:
|
||||||
|
|
||||||
|
Options with short names (-v)
|
||||||
|
Options with long names (--verbose)
|
||||||
|
Options with and without arguments (bool v.s. other type)
|
||||||
|
Options with optional arguments and default values
|
||||||
|
Option default values from ENVIRONMENT_VARIABLES, including slice and map values
|
||||||
|
Multiple option groups each containing a set of options
|
||||||
|
Generate and print well-formatted help message
|
||||||
|
Passing remaining command line arguments after -- (optional)
|
||||||
|
Ignoring unknown command line options (optional)
|
||||||
|
Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification
|
||||||
|
Supports multiple short options -aux
|
||||||
|
Supports all primitive go types (string, int{8..64}, uint{8..64}, float)
|
||||||
|
Supports same option multiple times (can store in slice or last option counts)
|
||||||
|
Supports maps
|
||||||
|
Supports function callbacks
|
||||||
|
Supports namespaces for (nested) option groups
|
||||||
|
|
||||||
|
Additional features specific to Windows:
|
||||||
|
Options with short names (/v)
|
||||||
|
Options with long names (/verbose)
|
||||||
|
Windows-style options with arguments use a colon as the delimiter
|
||||||
|
Modify generated help message with Windows-style / options
|
||||||
|
Windows style options can be disabled at build time using the "forceposix"
|
||||||
|
build tag
|
||||||
|
|
||||||
|
|
||||||
|
Basic usage
|
||||||
|
|
||||||
|
The flags package uses structs, reflection and struct field tags
|
||||||
|
to allow users to specify command line options. This results in very simple
|
||||||
|
and concise specification of your application options. For example:
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
|
||||||
|
}
|
||||||
|
|
||||||
|
This specifies one option with a short name -v and a long name --verbose.
|
||||||
|
When either -v or --verbose is found on the command line, a 'true' value
|
||||||
|
will be appended to the Verbose field. e.g. when specifying -vvv, the
|
||||||
|
resulting value of Verbose will be {[true, true, true]}.
|
||||||
|
|
||||||
|
Slice options work exactly the same as primitive type options, except that
|
||||||
|
whenever the option is encountered, a value is appended to the slice.
|
||||||
|
|
||||||
|
Map options from string to primitive type are also supported. On the command
|
||||||
|
line, you specify the value for such an option as key:value. For example
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
AuthorInfo string[string] `short:"a"`
|
||||||
|
}
|
||||||
|
|
||||||
|
Then, the AuthorInfo map can be filled with something like
|
||||||
|
-a name:Jesse -a "surname:van den Kieboom".
|
||||||
|
|
||||||
|
Finally, for full control over the conversion between command line argument
|
||||||
|
values and options, user defined types can choose to implement the Marshaler
|
||||||
|
and Unmarshaler interfaces.
|
||||||
|
|
||||||
|
|
||||||
|
Available field tags
|
||||||
|
|
||||||
|
The following is a list of tags for struct fields supported by go-flags:
|
||||||
|
|
||||||
|
short: the short name of the option (single character)
|
||||||
|
long: the long name of the option
|
||||||
|
required: if non empty, makes the option required to appear on the command
|
||||||
|
line. If a required option is not present, the parser will
|
||||||
|
return ErrRequired (optional)
|
||||||
|
description: the description of the option (optional)
|
||||||
|
long-description: the long description of the option. Currently only
|
||||||
|
displayed in generated man pages (optional)
|
||||||
|
no-flag: if non-empty, this field is ignored as an option (optional)
|
||||||
|
|
||||||
|
optional: if non-empty, makes the argument of the option optional. When an
|
||||||
|
argument is optional it can only be specified using
|
||||||
|
--option=argument (optional)
|
||||||
|
optional-value: the value of an optional option when the option occurs
|
||||||
|
without an argument. This tag can be specified multiple
|
||||||
|
times in the case of maps or slices (optional)
|
||||||
|
default: the default value of an option. This tag can be specified
|
||||||
|
multiple times in the case of slices or maps (optional)
|
||||||
|
default-mask: when specified, this value will be displayed in the help
|
||||||
|
instead of the actual default value. This is useful
|
||||||
|
mostly for hiding otherwise sensitive information from
|
||||||
|
showing up in the help. If default-mask takes the special
|
||||||
|
value "-", then no default value will be shown at all
|
||||||
|
(optional)
|
||||||
|
env: the default value of the option is overridden from the
|
||||||
|
specified environment variable, if one has been defined.
|
||||||
|
(optional)
|
||||||
|
env-delim: the 'env' default value from environment is split into
|
||||||
|
multiple values with the given delimiter string, use with
|
||||||
|
slices and maps (optional)
|
||||||
|
value-name: the name of the argument value (to be shown in the help)
|
||||||
|
(optional)
|
||||||
|
choice: limits the values for an option to a set of values.
|
||||||
|
This tag can be specified multiple times (optional)
|
||||||
|
hidden: if non-empty, the option is not visible in the help or man page.
|
||||||
|
|
||||||
|
base: a base (radix) used to convert strings to integer values, the
|
||||||
|
default base is 10 (i.e. decimal) (optional)
|
||||||
|
|
||||||
|
ini-name: the explicit ini option name (optional)
|
||||||
|
no-ini: if non-empty this field is ignored as an ini option
|
||||||
|
(optional)
|
||||||
|
|
||||||
|
group: when specified on a struct field, makes the struct
|
||||||
|
field a separate group with the given name (optional)
|
||||||
|
namespace: when specified on a group struct field, the namespace
|
||||||
|
gets prepended to every option's long name and
|
||||||
|
subgroup's namespace of this group, separated by
|
||||||
|
the parser's namespace delimiter (optional)
|
||||||
|
command: when specified on a struct field, makes the struct
|
||||||
|
field a (sub)command with the given name (optional)
|
||||||
|
subcommands-optional: when specified on a command struct field, makes
|
||||||
|
any subcommands of that command optional (optional)
|
||||||
|
alias: when specified on a command struct field, adds the
|
||||||
|
specified name as an alias for the command. Can be
|
||||||
|
be specified multiple times to add more than one
|
||||||
|
alias (optional)
|
||||||
|
positional-args: when specified on a field with a struct type,
|
||||||
|
uses the fields of that struct to parse remaining
|
||||||
|
positional command line arguments into (in order
|
||||||
|
of the fields). If a field has a slice type,
|
||||||
|
then all remaining arguments will be added to it.
|
||||||
|
Positional arguments are optional by default,
|
||||||
|
unless the "required" tag is specified together
|
||||||
|
with the "positional-args" tag. The "required" tag
|
||||||
|
can also be set on the individual rest argument
|
||||||
|
fields, to require only the first N positional
|
||||||
|
arguments. If the "required" tag is set on the
|
||||||
|
rest arguments slice, then its value determines
|
||||||
|
the minimum amount of rest arguments that needs to
|
||||||
|
be provided (e.g. `required:"2"`) (optional)
|
||||||
|
positional-arg-name: used on a field in a positional argument struct; name
|
||||||
|
of the positional argument placeholder to be shown in
|
||||||
|
the help (optional)
|
||||||
|
|
||||||
|
Either the `short:` tag or the `long:` must be specified to make the field eligible as an
|
||||||
|
option.
|
||||||
|
|
||||||
|
|
||||||
|
Option groups
|
||||||
|
|
||||||
|
Option groups are a simple way to semantically separate your options. All
|
||||||
|
options in a particular group are shown together in the help under the name
|
||||||
|
of the group. Namespaces can be used to specify option long names more
|
||||||
|
precisely and emphasize the options affiliation to their group.
|
||||||
|
|
||||||
|
There are currently three ways to specify option groups.
|
||||||
|
|
||||||
|
1. Use NewNamedParser specifying the various option groups.
|
||||||
|
2. Use AddGroup to add a group to an existing parser.
|
||||||
|
3. Add a struct field to the top-level options annotated with the
|
||||||
|
group:"group-name" tag.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Commands
|
||||||
|
|
||||||
|
The flags package also has basic support for commands. Commands are often
|
||||||
|
used in monolithic applications that support various commands or actions.
|
||||||
|
Take git for example, all of the add, commit, checkout, etc. are called
|
||||||
|
commands. Using commands you can easily separate multiple functions of your
|
||||||
|
application.
|
||||||
|
|
||||||
|
There are currently two ways to specify a command.
|
||||||
|
|
||||||
|
1. Use AddCommand on an existing parser.
|
||||||
|
2. Add a struct field to your options struct annotated with the
|
||||||
|
command:"command-name" tag.
|
||||||
|
|
||||||
|
The most common, idiomatic way to implement commands is to define a global
|
||||||
|
parser instance and implement each command in a separate file. These
|
||||||
|
command files should define a go init function which calls AddCommand on
|
||||||
|
the global parser.
|
||||||
|
|
||||||
|
When parsing ends and there is an active command and that command implements
|
||||||
|
the Commander interface, then its Execute method will be run with the
|
||||||
|
remaining command line arguments.
|
||||||
|
|
||||||
|
Command structs can have options which become valid to parse after the
|
||||||
|
command has been specified on the command line, in addition to the options
|
||||||
|
of all the parent commands. I.e. considering a -v flag on the parser and an
|
||||||
|
add command, the following are equivalent:
|
||||||
|
|
||||||
|
./app -v add
|
||||||
|
./app add -v
|
||||||
|
|
||||||
|
However, if the -v flag is defined on the add command, then the first of
|
||||||
|
the two examples above would fail since the -v flag is not defined before
|
||||||
|
the add command.
|
||||||
|
|
||||||
|
|
||||||
|
Completion
|
||||||
|
|
||||||
|
go-flags has builtin support to provide bash completion of flags, commands
|
||||||
|
and argument values. To use completion, the binary which uses go-flags
|
||||||
|
can be invoked in a special environment to list completion of the current
|
||||||
|
command line argument. It should be noted that this `executes` your application,
|
||||||
|
and it is up to the user to make sure there are no negative side effects (for
|
||||||
|
example from init functions).
|
||||||
|
|
||||||
|
Setting the environment variable `GO_FLAGS_COMPLETION=1` enables completion
|
||||||
|
by replacing the argument parsing routine with the completion routine which
|
||||||
|
outputs completions for the passed arguments. The basic invocation to
|
||||||
|
complete a set of arguments is therefore:
|
||||||
|
|
||||||
|
GO_FLAGS_COMPLETION=1 ./completion-example arg1 arg2 arg3
|
||||||
|
|
||||||
|
where `completion-example` is the binary, `arg1` and `arg2` are
|
||||||
|
the current arguments, and `arg3` (the last argument) is the argument
|
||||||
|
to be completed. If the GO_FLAGS_COMPLETION is set to "verbose", then
|
||||||
|
descriptions of possible completion items will also be shown, if there
|
||||||
|
are more than 1 completion items.
|
||||||
|
|
||||||
|
To use this with bash completion, a simple file can be written which
|
||||||
|
calls the binary which supports go-flags completion:
|
||||||
|
|
||||||
|
_completion_example() {
|
||||||
|
# All arguments except the first one
|
||||||
|
args=("${COMP_WORDS[@]:1:$COMP_CWORD}")
|
||||||
|
|
||||||
|
# Only split on newlines
|
||||||
|
local IFS=$'\n'
|
||||||
|
|
||||||
|
# Call completion (note that the first element of COMP_WORDS is
|
||||||
|
# the executable itself)
|
||||||
|
COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}"))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -F _completion_example completion-example
|
||||||
|
|
||||||
|
Completion requires the parser option PassDoubleDash and is therefore enforced if the environment variable GO_FLAGS_COMPLETION is set.
|
||||||
|
|
||||||
|
Customized completion for argument values is supported by implementing
|
||||||
|
the flags.Completer interface for the argument value type. An example
|
||||||
|
of a type which does so is the flags.Filename type, an alias of string
|
||||||
|
allowing simple filename completion. A slice or array argument value
|
||||||
|
whose element type implements flags.Completer will also be completed.
|
||||||
|
*/
|
||||||
|
package flags
|
406
vendor/github.com/jessevdk/go-flags/group.go
generated
vendored
Normal file
406
vendor/github.com/jessevdk/go-flags/group.go
generated
vendored
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
// Copyright 2012 Jesse van den Kieboom. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrNotPointerToStruct indicates that a provided data container is not
|
||||||
|
// a pointer to a struct. Only pointers to structs are valid data containers
|
||||||
|
// for options.
|
||||||
|
var ErrNotPointerToStruct = errors.New("provided data is not a pointer to struct")
|
||||||
|
|
||||||
|
// Group represents an option group. Option groups can be used to logically
|
||||||
|
// group options together under a description. Groups are only used to provide
|
||||||
|
// more structure to options both for the user (as displayed in the help message)
|
||||||
|
// and for you, since groups can be nested.
|
||||||
|
type Group struct {
|
||||||
|
// A short description of the group. The
|
||||||
|
// short description is primarily used in the built-in generated help
|
||||||
|
// message
|
||||||
|
ShortDescription string
|
||||||
|
|
||||||
|
// A long description of the group. The long
|
||||||
|
// description is primarily used to present information on commands
|
||||||
|
// (Command embeds Group) in the built-in generated help and man pages.
|
||||||
|
LongDescription string
|
||||||
|
|
||||||
|
// The namespace of the group
|
||||||
|
Namespace string
|
||||||
|
|
||||||
|
// If true, the group is not displayed in the help or man page
|
||||||
|
Hidden bool
|
||||||
|
|
||||||
|
// The parent of the group or nil if it has no parent
|
||||||
|
parent interface{}
|
||||||
|
|
||||||
|
// All the options in the group
|
||||||
|
options []*Option
|
||||||
|
|
||||||
|
// All the subgroups
|
||||||
|
groups []*Group
|
||||||
|
|
||||||
|
// Whether the group represents the built-in help group
|
||||||
|
isBuiltinHelp bool
|
||||||
|
|
||||||
|
data interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type scanHandler func(reflect.Value, *reflect.StructField) (bool, error)
|
||||||
|
|
||||||
|
// AddGroup adds a new group to the command with the given name and data. The
|
||||||
|
// data needs to be a pointer to a struct from which the fields indicate which
|
||||||
|
// options are in the group.
|
||||||
|
func (g *Group) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) {
|
||||||
|
group := newGroup(shortDescription, longDescription, data)
|
||||||
|
|
||||||
|
group.parent = g
|
||||||
|
|
||||||
|
if err := group.scan(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.groups = append(g.groups, group)
|
||||||
|
return group, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Groups returns the list of groups embedded in this group.
|
||||||
|
func (g *Group) Groups() []*Group {
|
||||||
|
return g.groups
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options returns the list of options in this group.
|
||||||
|
func (g *Group) Options() []*Option {
|
||||||
|
return g.options
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find locates the subgroup with the given short description and returns it.
|
||||||
|
// If no such group can be found Find will return nil. Note that the description
|
||||||
|
// is matched case insensitively.
|
||||||
|
func (g *Group) Find(shortDescription string) *Group {
|
||||||
|
lshortDescription := strings.ToLower(shortDescription)
|
||||||
|
|
||||||
|
var ret *Group
|
||||||
|
|
||||||
|
g.eachGroup(func(gg *Group) {
|
||||||
|
if gg != g && strings.ToLower(gg.ShortDescription) == lshortDescription {
|
||||||
|
ret = gg
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) findOption(matcher func(*Option) bool) (option *Option) {
|
||||||
|
g.eachGroup(func(g *Group) {
|
||||||
|
for _, opt := range g.options {
|
||||||
|
if option == nil && matcher(opt) {
|
||||||
|
option = opt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindOptionByLongName finds an option that is part of the group, or any of its
|
||||||
|
// subgroups, by matching its long name (including the option namespace).
|
||||||
|
func (g *Group) FindOptionByLongName(longName string) *Option {
|
||||||
|
return g.findOption(func(option *Option) bool {
|
||||||
|
return option.LongNameWithNamespace() == longName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindOptionByShortName finds an option that is part of the group, or any of
|
||||||
|
// its subgroups, by matching its short name.
|
||||||
|
func (g *Group) FindOptionByShortName(shortName rune) *Option {
|
||||||
|
return g.findOption(func(option *Option) bool {
|
||||||
|
return option.ShortName == shortName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGroup(shortDescription string, longDescription string, data interface{}) *Group {
|
||||||
|
return &Group{
|
||||||
|
ShortDescription: shortDescription,
|
||||||
|
LongDescription: longDescription,
|
||||||
|
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option {
|
||||||
|
prio := 0
|
||||||
|
var retopt *Option
|
||||||
|
|
||||||
|
g.eachGroup(func(g *Group) {
|
||||||
|
for _, opt := range g.options {
|
||||||
|
if namematch != nil && namematch(opt, name) && prio < 4 {
|
||||||
|
retopt = opt
|
||||||
|
prio = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == opt.field.Name && prio < 3 {
|
||||||
|
retopt = opt
|
||||||
|
prio = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == opt.LongNameWithNamespace() && prio < 2 {
|
||||||
|
retopt = opt
|
||||||
|
prio = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 {
|
||||||
|
retopt = opt
|
||||||
|
prio = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return retopt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) eachGroup(f func(*Group)) {
|
||||||
|
f(g)
|
||||||
|
|
||||||
|
for _, gg := range g.groups {
|
||||||
|
gg.eachGroup(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStringFalsy(s string) bool {
|
||||||
|
return s == "" || s == "false" || s == "no" || s == "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error {
|
||||||
|
stype := realval.Type()
|
||||||
|
|
||||||
|
if sfield != nil {
|
||||||
|
if ok, err := handler(realval, sfield); err != nil {
|
||||||
|
return err
|
||||||
|
} else if ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < stype.NumField(); i++ {
|
||||||
|
field := stype.Field(i)
|
||||||
|
|
||||||
|
// PkgName is set only for non-exported fields, which we ignore
|
||||||
|
if field.PkgPath != "" && !field.Anonymous {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
mtag := newMultiTag(string(field.Tag))
|
||||||
|
|
||||||
|
if err := mtag.Parse(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip fields with the no-flag tag
|
||||||
|
if mtag.Get("no-flag") != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dive deep into structs or pointers to structs
|
||||||
|
kind := field.Type.Kind()
|
||||||
|
fld := realval.Field(i)
|
||||||
|
|
||||||
|
if kind == reflect.Struct {
|
||||||
|
if err := g.scanStruct(fld, &field, handler); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
|
||||||
|
flagCountBefore := len(g.options) + len(g.groups)
|
||||||
|
|
||||||
|
if fld.IsNil() {
|
||||||
|
fld = reflect.New(fld.Type().Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(g.options)+len(g.groups) != flagCountBefore {
|
||||||
|
realval.Field(i).Set(fld)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
longname := mtag.Get("long")
|
||||||
|
shortname := mtag.Get("short")
|
||||||
|
|
||||||
|
// Need at least either a short or long name
|
||||||
|
if longname == "" && shortname == "" && mtag.Get("ini-name") == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
short := rune(0)
|
||||||
|
rc := utf8.RuneCountInString(shortname)
|
||||||
|
|
||||||
|
if rc > 1 {
|
||||||
|
return newErrorf(ErrShortNameTooLong,
|
||||||
|
"short names can only be 1 character long, not `%s'",
|
||||||
|
shortname)
|
||||||
|
|
||||||
|
} else if rc == 1 {
|
||||||
|
short, _ = utf8.DecodeRuneInString(shortname)
|
||||||
|
}
|
||||||
|
|
||||||
|
description := mtag.Get("description")
|
||||||
|
def := mtag.GetMany("default")
|
||||||
|
|
||||||
|
optionalValue := mtag.GetMany("optional-value")
|
||||||
|
valueName := mtag.Get("value-name")
|
||||||
|
defaultMask := mtag.Get("default-mask")
|
||||||
|
|
||||||
|
optional := !isStringFalsy(mtag.Get("optional"))
|
||||||
|
required := !isStringFalsy(mtag.Get("required"))
|
||||||
|
choices := mtag.GetMany("choice")
|
||||||
|
hidden := !isStringFalsy(mtag.Get("hidden"))
|
||||||
|
|
||||||
|
option := &Option{
|
||||||
|
Description: description,
|
||||||
|
ShortName: short,
|
||||||
|
LongName: longname,
|
||||||
|
Default: def,
|
||||||
|
EnvDefaultKey: mtag.Get("env"),
|
||||||
|
EnvDefaultDelim: mtag.Get("env-delim"),
|
||||||
|
OptionalArgument: optional,
|
||||||
|
OptionalValue: optionalValue,
|
||||||
|
Required: required,
|
||||||
|
ValueName: valueName,
|
||||||
|
DefaultMask: defaultMask,
|
||||||
|
Choices: choices,
|
||||||
|
Hidden: hidden,
|
||||||
|
|
||||||
|
group: g,
|
||||||
|
|
||||||
|
field: field,
|
||||||
|
value: realval.Field(i),
|
||||||
|
tag: mtag,
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.isBool() && option.Default != nil {
|
||||||
|
return newErrorf(ErrInvalidTag,
|
||||||
|
"boolean flag `%s' may not have default values, they always default to `false' and can only be turned on",
|
||||||
|
option.shortAndLongName())
|
||||||
|
}
|
||||||
|
|
||||||
|
g.options = append(g.options, option)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) checkForDuplicateFlags() *Error {
|
||||||
|
shortNames := make(map[rune]*Option)
|
||||||
|
longNames := make(map[string]*Option)
|
||||||
|
|
||||||
|
var duplicateError *Error
|
||||||
|
|
||||||
|
g.eachGroup(func(g *Group) {
|
||||||
|
for _, option := range g.options {
|
||||||
|
if option.LongName != "" {
|
||||||
|
longName := option.LongNameWithNamespace()
|
||||||
|
|
||||||
|
if otherOption, ok := longNames[longName]; ok {
|
||||||
|
duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
longNames[longName] = option
|
||||||
|
}
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
if otherOption, ok := shortNames[option.ShortName]; ok {
|
||||||
|
duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
shortNames[option.ShortName] = option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return duplicateError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) {
|
||||||
|
mtag := newMultiTag(string(sfield.Tag))
|
||||||
|
|
||||||
|
if err := mtag.Parse(); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
subgroup := mtag.Get("group")
|
||||||
|
|
||||||
|
if len(subgroup) != 0 {
|
||||||
|
var ptrval reflect.Value
|
||||||
|
|
||||||
|
if realval.Kind() == reflect.Ptr {
|
||||||
|
ptrval = realval
|
||||||
|
|
||||||
|
if ptrval.IsNil() {
|
||||||
|
ptrval.Set(reflect.New(ptrval.Type()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptrval = realval.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
description := mtag.Get("description")
|
||||||
|
|
||||||
|
group, err := g.AddGroup(subgroup, description, ptrval.Interface())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
group.Namespace = mtag.Get("namespace")
|
||||||
|
group.Hidden = mtag.Get("hidden") != ""
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) scanType(handler scanHandler) error {
|
||||||
|
// Get all the public fields in the data struct
|
||||||
|
ptrval := reflect.ValueOf(g.data)
|
||||||
|
|
||||||
|
if ptrval.Type().Kind() != reflect.Ptr {
|
||||||
|
panic(ErrNotPointerToStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
stype := ptrval.Type().Elem()
|
||||||
|
|
||||||
|
if stype.Kind() != reflect.Struct {
|
||||||
|
panic(ErrNotPointerToStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
realval := reflect.Indirect(ptrval)
|
||||||
|
|
||||||
|
if err := g.scanStruct(realval, nil, handler); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.checkForDuplicateFlags(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) scan() error {
|
||||||
|
return g.scanType(g.scanSubGroupHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) groupByName(name string) *Group {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
return g.Find(name)
|
||||||
|
}
|
491
vendor/github.com/jessevdk/go-flags/help.go
generated
vendored
Normal file
491
vendor/github.com/jessevdk/go-flags/help.go
generated
vendored
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
// Copyright 2012 Jesse van den Kieboom. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type alignmentInfo struct {
|
||||||
|
maxLongLen int
|
||||||
|
hasShort bool
|
||||||
|
hasValueName bool
|
||||||
|
terminalColumns int
|
||||||
|
indent bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
paddingBeforeOption = 2
|
||||||
|
distanceBetweenOptionAndDescription = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *alignmentInfo) descriptionStart() int {
|
||||||
|
ret := a.maxLongLen + distanceBetweenOptionAndDescription
|
||||||
|
|
||||||
|
if a.hasShort {
|
||||||
|
ret += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.maxLongLen > 0 {
|
||||||
|
ret += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.hasValueName {
|
||||||
|
ret += 3
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *alignmentInfo) updateLen(name string, indent bool) {
|
||||||
|
l := utf8.RuneCountInString(name)
|
||||||
|
|
||||||
|
if indent {
|
||||||
|
l = l + 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if l > a.maxLongLen {
|
||||||
|
a.maxLongLen = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) getAlignmentInfo() alignmentInfo {
|
||||||
|
ret := alignmentInfo{
|
||||||
|
maxLongLen: 0,
|
||||||
|
hasShort: false,
|
||||||
|
hasValueName: false,
|
||||||
|
terminalColumns: getTerminalColumns(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.terminalColumns <= 0 {
|
||||||
|
ret.terminalColumns = 80
|
||||||
|
}
|
||||||
|
|
||||||
|
var prevcmd *Command
|
||||||
|
|
||||||
|
p.eachActiveGroup(func(c *Command, grp *Group) {
|
||||||
|
if c != prevcmd {
|
||||||
|
for _, arg := range c.args {
|
||||||
|
ret.updateLen(arg.Name, c != p.Command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, info := range grp.options {
|
||||||
|
if !info.canCli() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.ShortName != 0 {
|
||||||
|
ret.hasShort = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(info.ValueName) > 0 {
|
||||||
|
ret.hasValueName = true
|
||||||
|
}
|
||||||
|
|
||||||
|
l := info.LongNameWithNamespace() + info.ValueName
|
||||||
|
|
||||||
|
if len(info.Choices) != 0 {
|
||||||
|
l += "[" + strings.Join(info.Choices, "|") + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.updateLen(l, c != p.Command)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapText(s string, l int, prefix string) string {
|
||||||
|
var ret string
|
||||||
|
|
||||||
|
if l < 10 {
|
||||||
|
l = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic text wrapping of s at spaces to fit in l
|
||||||
|
lines := strings.Split(s, "\n")
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
var retline string
|
||||||
|
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
for len(line) > l {
|
||||||
|
// Try to split on space
|
||||||
|
suffix := ""
|
||||||
|
|
||||||
|
pos := strings.LastIndex(line[:l], " ")
|
||||||
|
|
||||||
|
if pos < 0 {
|
||||||
|
pos = l - 1
|
||||||
|
suffix = "-\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(retline) != 0 {
|
||||||
|
retline += "\n" + prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
retline += strings.TrimSpace(line[:pos]) + suffix
|
||||||
|
line = strings.TrimSpace(line[pos:])
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(line) > 0 {
|
||||||
|
if len(retline) != 0 {
|
||||||
|
retline += "\n" + prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
retline += line
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ret) > 0 {
|
||||||
|
ret += "\n"
|
||||||
|
|
||||||
|
if len(retline) > 0 {
|
||||||
|
ret += prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += retline
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alignmentInfo) {
|
||||||
|
line := &bytes.Buffer{}
|
||||||
|
|
||||||
|
prefix := paddingBeforeOption
|
||||||
|
|
||||||
|
if info.indent {
|
||||||
|
prefix += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.Hidden {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
line.WriteString(strings.Repeat(" ", prefix))
|
||||||
|
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
line.WriteRune(defaultShortOptDelimiter)
|
||||||
|
line.WriteRune(option.ShortName)
|
||||||
|
} else if info.hasShort {
|
||||||
|
line.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
descstart := info.descriptionStart() + paddingBeforeOption
|
||||||
|
|
||||||
|
if len(option.LongName) > 0 {
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
line.WriteString(", ")
|
||||||
|
} else if info.hasShort {
|
||||||
|
line.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
line.WriteString(defaultLongOptDelimiter)
|
||||||
|
line.WriteString(option.LongNameWithNamespace())
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.canArgument() {
|
||||||
|
line.WriteRune(defaultNameArgDelimiter)
|
||||||
|
|
||||||
|
if len(option.ValueName) > 0 {
|
||||||
|
line.WriteString(option.ValueName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(option.Choices) > 0 {
|
||||||
|
line.WriteString("[" + strings.Join(option.Choices, "|") + "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
written := line.Len()
|
||||||
|
line.WriteTo(writer)
|
||||||
|
|
||||||
|
if option.Description != "" {
|
||||||
|
dw := descstart - written
|
||||||
|
writer.WriteString(strings.Repeat(" ", dw))
|
||||||
|
|
||||||
|
var def string
|
||||||
|
|
||||||
|
if len(option.DefaultMask) != 0 {
|
||||||
|
if option.DefaultMask != "-" {
|
||||||
|
def = option.DefaultMask
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def = option.defaultLiteral
|
||||||
|
}
|
||||||
|
|
||||||
|
var envDef string
|
||||||
|
if option.EnvDefaultKey != "" {
|
||||||
|
var envPrintable string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
envPrintable = "%" + option.EnvDefaultKey + "%"
|
||||||
|
} else {
|
||||||
|
envPrintable = "$" + option.EnvDefaultKey
|
||||||
|
}
|
||||||
|
envDef = fmt.Sprintf(" [%s]", envPrintable)
|
||||||
|
}
|
||||||
|
|
||||||
|
var desc string
|
||||||
|
|
||||||
|
if def != "" {
|
||||||
|
desc = fmt.Sprintf("%s (default: %v)%s", option.Description, def, envDef)
|
||||||
|
} else {
|
||||||
|
desc = option.Description + envDef
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteString(wrapText(desc,
|
||||||
|
info.terminalColumns-descstart,
|
||||||
|
strings.Repeat(" ", descstart)))
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxCommandLength(s []*Command) int {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := len(s[0].Name)
|
||||||
|
|
||||||
|
for _, v := range s[1:] {
|
||||||
|
l := len(v.Name)
|
||||||
|
|
||||||
|
if l > ret {
|
||||||
|
ret = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHelp writes a help message containing all the possible options and
|
||||||
|
// their descriptions to the provided writer. Note that the HelpFlag parser
|
||||||
|
// option provides a convenient way to add a -h/--help option group to the
|
||||||
|
// command line parser which will automatically show the help messages using
|
||||||
|
// this method.
|
||||||
|
func (p *Parser) WriteHelp(writer io.Writer) {
|
||||||
|
if writer == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wr := bufio.NewWriter(writer)
|
||||||
|
aligninfo := p.getAlignmentInfo()
|
||||||
|
|
||||||
|
cmd := p.Command
|
||||||
|
|
||||||
|
for cmd.Active != nil {
|
||||||
|
cmd = cmd.Active
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Name != "" {
|
||||||
|
wr.WriteString("Usage:\n")
|
||||||
|
wr.WriteString(" ")
|
||||||
|
|
||||||
|
allcmd := p.Command
|
||||||
|
|
||||||
|
for allcmd != nil {
|
||||||
|
var usage string
|
||||||
|
|
||||||
|
if allcmd == p.Command {
|
||||||
|
if len(p.Usage) != 0 {
|
||||||
|
usage = p.Usage
|
||||||
|
} else if p.Options&HelpFlag != 0 {
|
||||||
|
usage = "[OPTIONS]"
|
||||||
|
}
|
||||||
|
} else if us, ok := allcmd.data.(Usage); ok {
|
||||||
|
usage = us.Usage()
|
||||||
|
} else if allcmd.hasCliOptions() {
|
||||||
|
usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(usage) != 0 {
|
||||||
|
fmt.Fprintf(wr, " %s %s", allcmd.Name, usage)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, " %s", allcmd.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(allcmd.args) > 0 {
|
||||||
|
fmt.Fprintf(wr, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, arg := range allcmd.args {
|
||||||
|
if i != 0 {
|
||||||
|
fmt.Fprintf(wr, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
name := arg.Name
|
||||||
|
|
||||||
|
if arg.isRemaining() {
|
||||||
|
name = name + "..."
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allcmd.ArgsRequired {
|
||||||
|
fmt.Fprintf(wr, "[%s]", name)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, "%s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if allcmd.Active == nil && len(allcmd.commands) > 0 {
|
||||||
|
var co, cc string
|
||||||
|
|
||||||
|
if allcmd.SubcommandsOptional {
|
||||||
|
co, cc = "[", "]"
|
||||||
|
} else {
|
||||||
|
co, cc = "<", ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
visibleCommands := allcmd.visibleCommands()
|
||||||
|
|
||||||
|
if len(visibleCommands) > 3 {
|
||||||
|
fmt.Fprintf(wr, " %scommand%s", co, cc)
|
||||||
|
} else {
|
||||||
|
subcommands := allcmd.sortedVisibleCommands()
|
||||||
|
names := make([]string, len(subcommands))
|
||||||
|
|
||||||
|
for i, subc := range subcommands {
|
||||||
|
names[i] = subc.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, " %s%s%s", co, strings.Join(names, " | "), cc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allcmd = allcmd.Active
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(wr)
|
||||||
|
|
||||||
|
if len(cmd.LongDescription) != 0 {
|
||||||
|
fmt.Fprintln(wr)
|
||||||
|
|
||||||
|
t := wrapText(cmd.LongDescription,
|
||||||
|
aligninfo.terminalColumns,
|
||||||
|
"")
|
||||||
|
|
||||||
|
fmt.Fprintln(wr, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := p.Command
|
||||||
|
|
||||||
|
for c != nil {
|
||||||
|
printcmd := c != p.Command
|
||||||
|
|
||||||
|
c.eachGroup(func(grp *Group) {
|
||||||
|
first := true
|
||||||
|
|
||||||
|
// Skip built-in help group for all commands except the top-level
|
||||||
|
// parser
|
||||||
|
if grp.Hidden || (grp.isBuiltinHelp && c != p.Command) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, info := range grp.options {
|
||||||
|
if !info.canCli() || info.Hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if printcmd {
|
||||||
|
fmt.Fprintf(wr, "\n[%s command options]\n", c.Name)
|
||||||
|
aligninfo.indent = true
|
||||||
|
printcmd = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if first && cmd.Group != grp {
|
||||||
|
fmt.Fprintln(wr)
|
||||||
|
|
||||||
|
if aligninfo.indent {
|
||||||
|
wr.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, "%s:\n", grp.ShortDescription)
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
|
||||||
|
p.writeHelpOption(wr, info, aligninfo)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var args []*Arg
|
||||||
|
for _, arg := range c.args {
|
||||||
|
if arg.Description != "" {
|
||||||
|
args = append(args, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
if c == p.Command {
|
||||||
|
fmt.Fprintf(wr, "\nArguments:\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, "\n[%s command arguments]\n", c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
descStart := aligninfo.descriptionStart() + paddingBeforeOption
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
argPrefix := strings.Repeat(" ", paddingBeforeOption)
|
||||||
|
argPrefix += arg.Name
|
||||||
|
|
||||||
|
if len(arg.Description) > 0 {
|
||||||
|
argPrefix += ":"
|
||||||
|
wr.WriteString(argPrefix)
|
||||||
|
|
||||||
|
// Space between "arg:" and the description start
|
||||||
|
descPadding := strings.Repeat(" ", descStart-len(argPrefix))
|
||||||
|
// How much space the description gets before wrapping
|
||||||
|
descWidth := aligninfo.terminalColumns - 1 - descStart
|
||||||
|
// Whitespace to which we can indent new description lines
|
||||||
|
descPrefix := strings.Repeat(" ", descStart)
|
||||||
|
|
||||||
|
wr.WriteString(descPadding)
|
||||||
|
wr.WriteString(wrapText(arg.Description, descWidth, descPrefix))
|
||||||
|
} else {
|
||||||
|
wr.WriteString(argPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(wr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c = c.Active
|
||||||
|
}
|
||||||
|
|
||||||
|
scommands := cmd.sortedVisibleCommands()
|
||||||
|
|
||||||
|
if len(scommands) > 0 {
|
||||||
|
maxnamelen := maxCommandLength(scommands)
|
||||||
|
|
||||||
|
fmt.Fprintln(wr)
|
||||||
|
fmt.Fprintln(wr, "Available commands:")
|
||||||
|
|
||||||
|
for _, c := range scommands {
|
||||||
|
fmt.Fprintf(wr, " %s", c.Name)
|
||||||
|
|
||||||
|
if len(c.ShortDescription) > 0 {
|
||||||
|
pad := strings.Repeat(" ", maxnamelen-len(c.Name))
|
||||||
|
fmt.Fprintf(wr, "%s %s", pad, c.ShortDescription)
|
||||||
|
|
||||||
|
if len(c.Aliases) > 0 {
|
||||||
|
fmt.Fprintf(wr, " (aliases: %s)", strings.Join(c.Aliases, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(wr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wr.Flush()
|
||||||
|
}
|
597
vendor/github.com/jessevdk/go-flags/ini.go
generated
vendored
Normal file
597
vendor/github.com/jessevdk/go-flags/ini.go
generated
vendored
Normal file
@ -0,0 +1,597 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IniError contains location information on where an error occurred.
|
||||||
|
type IniError struct {
|
||||||
|
// The error message.
|
||||||
|
Message string
|
||||||
|
|
||||||
|
// The filename of the file in which the error occurred.
|
||||||
|
File string
|
||||||
|
|
||||||
|
// The line number at which the error occurred.
|
||||||
|
LineNumber uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error provides a "file:line: message" formatted message of the ini error.
|
||||||
|
func (x *IniError) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s:%d: %s",
|
||||||
|
x.File,
|
||||||
|
x.LineNumber,
|
||||||
|
x.Message,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IniOptions for writing
|
||||||
|
type IniOptions uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// IniNone indicates no options.
|
||||||
|
IniNone IniOptions = 0
|
||||||
|
|
||||||
|
// IniIncludeDefaults indicates that default values should be written.
|
||||||
|
IniIncludeDefaults = 1 << iota
|
||||||
|
|
||||||
|
// IniCommentDefaults indicates that if IniIncludeDefaults is used
|
||||||
|
// options with default values are written but commented out.
|
||||||
|
IniCommentDefaults
|
||||||
|
|
||||||
|
// IniIncludeComments indicates that comments containing the description
|
||||||
|
// of an option should be written.
|
||||||
|
IniIncludeComments
|
||||||
|
|
||||||
|
// IniDefault provides a default set of options.
|
||||||
|
IniDefault = IniIncludeComments
|
||||||
|
)
|
||||||
|
|
||||||
|
// IniParser is a utility to read and write flags options from and to ini
|
||||||
|
// formatted strings.
|
||||||
|
type IniParser struct {
|
||||||
|
ParseAsDefaults bool // override default flags
|
||||||
|
|
||||||
|
parser *Parser
|
||||||
|
}
|
||||||
|
|
||||||
|
type iniValue struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
Quoted bool
|
||||||
|
LineNumber uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type iniSection []iniValue
|
||||||
|
|
||||||
|
type ini struct {
|
||||||
|
File string
|
||||||
|
Sections map[string]iniSection
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIniParser creates a new ini parser for a given Parser.
|
||||||
|
func NewIniParser(p *Parser) *IniParser {
|
||||||
|
return &IniParser{
|
||||||
|
parser: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IniParse is a convenience function to parse command line options with default
|
||||||
|
// settings from an ini formatted file. The provided data is a pointer to a struct
|
||||||
|
// representing the default option group (named "Application Options"). For
|
||||||
|
// more control, use flags.NewParser.
|
||||||
|
func IniParse(filename string, data interface{}) error {
|
||||||
|
p := NewParser(data, Default)
|
||||||
|
|
||||||
|
return NewIniParser(p).ParseFile(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFile parses flags from an ini formatted file. See Parse for more
|
||||||
|
// information on the ini file format. The returned errors can be of the type
|
||||||
|
// flags.Error or flags.IniError.
|
||||||
|
func (i *IniParser) ParseFile(filename string) error {
|
||||||
|
ini, err := readIniFromFile(filename)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.parse(ini)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses flags from an ini format. You can use ParseFile as a
|
||||||
|
// convenience function to parse from a filename instead of a general
|
||||||
|
// io.Reader.
|
||||||
|
//
|
||||||
|
// The format of the ini file is as follows:
|
||||||
|
//
|
||||||
|
// [Option group name]
|
||||||
|
// option = value
|
||||||
|
//
|
||||||
|
// Each section in the ini file represents an option group or command in the
|
||||||
|
// flags parser. The default flags parser option group (i.e. when using
|
||||||
|
// flags.Parse) is named 'Application Options'. The ini option name is matched
|
||||||
|
// in the following order:
|
||||||
|
//
|
||||||
|
// 1. Compared to the ini-name tag on the option struct field (if present)
|
||||||
|
// 2. Compared to the struct field name
|
||||||
|
// 3. Compared to the option long name (if present)
|
||||||
|
// 4. Compared to the option short name (if present)
|
||||||
|
//
|
||||||
|
// Sections for nested groups and commands can be addressed using a dot `.'
|
||||||
|
// namespacing notation (i.e [subcommand.Options]). Group section names are
|
||||||
|
// matched case insensitive.
|
||||||
|
//
|
||||||
|
// The returned errors can be of the type flags.Error or flags.IniError.
|
||||||
|
func (i *IniParser) Parse(reader io.Reader) error {
|
||||||
|
ini, err := readIni(reader, "")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.parse(ini)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteFile writes the flags as ini format into a file. See Write
|
||||||
|
// for more information. The returned error occurs when the specified file
|
||||||
|
// could not be opened for writing.
|
||||||
|
func (i *IniParser) WriteFile(filename string, options IniOptions) error {
|
||||||
|
return writeIniToFile(i, filename, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the current values of all the flags to an ini format.
|
||||||
|
// See Parse for more information on the ini file format. You typically
|
||||||
|
// call this only after settings have been parsed since the default values of each
|
||||||
|
// option are stored just before parsing the flags (this is only relevant when
|
||||||
|
// IniIncludeDefaults is _not_ set in options).
|
||||||
|
func (i *IniParser) Write(writer io.Writer, options IniOptions) {
|
||||||
|
writeIni(i, writer, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFullLine(reader *bufio.Reader) (string, error) {
|
||||||
|
var line []byte
|
||||||
|
|
||||||
|
for {
|
||||||
|
l, more, err := reader.ReadLine()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if line == nil && !more {
|
||||||
|
return string(l), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
line = append(line, l...)
|
||||||
|
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(line), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func optionIniName(option *Option) string {
|
||||||
|
name := option.tag.Get("_read-ini-name")
|
||||||
|
|
||||||
|
if len(name) != 0 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
name = option.tag.Get("ini-name")
|
||||||
|
|
||||||
|
if len(name) != 0 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
return option.field.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeGroupIni(cmd *Command, group *Group, namespace string, writer io.Writer, options IniOptions) {
|
||||||
|
var sname string
|
||||||
|
|
||||||
|
if len(namespace) != 0 {
|
||||||
|
sname = namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd.Group != group && len(group.ShortDescription) != 0 {
|
||||||
|
if len(sname) != 0 {
|
||||||
|
sname += "."
|
||||||
|
}
|
||||||
|
|
||||||
|
sname += group.ShortDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
sectionwritten := false
|
||||||
|
comments := (options & IniIncludeComments) != IniNone
|
||||||
|
|
||||||
|
for _, option := range group.options {
|
||||||
|
if option.isFunc() || option.Hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(option.tag.Get("no-ini")) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val := option.value
|
||||||
|
|
||||||
|
if (options&IniIncludeDefaults) == IniNone && option.valueIsDefault() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sectionwritten {
|
||||||
|
fmt.Fprintf(writer, "[%s]\n", sname)
|
||||||
|
sectionwritten = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if comments && len(option.Description) != 0 {
|
||||||
|
fmt.Fprintf(writer, "; %s\n", option.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
oname := optionIniName(option)
|
||||||
|
|
||||||
|
commentOption := (options&(IniIncludeDefaults|IniCommentDefaults)) == IniIncludeDefaults|IniCommentDefaults && option.valueIsDefault()
|
||||||
|
|
||||||
|
kind := val.Type().Kind()
|
||||||
|
switch kind {
|
||||||
|
case reflect.Slice:
|
||||||
|
kind = val.Type().Elem().Kind()
|
||||||
|
|
||||||
|
if val.Len() == 0 {
|
||||||
|
writeOption(writer, oname, kind, "", "", true, option.iniQuote)
|
||||||
|
} else {
|
||||||
|
for idx := 0; idx < val.Len(); idx++ {
|
||||||
|
v, _ := convertToString(val.Index(idx), option.tag)
|
||||||
|
|
||||||
|
writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
kind = val.Type().Elem().Kind()
|
||||||
|
|
||||||
|
if val.Len() == 0 {
|
||||||
|
writeOption(writer, oname, kind, "", "", true, option.iniQuote)
|
||||||
|
} else {
|
||||||
|
mkeys := val.MapKeys()
|
||||||
|
keys := make([]string, len(val.MapKeys()))
|
||||||
|
kkmap := make(map[string]reflect.Value)
|
||||||
|
|
||||||
|
for i, k := range mkeys {
|
||||||
|
keys[i], _ = convertToString(k, option.tag)
|
||||||
|
kkmap[keys[i]] = k
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, k := range keys {
|
||||||
|
v, _ := convertToString(val.MapIndex(kkmap[k]), option.tag)
|
||||||
|
|
||||||
|
writeOption(writer, oname, kind, k, v, commentOption, option.iniQuote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
v, _ := convertToString(val, option.tag)
|
||||||
|
|
||||||
|
writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote)
|
||||||
|
}
|
||||||
|
|
||||||
|
if comments {
|
||||||
|
fmt.Fprintln(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sectionwritten && !comments {
|
||||||
|
fmt.Fprintln(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeOption(writer io.Writer, optionName string, optionType reflect.Kind, optionKey string, optionValue string, commentOption bool, forceQuote bool) {
|
||||||
|
if forceQuote || (optionType == reflect.String && !isPrint(optionValue)) {
|
||||||
|
optionValue = strconv.Quote(optionValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
comment := ""
|
||||||
|
if commentOption {
|
||||||
|
comment = "; "
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(writer, "%s%s =", comment, optionName)
|
||||||
|
|
||||||
|
if optionKey != "" {
|
||||||
|
fmt.Fprintf(writer, " %s:%s", optionKey, optionValue)
|
||||||
|
} else if optionValue != "" {
|
||||||
|
fmt.Fprintf(writer, " %s", optionValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeCommandIni(command *Command, namespace string, writer io.Writer, options IniOptions) {
|
||||||
|
command.eachGroup(func(group *Group) {
|
||||||
|
if !group.Hidden {
|
||||||
|
writeGroupIni(command, group, namespace, writer, options)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, c := range command.commands {
|
||||||
|
var nns string
|
||||||
|
|
||||||
|
if c.Hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(namespace) != 0 {
|
||||||
|
nns = c.Name + "." + nns
|
||||||
|
} else {
|
||||||
|
nns = c.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCommandIni(c, nns, writer, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeIni(parser *IniParser, writer io.Writer, options IniOptions) {
|
||||||
|
writeCommandIni(parser.parser.Command, "", writer, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeIniToFile(parser *IniParser, filename string, options IniOptions) error {
|
||||||
|
file, err := os.Create(filename)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
writeIni(parser, file, options)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readIniFromFile(filename string) (*ini, error) {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
return readIni(file, filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readIni(contents io.Reader, filename string) (*ini, error) {
|
||||||
|
ret := &ini{
|
||||||
|
File: filename,
|
||||||
|
Sections: make(map[string]iniSection),
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(contents)
|
||||||
|
|
||||||
|
// Empty global section
|
||||||
|
section := make(iniSection, 0, 10)
|
||||||
|
sectionname := ""
|
||||||
|
|
||||||
|
ret.Sections[sectionname] = section
|
||||||
|
|
||||||
|
var lineno uint
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, err := readFullLine(reader)
|
||||||
|
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lineno++
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
// Skip empty lines and lines starting with ; (comments)
|
||||||
|
if len(line) == 0 || line[0] == ';' || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if line[0] == '[' {
|
||||||
|
if line[0] != '[' || line[len(line)-1] != ']' {
|
||||||
|
return nil, &IniError{
|
||||||
|
Message: "malformed section header",
|
||||||
|
File: filename,
|
||||||
|
LineNumber: lineno,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := strings.TrimSpace(line[1 : len(line)-1])
|
||||||
|
|
||||||
|
if len(name) == 0 {
|
||||||
|
return nil, &IniError{
|
||||||
|
Message: "empty section name",
|
||||||
|
File: filename,
|
||||||
|
LineNumber: lineno,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sectionname = name
|
||||||
|
section = ret.Sections[name]
|
||||||
|
|
||||||
|
if section == nil {
|
||||||
|
section = make(iniSection, 0, 10)
|
||||||
|
ret.Sections[name] = section
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse option here
|
||||||
|
keyval := strings.SplitN(line, "=", 2)
|
||||||
|
|
||||||
|
if len(keyval) != 2 {
|
||||||
|
return nil, &IniError{
|
||||||
|
Message: fmt.Sprintf("malformed key=value (%s)", line),
|
||||||
|
File: filename,
|
||||||
|
LineNumber: lineno,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := strings.TrimSpace(keyval[0])
|
||||||
|
value := strings.TrimSpace(keyval[1])
|
||||||
|
quoted := false
|
||||||
|
|
||||||
|
if len(value) != 0 && value[0] == '"' {
|
||||||
|
if v, err := strconv.Unquote(value); err == nil {
|
||||||
|
value = v
|
||||||
|
|
||||||
|
quoted = true
|
||||||
|
} else {
|
||||||
|
return nil, &IniError{
|
||||||
|
Message: err.Error(),
|
||||||
|
File: filename,
|
||||||
|
LineNumber: lineno,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section = append(section, iniValue{
|
||||||
|
Name: name,
|
||||||
|
Value: value,
|
||||||
|
Quoted: quoted,
|
||||||
|
LineNumber: lineno,
|
||||||
|
})
|
||||||
|
|
||||||
|
ret.Sections[sectionname] = section
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IniParser) matchingGroups(name string) []*Group {
|
||||||
|
if len(name) == 0 {
|
||||||
|
var ret []*Group
|
||||||
|
|
||||||
|
i.parser.eachGroup(func(g *Group) {
|
||||||
|
ret = append(ret, g)
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
g := i.parser.groupByName(name)
|
||||||
|
|
||||||
|
if g != nil {
|
||||||
|
return []*Group{g}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IniParser) parse(ini *ini) error {
|
||||||
|
p := i.parser
|
||||||
|
|
||||||
|
var quotesLookup = make(map[*Option]bool)
|
||||||
|
|
||||||
|
for name, section := range ini.Sections {
|
||||||
|
groups := i.matchingGroups(name)
|
||||||
|
|
||||||
|
if len(groups) == 0 {
|
||||||
|
return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, inival := range section {
|
||||||
|
var opt *Option
|
||||||
|
|
||||||
|
for _, group := range groups {
|
||||||
|
opt = group.optionByName(inival.Name, func(o *Option, n string) bool {
|
||||||
|
return strings.ToLower(o.tag.Get("ini-name")) == strings.ToLower(n)
|
||||||
|
})
|
||||||
|
|
||||||
|
if opt != nil && len(opt.tag.Get("no-ini")) != 0 {
|
||||||
|
opt = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt == nil {
|
||||||
|
if (p.Options & IgnoreUnknown) == None {
|
||||||
|
return &IniError{
|
||||||
|
Message: fmt.Sprintf("unknown option: %s", inival.Name),
|
||||||
|
File: ini.File,
|
||||||
|
LineNumber: inival.LineNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// ini value is ignored if override is set and
|
||||||
|
// value was previously set from non default
|
||||||
|
if i.ParseAsDefaults && !opt.isSetDefault {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pval := &inival.Value
|
||||||
|
|
||||||
|
if !opt.canArgument() && len(inival.Value) == 0 {
|
||||||
|
pval = nil
|
||||||
|
} else {
|
||||||
|
if opt.value.Type().Kind() == reflect.Map {
|
||||||
|
parts := strings.SplitN(inival.Value, ":", 2)
|
||||||
|
|
||||||
|
// only handle unquoting
|
||||||
|
if len(parts) == 2 && parts[1][0] == '"' {
|
||||||
|
if v, err := strconv.Unquote(parts[1]); err == nil {
|
||||||
|
parts[1] = v
|
||||||
|
|
||||||
|
inival.Quoted = true
|
||||||
|
} else {
|
||||||
|
return &IniError{
|
||||||
|
Message: err.Error(),
|
||||||
|
File: ini.File,
|
||||||
|
LineNumber: inival.LineNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := parts[0] + ":" + parts[1]
|
||||||
|
|
||||||
|
pval = &s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := opt.set(pval); err != nil {
|
||||||
|
return &IniError{
|
||||||
|
Message: err.Error(),
|
||||||
|
File: ini.File,
|
||||||
|
LineNumber: inival.LineNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// either all INI values are quoted or only values who need quoting
|
||||||
|
if _, ok := quotesLookup[opt]; !inival.Quoted || !ok {
|
||||||
|
quotesLookup[opt] = inival.Quoted
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.tag.Set("_read-ini-name", inival.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for opt, quoted := range quotesLookup {
|
||||||
|
opt.iniQuote = quoted
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
205
vendor/github.com/jessevdk/go-flags/man.go
generated
vendored
Normal file
205
vendor/github.com/jessevdk/go-flags/man.go
generated
vendored
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func manQuote(s string) string {
|
||||||
|
return strings.Replace(s, "\\", "\\\\", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatForMan(wr io.Writer, s string) {
|
||||||
|
for {
|
||||||
|
idx := strings.IndexRune(s, '`')
|
||||||
|
|
||||||
|
if idx < 0 {
|
||||||
|
fmt.Fprintf(wr, "%s", manQuote(s))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, "%s", manQuote(s[:idx]))
|
||||||
|
|
||||||
|
s = s[idx+1:]
|
||||||
|
idx = strings.IndexRune(s, '\'')
|
||||||
|
|
||||||
|
if idx < 0 {
|
||||||
|
fmt.Fprintf(wr, "%s", manQuote(s))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx]))
|
||||||
|
s = s[idx+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeManPageOptions(wr io.Writer, grp *Group) {
|
||||||
|
grp.eachGroup(func(group *Group) {
|
||||||
|
if group.Hidden || len(group.options) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the parent (grp) has any subgroups, display their descriptions as
|
||||||
|
// subsection headers similar to the output of --help.
|
||||||
|
if group.ShortDescription != "" && len(grp.groups) > 0 {
|
||||||
|
fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription)
|
||||||
|
|
||||||
|
if group.LongDescription != "" {
|
||||||
|
formatForMan(wr, group.LongDescription)
|
||||||
|
fmt.Fprintln(wr, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range group.options {
|
||||||
|
if !opt.canCli() || opt.Hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(wr, ".TP")
|
||||||
|
fmt.Fprintf(wr, "\\fB")
|
||||||
|
|
||||||
|
if opt.ShortName != 0 {
|
||||||
|
fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opt.LongName) != 0 {
|
||||||
|
if opt.ShortName != 0 {
|
||||||
|
fmt.Fprintf(wr, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opt.ValueName) != 0 || opt.OptionalArgument {
|
||||||
|
if opt.OptionalArgument {
|
||||||
|
fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", ")))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(opt.Default) != 0 {
|
||||||
|
fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
|
||||||
|
} else if len(opt.EnvDefaultKey) != 0 {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvDefaultKey))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvDefaultKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.Required {
|
||||||
|
fmt.Fprintf(wr, " (\\fIrequired\\fR)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(wr, "\\fP")
|
||||||
|
|
||||||
|
if len(opt.Description) != 0 {
|
||||||
|
formatForMan(wr, opt.Description)
|
||||||
|
fmt.Fprintln(wr, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeManPageSubcommands(wr io.Writer, name string, root *Command) {
|
||||||
|
commands := root.sortedVisibleCommands()
|
||||||
|
|
||||||
|
for _, c := range commands {
|
||||||
|
var nn string
|
||||||
|
|
||||||
|
if c.Hidden {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(name) != 0 {
|
||||||
|
nn = name + " " + c.Name
|
||||||
|
} else {
|
||||||
|
nn = c.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
writeManPageCommand(wr, nn, root, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeManPageCommand(wr io.Writer, name string, root *Command, command *Command) {
|
||||||
|
fmt.Fprintf(wr, ".SS %s\n", name)
|
||||||
|
fmt.Fprintln(wr, command.ShortDescription)
|
||||||
|
|
||||||
|
if len(command.LongDescription) > 0 {
|
||||||
|
fmt.Fprintln(wr, "")
|
||||||
|
|
||||||
|
cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name))
|
||||||
|
|
||||||
|
if strings.HasPrefix(command.LongDescription, cmdstart) {
|
||||||
|
fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))
|
||||||
|
|
||||||
|
formatForMan(wr, command.LongDescription[len(cmdstart):])
|
||||||
|
fmt.Fprintln(wr, "")
|
||||||
|
} else {
|
||||||
|
formatForMan(wr, command.LongDescription)
|
||||||
|
fmt.Fprintln(wr, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var usage string
|
||||||
|
if us, ok := command.data.(Usage); ok {
|
||||||
|
usage = us.Usage()
|
||||||
|
} else if command.hasCliOptions() {
|
||||||
|
usage = fmt.Sprintf("[%s-OPTIONS]", command.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pre string
|
||||||
|
if root.hasCliOptions() {
|
||||||
|
pre = fmt.Sprintf("%s [OPTIONS] %s", root.Name, command.Name)
|
||||||
|
} else {
|
||||||
|
pre = fmt.Sprintf("%s %s", root.Name, command.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(usage) > 0 {
|
||||||
|
fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(command.Aliases) > 0 {
|
||||||
|
fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
writeManPageOptions(wr, command.Group)
|
||||||
|
writeManPageSubcommands(wr, name, command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteManPage writes a basic man page in groff format to the specified
|
||||||
|
// writer.
|
||||||
|
func (p *Parser) WriteManPage(wr io.Writer) {
|
||||||
|
t := time.Now()
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006"))
|
||||||
|
fmt.Fprintln(wr, ".SH NAME")
|
||||||
|
fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription))
|
||||||
|
fmt.Fprintln(wr, ".SH SYNOPSIS")
|
||||||
|
|
||||||
|
usage := p.Usage
|
||||||
|
|
||||||
|
if len(usage) == 0 {
|
||||||
|
usage = "[OPTIONS]"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
|
||||||
|
fmt.Fprintln(wr, ".SH DESCRIPTION")
|
||||||
|
|
||||||
|
formatForMan(wr, p.LongDescription)
|
||||||
|
fmt.Fprintln(wr, "")
|
||||||
|
|
||||||
|
fmt.Fprintln(wr, ".SH OPTIONS")
|
||||||
|
|
||||||
|
writeManPageOptions(wr, p.Command.Group)
|
||||||
|
|
||||||
|
if len(p.visibleCommands()) > 0 {
|
||||||
|
fmt.Fprintln(wr, ".SH COMMANDS")
|
||||||
|
|
||||||
|
writeManPageSubcommands(wr, "", p.Command)
|
||||||
|
}
|
||||||
|
}
|
140
vendor/github.com/jessevdk/go-flags/multitag.go
generated
vendored
Normal file
140
vendor/github.com/jessevdk/go-flags/multitag.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type multiTag struct {
|
||||||
|
value string
|
||||||
|
cache map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMultiTag(v string) multiTag {
|
||||||
|
return multiTag{
|
||||||
|
value: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) scan() (map[string][]string, error) {
|
||||||
|
v := x.value
|
||||||
|
|
||||||
|
ret := make(map[string][]string)
|
||||||
|
|
||||||
|
// This is mostly copied from reflect.StructTag.Get
|
||||||
|
for v != "" {
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
for i < len(v) && v[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v[i:]
|
||||||
|
|
||||||
|
if v == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan to colon to find key
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if i >= len(v) {
|
||||||
|
return nil, newErrorf(ErrTag, "expected `:' after key name, but got end of tag (in `%v`)", x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v[i] != ':' {
|
||||||
|
return nil, newErrorf(ErrTag, "expected `:' after key name, but got `%v' (in `%v`)", v[i], x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i+1 >= len(v) {
|
||||||
|
return nil, newErrorf(ErrTag, "expected `\"' to start tag value at end of tag (in `%v`)", x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v[i+1] != '"' {
|
||||||
|
return nil, newErrorf(ErrTag, "expected `\"' to start tag value, but got `%v' (in `%v`)", v[i+1], x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := v[:i]
|
||||||
|
v = v[i+1:]
|
||||||
|
|
||||||
|
// Scan quoted string to find value
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
for i < len(v) && v[i] != '"' {
|
||||||
|
if v[i] == '\n' {
|
||||||
|
return nil, newErrorf(ErrTag, "unexpected newline in tag value `%v' (in `%v`)", name, x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v[i] == '\\' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if i >= len(v) {
|
||||||
|
return nil, newErrorf(ErrTag, "expected end of tag value `\"' at end of tag (in `%v`)", x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := strconv.Unquote(v[:i+1])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, newErrorf(ErrTag, "Malformed value of tag `%v:%v` => %v (in `%v`)", name, v[:i+1], err, x.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v[i+1:]
|
||||||
|
|
||||||
|
ret[name] = append(ret[name], val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) Parse() error {
|
||||||
|
vals, err := x.scan()
|
||||||
|
x.cache = vals
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) cached() map[string][]string {
|
||||||
|
if x.cache == nil {
|
||||||
|
cache, _ := x.scan()
|
||||||
|
|
||||||
|
if cache == nil {
|
||||||
|
cache = make(map[string][]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
x.cache = cache
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) Get(key string) string {
|
||||||
|
c := x.cached()
|
||||||
|
|
||||||
|
if v, ok := c[key]; ok {
|
||||||
|
return v[len(v)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) GetMany(key string) []string {
|
||||||
|
c := x.cached()
|
||||||
|
return c[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) Set(key string, value string) {
|
||||||
|
c := x.cached()
|
||||||
|
c[key] = []string{value}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *multiTag) SetMany(key string, value []string) {
|
||||||
|
c := x.cached()
|
||||||
|
c[key] = value
|
||||||
|
}
|
459
vendor/github.com/jessevdk/go-flags/option.go
generated
vendored
Normal file
459
vendor/github.com/jessevdk/go-flags/option.go
generated
vendored
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Option flag information. Contains a description of the option, short and
|
||||||
|
// long name as well as a default value and whether an argument for this
|
||||||
|
// flag is optional.
|
||||||
|
type Option struct {
|
||||||
|
// The description of the option flag. This description is shown
|
||||||
|
// automatically in the built-in help.
|
||||||
|
Description string
|
||||||
|
|
||||||
|
// The short name of the option (a single character). If not 0, the
|
||||||
|
// option flag can be 'activated' using -<ShortName>. Either ShortName
|
||||||
|
// or LongName needs to be non-empty.
|
||||||
|
ShortName rune
|
||||||
|
|
||||||
|
// The long name of the option. If not "", the option flag can be
|
||||||
|
// activated using --<LongName>. Either ShortName or LongName needs
|
||||||
|
// to be non-empty.
|
||||||
|
LongName string
|
||||||
|
|
||||||
|
// The default value of the option.
|
||||||
|
Default []string
|
||||||
|
|
||||||
|
// The optional environment default value key name.
|
||||||
|
EnvDefaultKey string
|
||||||
|
|
||||||
|
// The optional delimiter string for EnvDefaultKey values.
|
||||||
|
EnvDefaultDelim string
|
||||||
|
|
||||||
|
// If true, specifies that the argument to an option flag is optional.
|
||||||
|
// When no argument to the flag is specified on the command line, the
|
||||||
|
// value of OptionalValue will be set in the field this option represents.
|
||||||
|
// This is only valid for non-boolean options.
|
||||||
|
OptionalArgument bool
|
||||||
|
|
||||||
|
// The optional value of the option. The optional value is used when
|
||||||
|
// the option flag is marked as having an OptionalArgument. This means
|
||||||
|
// that when the flag is specified, but no option argument is given,
|
||||||
|
// the value of the field this option represents will be set to
|
||||||
|
// OptionalValue. This is only valid for non-boolean options.
|
||||||
|
OptionalValue []string
|
||||||
|
|
||||||
|
// If true, the option _must_ be specified on the command line. If the
|
||||||
|
// option is not specified, the parser will generate an ErrRequired type
|
||||||
|
// error.
|
||||||
|
Required bool
|
||||||
|
|
||||||
|
// A name for the value of an option shown in the Help as --flag [ValueName]
|
||||||
|
ValueName string
|
||||||
|
|
||||||
|
// A mask value to show in the help instead of the default value. This
|
||||||
|
// is useful for hiding sensitive information in the help, such as
|
||||||
|
// passwords.
|
||||||
|
DefaultMask string
|
||||||
|
|
||||||
|
// If non empty, only a certain set of values is allowed for an option.
|
||||||
|
Choices []string
|
||||||
|
|
||||||
|
// If true, the option is not displayed in the help or man page
|
||||||
|
Hidden bool
|
||||||
|
|
||||||
|
// The group which the option belongs to
|
||||||
|
group *Group
|
||||||
|
|
||||||
|
// The struct field which the option represents.
|
||||||
|
field reflect.StructField
|
||||||
|
|
||||||
|
// The struct field value which the option represents.
|
||||||
|
value reflect.Value
|
||||||
|
|
||||||
|
// Determines if the option will be always quoted in the INI output
|
||||||
|
iniQuote bool
|
||||||
|
|
||||||
|
tag multiTag
|
||||||
|
isSet bool
|
||||||
|
isSetDefault bool
|
||||||
|
preventDefault bool
|
||||||
|
|
||||||
|
defaultLiteral string
|
||||||
|
}
|
||||||
|
|
||||||
|
// LongNameWithNamespace returns the option's long name with the group namespaces
|
||||||
|
// prepended by walking up the option's group tree. Namespaces and the long name
|
||||||
|
// itself are separated by the parser's namespace delimiter. If the long name is
|
||||||
|
// empty an empty string is returned.
|
||||||
|
func (option *Option) LongNameWithNamespace() string {
|
||||||
|
if len(option.LongName) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the namespace delimiter from the parser which is always at the
|
||||||
|
// end of the group hierarchy
|
||||||
|
namespaceDelimiter := ""
|
||||||
|
g := option.group
|
||||||
|
|
||||||
|
for {
|
||||||
|
if p, ok := g.parent.(*Parser); ok {
|
||||||
|
namespaceDelimiter = p.NamespaceDelimiter
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch i := g.parent.(type) {
|
||||||
|
case *Command:
|
||||||
|
g = i.Group
|
||||||
|
case *Group:
|
||||||
|
g = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// concatenate long name with namespace
|
||||||
|
longName := option.LongName
|
||||||
|
g = option.group
|
||||||
|
|
||||||
|
for g != nil {
|
||||||
|
if g.Namespace != "" {
|
||||||
|
longName = g.Namespace + namespaceDelimiter + longName
|
||||||
|
}
|
||||||
|
|
||||||
|
switch i := g.parent.(type) {
|
||||||
|
case *Command:
|
||||||
|
g = i.Group
|
||||||
|
case *Group:
|
||||||
|
g = i
|
||||||
|
case *Parser:
|
||||||
|
g = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return longName
|
||||||
|
}
|
||||||
|
|
||||||
|
// String converts an option to a human friendly readable string describing the
|
||||||
|
// option.
|
||||||
|
func (option *Option) String() string {
|
||||||
|
var s string
|
||||||
|
var short string
|
||||||
|
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
data := make([]byte, utf8.RuneLen(option.ShortName))
|
||||||
|
utf8.EncodeRune(data, option.ShortName)
|
||||||
|
short = string(data)
|
||||||
|
|
||||||
|
if len(option.LongName) != 0 {
|
||||||
|
s = fmt.Sprintf("%s%s, %s%s",
|
||||||
|
string(defaultShortOptDelimiter), short,
|
||||||
|
defaultLongOptDelimiter, option.LongNameWithNamespace())
|
||||||
|
} else {
|
||||||
|
s = fmt.Sprintf("%s%s", string(defaultShortOptDelimiter), short)
|
||||||
|
}
|
||||||
|
} else if len(option.LongName) != 0 {
|
||||||
|
s = fmt.Sprintf("%s%s", defaultLongOptDelimiter, option.LongNameWithNamespace())
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the option value as an interface{}.
|
||||||
|
func (option *Option) Value() interface{} {
|
||||||
|
return option.value.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field returns the reflect struct field of the option.
|
||||||
|
func (option *Option) Field() reflect.StructField {
|
||||||
|
return option.field
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet returns true if option has been set
|
||||||
|
func (option *Option) IsSet() bool {
|
||||||
|
return option.isSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSetDefault returns true if option has been set via the default option tag
|
||||||
|
func (option *Option) IsSetDefault() bool {
|
||||||
|
return option.isSetDefault
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the value of an option to the specified value. An error will be returned
|
||||||
|
// if the specified value could not be converted to the corresponding option
|
||||||
|
// value type.
|
||||||
|
func (option *Option) set(value *string) error {
|
||||||
|
kind := option.value.Type().Kind()
|
||||||
|
|
||||||
|
if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet {
|
||||||
|
option.empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
option.isSet = true
|
||||||
|
option.preventDefault = true
|
||||||
|
|
||||||
|
if len(option.Choices) != 0 {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, choice := range option.Choices {
|
||||||
|
if choice == *value {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
allowed := strings.Join(option.Choices[0:len(option.Choices)-1], ", ")
|
||||||
|
|
||||||
|
if len(option.Choices) > 1 {
|
||||||
|
allowed += " or " + option.Choices[len(option.Choices)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return newErrorf(ErrInvalidChoice,
|
||||||
|
"Invalid value `%s' for option `%s'. Allowed values are: %s",
|
||||||
|
*value, option, allowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.isFunc() {
|
||||||
|
return option.call(value)
|
||||||
|
} else if value != nil {
|
||||||
|
return convert(*value, option.value, option.tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return convert("", option.value, option.tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) canCli() bool {
|
||||||
|
return option.ShortName != 0 || len(option.LongName) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) canArgument() bool {
|
||||||
|
if u := option.isUnmarshaler(); u != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return !option.isBool()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) emptyValue() reflect.Value {
|
||||||
|
tp := option.value.Type()
|
||||||
|
|
||||||
|
if tp.Kind() == reflect.Map {
|
||||||
|
return reflect.MakeMap(tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.Zero(tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) empty() {
|
||||||
|
if !option.isFunc() {
|
||||||
|
option.value.Set(option.emptyValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) clearDefault() {
|
||||||
|
usedDefault := option.Default
|
||||||
|
|
||||||
|
if envKey := option.EnvDefaultKey; envKey != "" {
|
||||||
|
if value, ok := os.LookupEnv(envKey); ok {
|
||||||
|
if option.EnvDefaultDelim != "" {
|
||||||
|
usedDefault = strings.Split(value,
|
||||||
|
option.EnvDefaultDelim)
|
||||||
|
} else {
|
||||||
|
usedDefault = []string{value}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option.isSetDefault = true
|
||||||
|
|
||||||
|
if len(usedDefault) > 0 {
|
||||||
|
option.empty()
|
||||||
|
|
||||||
|
for _, d := range usedDefault {
|
||||||
|
option.set(&d)
|
||||||
|
option.isSetDefault = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tp := option.value.Type()
|
||||||
|
|
||||||
|
switch tp.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
if option.value.IsNil() {
|
||||||
|
option.empty()
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
if option.value.IsNil() {
|
||||||
|
option.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) valueIsDefault() bool {
|
||||||
|
// Check if the value of the option corresponds to its
|
||||||
|
// default value
|
||||||
|
emptyval := option.emptyValue()
|
||||||
|
|
||||||
|
checkvalptr := reflect.New(emptyval.Type())
|
||||||
|
checkval := reflect.Indirect(checkvalptr)
|
||||||
|
|
||||||
|
checkval.Set(emptyval)
|
||||||
|
|
||||||
|
if len(option.Default) != 0 {
|
||||||
|
for _, v := range option.Default {
|
||||||
|
convert(v, checkval, option.tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.DeepEqual(option.value.Interface(), checkval.Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) isUnmarshaler() Unmarshaler {
|
||||||
|
v := option.value
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !v.CanInterface() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
i := v.Interface()
|
||||||
|
|
||||||
|
if u, ok := i.(Unmarshaler); ok {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.CanAddr() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) isBool() bool {
|
||||||
|
tp := option.value.Type()
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch tp.Kind() {
|
||||||
|
case reflect.Slice, reflect.Ptr:
|
||||||
|
tp = tp.Elem()
|
||||||
|
case reflect.Bool:
|
||||||
|
return true
|
||||||
|
case reflect.Func:
|
||||||
|
return tp.NumIn() == 0
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) isSignedNumber() bool {
|
||||||
|
tp := option.value.Type()
|
||||||
|
|
||||||
|
for {
|
||||||
|
switch tp.Kind() {
|
||||||
|
case reflect.Slice, reflect.Ptr:
|
||||||
|
tp = tp.Elem()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) isFunc() bool {
|
||||||
|
return option.value.Type().Kind() == reflect.Func
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) call(value *string) error {
|
||||||
|
var retval []reflect.Value
|
||||||
|
|
||||||
|
if value == nil {
|
||||||
|
retval = option.value.Call(nil)
|
||||||
|
} else {
|
||||||
|
tp := option.value.Type().In(0)
|
||||||
|
|
||||||
|
val := reflect.New(tp)
|
||||||
|
val = reflect.Indirect(val)
|
||||||
|
|
||||||
|
if err := convert(*value, val, option.tag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = option.value.Call([]reflect.Value{val})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(retval) == 1 && retval[0].Type() == reflect.TypeOf((*error)(nil)).Elem() {
|
||||||
|
if retval[0].Interface() == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval[0].Interface().(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) updateDefaultLiteral() {
|
||||||
|
defs := option.Default
|
||||||
|
def := ""
|
||||||
|
|
||||||
|
if len(defs) == 0 && option.canArgument() {
|
||||||
|
var showdef bool
|
||||||
|
|
||||||
|
switch option.field.Type.Kind() {
|
||||||
|
case reflect.Func, reflect.Ptr:
|
||||||
|
showdef = !option.value.IsNil()
|
||||||
|
case reflect.Slice, reflect.String, reflect.Array:
|
||||||
|
showdef = option.value.Len() > 0
|
||||||
|
case reflect.Map:
|
||||||
|
showdef = !option.value.IsNil() && option.value.Len() > 0
|
||||||
|
default:
|
||||||
|
zeroval := reflect.Zero(option.field.Type)
|
||||||
|
showdef = !reflect.DeepEqual(zeroval.Interface(), option.value.Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
if showdef {
|
||||||
|
def, _ = convertToString(option.value, option.tag)
|
||||||
|
}
|
||||||
|
} else if len(defs) != 0 {
|
||||||
|
l := len(defs) - 1
|
||||||
|
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
def += quoteIfNeeded(defs[i]) + ", "
|
||||||
|
}
|
||||||
|
|
||||||
|
def += quoteIfNeeded(defs[l])
|
||||||
|
}
|
||||||
|
|
||||||
|
option.defaultLiteral = def
|
||||||
|
}
|
||||||
|
|
||||||
|
func (option *Option) shortAndLongName() string {
|
||||||
|
ret := &bytes.Buffer{}
|
||||||
|
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
ret.WriteRune(defaultShortOptDelimiter)
|
||||||
|
ret.WriteRune(option.ShortName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(option.LongName) != 0 {
|
||||||
|
if option.ShortName != 0 {
|
||||||
|
ret.WriteRune('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.WriteString(option.LongName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.String()
|
||||||
|
}
|
67
vendor/github.com/jessevdk/go-flags/optstyle_other.go
generated
vendored
Normal file
67
vendor/github.com/jessevdk/go-flags/optstyle_other.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// +build !windows forceposix
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultShortOptDelimiter = '-'
|
||||||
|
defaultLongOptDelimiter = "--"
|
||||||
|
defaultNameArgDelimiter = '='
|
||||||
|
)
|
||||||
|
|
||||||
|
func argumentStartsOption(arg string) bool {
|
||||||
|
return len(arg) > 0 && arg[0] == '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
func argumentIsOption(arg string) bool {
|
||||||
|
if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// stripOptionPrefix returns the option without the prefix and whether or
|
||||||
|
// not the option is a long option or not.
|
||||||
|
func stripOptionPrefix(optname string) (prefix string, name string, islong bool) {
|
||||||
|
if strings.HasPrefix(optname, "--") {
|
||||||
|
return "--", optname[2:], true
|
||||||
|
} else if strings.HasPrefix(optname, "-") {
|
||||||
|
return "-", optname[1:], false
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", optname, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitOption attempts to split the passed option into a name and an argument.
|
||||||
|
// When there is no argument specified, nil will be returned for it.
|
||||||
|
func splitOption(prefix string, option string, islong bool) (string, string, *string) {
|
||||||
|
pos := strings.Index(option, "=")
|
||||||
|
|
||||||
|
if (islong && pos >= 0) || (!islong && pos == 1) {
|
||||||
|
rest := option[pos+1:]
|
||||||
|
return option[:pos], "=", &rest
|
||||||
|
}
|
||||||
|
|
||||||
|
return option, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addHelpGroup adds a new group that contains default help parameters.
|
||||||
|
func (c *Command) addHelpGroup(showHelp func() error) *Group {
|
||||||
|
var help struct {
|
||||||
|
ShowHelp func() error `short:"h" long:"help" description:"Show this help message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
help.ShowHelp = showHelp
|
||||||
|
ret, _ := c.AddGroup("Help Options", "", &help)
|
||||||
|
ret.isBuiltinHelp = true
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
108
vendor/github.com/jessevdk/go-flags/optstyle_windows.go
generated
vendored
Normal file
108
vendor/github.com/jessevdk/go-flags/optstyle_windows.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// +build !forceposix
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows uses a front slash for both short and long options. Also it uses
|
||||||
|
// a colon for name/argument delimter.
|
||||||
|
const (
|
||||||
|
defaultShortOptDelimiter = '/'
|
||||||
|
defaultLongOptDelimiter = "/"
|
||||||
|
defaultNameArgDelimiter = ':'
|
||||||
|
)
|
||||||
|
|
||||||
|
func argumentStartsOption(arg string) bool {
|
||||||
|
return len(arg) > 0 && (arg[0] == '-' || arg[0] == '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
func argumentIsOption(arg string) bool {
|
||||||
|
// Windows-style options allow front slash for the option
|
||||||
|
// delimiter.
|
||||||
|
if len(arg) > 1 && arg[0] == '/' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// stripOptionPrefix returns the option without the prefix and whether or
|
||||||
|
// not the option is a long option or not.
|
||||||
|
func stripOptionPrefix(optname string) (prefix string, name string, islong bool) {
|
||||||
|
// Determine if the argument is a long option or not. Windows
|
||||||
|
// typically supports both long and short options with a single
|
||||||
|
// front slash as the option delimiter, so handle this situation
|
||||||
|
// nicely.
|
||||||
|
possplit := 0
|
||||||
|
|
||||||
|
if strings.HasPrefix(optname, "--") {
|
||||||
|
possplit = 2
|
||||||
|
islong = true
|
||||||
|
} else if strings.HasPrefix(optname, "-") {
|
||||||
|
possplit = 1
|
||||||
|
islong = false
|
||||||
|
} else if strings.HasPrefix(optname, "/") {
|
||||||
|
possplit = 1
|
||||||
|
islong = len(optname) > 2
|
||||||
|
}
|
||||||
|
|
||||||
|
return optname[:possplit], optname[possplit:], islong
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitOption attempts to split the passed option into a name and an argument.
|
||||||
|
// When there is no argument specified, nil will be returned for it.
|
||||||
|
func splitOption(prefix string, option string, islong bool) (string, string, *string) {
|
||||||
|
if len(option) == 0 {
|
||||||
|
return option, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows typically uses a colon for the option name and argument
|
||||||
|
// delimiter while POSIX typically uses an equals. Support both styles,
|
||||||
|
// but don't allow the two to be mixed. That is to say /foo:bar and
|
||||||
|
// --foo=bar are acceptable, but /foo=bar and --foo:bar are not.
|
||||||
|
var pos int
|
||||||
|
var sp string
|
||||||
|
|
||||||
|
if prefix == "/" {
|
||||||
|
sp = ":"
|
||||||
|
pos = strings.Index(option, sp)
|
||||||
|
} else if len(prefix) > 0 {
|
||||||
|
sp = "="
|
||||||
|
pos = strings.Index(option, sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (islong && pos >= 0) || (!islong && pos == 1) {
|
||||||
|
rest := option[pos+1:]
|
||||||
|
return option[:pos], sp, &rest
|
||||||
|
}
|
||||||
|
|
||||||
|
return option, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addHelpGroup adds a new group that contains default help parameters.
|
||||||
|
func (c *Command) addHelpGroup(showHelp func() error) *Group {
|
||||||
|
// Windows CLI applications typically use /? for help, so make both
|
||||||
|
// that available as well as the POSIX style h and help.
|
||||||
|
var help struct {
|
||||||
|
ShowHelpWindows func() error `short:"?" description:"Show this help message"`
|
||||||
|
ShowHelpPosix func() error `short:"h" long:"help" description:"Show this help message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
help.ShowHelpWindows = showHelp
|
||||||
|
help.ShowHelpPosix = showHelp
|
||||||
|
|
||||||
|
ret, _ := c.AddGroup("Help Options", "", &help)
|
||||||
|
ret.isBuiltinHelp = true
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
700
vendor/github.com/jessevdk/go-flags/parser.go
generated
vendored
Normal file
700
vendor/github.com/jessevdk/go-flags/parser.go
generated
vendored
Normal file
@ -0,0 +1,700 @@
|
|||||||
|
// Copyright 2012 Jesse van den Kieboom. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Parser provides command line option parsing. It can contain several
|
||||||
|
// option groups each with their own set of options.
|
||||||
|
type Parser struct {
|
||||||
|
// Embedded, see Command for more information
|
||||||
|
*Command
|
||||||
|
|
||||||
|
// A usage string to be displayed in the help message.
|
||||||
|
Usage string
|
||||||
|
|
||||||
|
// Option flags changing the behavior of the parser.
|
||||||
|
Options Options
|
||||||
|
|
||||||
|
// NamespaceDelimiter separates group namespaces and option long names
|
||||||
|
NamespaceDelimiter string
|
||||||
|
|
||||||
|
// UnknownOptionsHandler is a function which gets called when the parser
|
||||||
|
// encounters an unknown option. The function receives the unknown option
|
||||||
|
// name, a SplitArgument which specifies its value if set with an argument
|
||||||
|
// separator, and the remaining command line arguments.
|
||||||
|
// It should return a new list of remaining arguments to continue parsing,
|
||||||
|
// or an error to indicate a parse failure.
|
||||||
|
UnknownOptionHandler func(option string, arg SplitArgument, args []string) ([]string, error)
|
||||||
|
|
||||||
|
// CompletionHandler is a function gets called to handle the completion of
|
||||||
|
// items. By default, the items are printed and the application is exited.
|
||||||
|
// You can override this default behavior by specifying a custom CompletionHandler.
|
||||||
|
CompletionHandler func(items []Completion)
|
||||||
|
|
||||||
|
// CommandHandler is a function that gets called to handle execution of a
|
||||||
|
// command. By default, the command will simply be executed. This can be
|
||||||
|
// overridden to perform certain actions (such as applying global flags)
|
||||||
|
// just before the command is executed. Note that if you override the
|
||||||
|
// handler it is your responsibility to call the command.Execute function.
|
||||||
|
//
|
||||||
|
// The command passed into CommandHandler may be nil in case there is no
|
||||||
|
// command to be executed when parsing has finished.
|
||||||
|
CommandHandler func(command Commander, args []string) error
|
||||||
|
|
||||||
|
internalError error
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitArgument represents the argument value of an option that was passed using
|
||||||
|
// an argument separator.
|
||||||
|
type SplitArgument interface {
|
||||||
|
// String returns the option's value as a string, and a boolean indicating
|
||||||
|
// if the option was present.
|
||||||
|
Value() (string, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
type strArgument struct {
|
||||||
|
value *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s strArgument) Value() (string, bool) {
|
||||||
|
if s.value == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return *s.value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options provides parser options that change the behavior of the option
|
||||||
|
// parser.
|
||||||
|
type Options uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// None indicates no options.
|
||||||
|
None Options = 0
|
||||||
|
|
||||||
|
// HelpFlag adds a default Help Options group to the parser containing
|
||||||
|
// -h and --help options. When either -h or --help is specified on the
|
||||||
|
// command line, the parser will return the special error of type
|
||||||
|
// ErrHelp. When PrintErrors is also specified, then the help message
|
||||||
|
// will also be automatically printed to os.Stdout.
|
||||||
|
HelpFlag = 1 << iota
|
||||||
|
|
||||||
|
// PassDoubleDash passes all arguments after a double dash, --, as
|
||||||
|
// remaining command line arguments (i.e. they will not be parsed for
|
||||||
|
// flags).
|
||||||
|
PassDoubleDash
|
||||||
|
|
||||||
|
// IgnoreUnknown ignores any unknown options and passes them as
|
||||||
|
// remaining command line arguments instead of generating an error.
|
||||||
|
IgnoreUnknown
|
||||||
|
|
||||||
|
// PrintErrors prints any errors which occurred during parsing to
|
||||||
|
// os.Stderr. In the special case of ErrHelp, the message will be printed
|
||||||
|
// to os.Stdout.
|
||||||
|
PrintErrors
|
||||||
|
|
||||||
|
// PassAfterNonOption passes all arguments after the first non option
|
||||||
|
// as remaining command line arguments. This is equivalent to strict
|
||||||
|
// POSIX processing.
|
||||||
|
PassAfterNonOption
|
||||||
|
|
||||||
|
// Default is a convenient default set of options which should cover
|
||||||
|
// most of the uses of the flags package.
|
||||||
|
Default = HelpFlag | PrintErrors | PassDoubleDash
|
||||||
|
)
|
||||||
|
|
||||||
|
type parseState struct {
|
||||||
|
arg string
|
||||||
|
args []string
|
||||||
|
retargs []string
|
||||||
|
positional []*Arg
|
||||||
|
err error
|
||||||
|
|
||||||
|
command *Command
|
||||||
|
lookup lookup
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse is a convenience function to parse command line options with default
|
||||||
|
// settings. The provided data is a pointer to a struct representing the
|
||||||
|
// default option group (named "Application Options"). For more control, use
|
||||||
|
// flags.NewParser.
|
||||||
|
func Parse(data interface{}) ([]string, error) {
|
||||||
|
return NewParser(data, Default).Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseArgs is a convenience function to parse command line options with default
|
||||||
|
// settings. The provided data is a pointer to a struct representing the
|
||||||
|
// default option group (named "Application Options"). The args argument is
|
||||||
|
// the list of command line arguments to parse. If you just want to parse the
|
||||||
|
// default program command line arguments (i.e. os.Args), then use flags.Parse
|
||||||
|
// instead. For more control, use flags.NewParser.
|
||||||
|
func ParseArgs(data interface{}, args []string) ([]string, error) {
|
||||||
|
return NewParser(data, Default).ParseArgs(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewParser creates a new parser. It uses os.Args[0] as the application
|
||||||
|
// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
|
||||||
|
// more details). The provided data is a pointer to a struct representing the
|
||||||
|
// default option group (named "Application Options"), or nil if the default
|
||||||
|
// group should not be added. The options parameter specifies a set of options
|
||||||
|
// for the parser.
|
||||||
|
func NewParser(data interface{}, options Options) *Parser {
|
||||||
|
p := NewNamedParser(path.Base(os.Args[0]), options)
|
||||||
|
|
||||||
|
if data != nil {
|
||||||
|
g, err := p.AddGroup("Application Options", "", data)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
g.parent = p
|
||||||
|
}
|
||||||
|
|
||||||
|
p.internalError = err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNamedParser creates a new parser. The appname is used to display the
|
||||||
|
// executable name in the built-in help message. Option groups and commands can
|
||||||
|
// be added to this parser by using AddGroup and AddCommand.
|
||||||
|
func NewNamedParser(appname string, options Options) *Parser {
|
||||||
|
p := &Parser{
|
||||||
|
Command: newCommand(appname, "", "", nil),
|
||||||
|
Options: options,
|
||||||
|
NamespaceDelimiter: ".",
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Command.parent = p
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
|
||||||
|
// For more detailed information see ParseArgs.
|
||||||
|
func (p *Parser) Parse() ([]string, error) {
|
||||||
|
return p.ParseArgs(os.Args[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseArgs parses the command line arguments according to the option groups that
|
||||||
|
// were added to the parser. On successful parsing of the arguments, the
|
||||||
|
// remaining, non-option, arguments (if any) are returned. The returned error
|
||||||
|
// indicates a parsing error and can be used with PrintError to display
|
||||||
|
// contextual information on where the error occurred exactly.
|
||||||
|
//
|
||||||
|
// When the common help group has been added (AddHelp) and either -h or --help
|
||||||
|
// was specified in the command line arguments, a help message will be
|
||||||
|
// automatically printed if the PrintErrors option is enabled.
|
||||||
|
// Furthermore, the special error type ErrHelp is returned.
|
||||||
|
// It is up to the caller to exit the program if so desired.
|
||||||
|
func (p *Parser) ParseArgs(args []string) ([]string, error) {
|
||||||
|
if p.internalError != nil {
|
||||||
|
return nil, p.internalError
|
||||||
|
}
|
||||||
|
|
||||||
|
p.eachOption(func(c *Command, g *Group, option *Option) {
|
||||||
|
option.isSet = false
|
||||||
|
option.isSetDefault = false
|
||||||
|
option.updateDefaultLiteral()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add built-in help group to all commands if necessary
|
||||||
|
if (p.Options & HelpFlag) != None {
|
||||||
|
p.addHelpGroups(p.showBuiltinHelp)
|
||||||
|
}
|
||||||
|
|
||||||
|
compval := os.Getenv("GO_FLAGS_COMPLETION")
|
||||||
|
|
||||||
|
if len(compval) != 0 {
|
||||||
|
comp := &completion{parser: p}
|
||||||
|
items := comp.complete(args)
|
||||||
|
|
||||||
|
if p.CompletionHandler != nil {
|
||||||
|
p.CompletionHandler(items)
|
||||||
|
} else {
|
||||||
|
comp.print(items, compval == "verbose")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &parseState{
|
||||||
|
args: args,
|
||||||
|
retargs: make([]string, 0, len(args)),
|
||||||
|
}
|
||||||
|
|
||||||
|
p.fillParseState(s)
|
||||||
|
|
||||||
|
for !s.eof() {
|
||||||
|
arg := s.pop()
|
||||||
|
|
||||||
|
// When PassDoubleDash is set and we encounter a --, then
|
||||||
|
// simply append all the rest as arguments and break out
|
||||||
|
if (p.Options&PassDoubleDash) != None && arg == "--" {
|
||||||
|
s.addArgs(s.args...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if !argumentIsOption(arg) {
|
||||||
|
// Note: this also sets s.err, so we can just check for
|
||||||
|
// nil here and use s.err later
|
||||||
|
if p.parseNonOption(s) != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
prefix, optname, islong := stripOptionPrefix(arg)
|
||||||
|
optname, _, argument := splitOption(prefix, optname, islong)
|
||||||
|
|
||||||
|
if islong {
|
||||||
|
err = p.parseLong(s, optname, argument)
|
||||||
|
} else {
|
||||||
|
err = p.parseShort(s, optname, argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ignoreUnknown := (p.Options & IgnoreUnknown) != None
|
||||||
|
parseErr := wrapError(err)
|
||||||
|
|
||||||
|
if parseErr.Type != ErrUnknownFlag || (!ignoreUnknown && p.UnknownOptionHandler == nil) {
|
||||||
|
s.err = parseErr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if ignoreUnknown {
|
||||||
|
s.addArgs(arg)
|
||||||
|
} else if p.UnknownOptionHandler != nil {
|
||||||
|
modifiedArgs, err := p.UnknownOptionHandler(optname, strArgument{argument}, s.args)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.err = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s.args = modifiedArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.err == nil {
|
||||||
|
p.eachOption(func(c *Command, g *Group, option *Option) {
|
||||||
|
if option.preventDefault {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
option.clearDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
s.checkRequired(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
var reterr error
|
||||||
|
|
||||||
|
if s.err != nil {
|
||||||
|
reterr = s.err
|
||||||
|
} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
|
||||||
|
reterr = s.estimateCommand()
|
||||||
|
} else if cmd, ok := s.command.data.(Commander); ok {
|
||||||
|
if p.CommandHandler != nil {
|
||||||
|
reterr = p.CommandHandler(cmd, s.retargs)
|
||||||
|
} else {
|
||||||
|
reterr = cmd.Execute(s.retargs)
|
||||||
|
}
|
||||||
|
} else if p.CommandHandler != nil {
|
||||||
|
reterr = p.CommandHandler(nil, s.retargs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reterr != nil {
|
||||||
|
var retargs []string
|
||||||
|
|
||||||
|
if ourErr, ok := reterr.(*Error); !ok || ourErr.Type != ErrHelp {
|
||||||
|
retargs = append([]string{s.arg}, s.args...)
|
||||||
|
} else {
|
||||||
|
retargs = s.args
|
||||||
|
}
|
||||||
|
|
||||||
|
return retargs, p.printError(reterr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.retargs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parseState) eof() bool {
|
||||||
|
return len(p.args) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parseState) pop() string {
|
||||||
|
if p.eof() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
p.arg = p.args[0]
|
||||||
|
p.args = p.args[1:]
|
||||||
|
|
||||||
|
return p.arg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parseState) peek() string {
|
||||||
|
if p.eof() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parseState) checkRequired(parser *Parser) error {
|
||||||
|
c := parser.Command
|
||||||
|
|
||||||
|
var required []*Option
|
||||||
|
|
||||||
|
for c != nil {
|
||||||
|
c.eachGroup(func(g *Group) {
|
||||||
|
for _, option := range g.options {
|
||||||
|
if !option.isSet && option.Required {
|
||||||
|
required = append(required, option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
c = c.Active
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(required) == 0 {
|
||||||
|
if len(p.positional) > 0 {
|
||||||
|
var reqnames []string
|
||||||
|
|
||||||
|
for _, arg := range p.positional {
|
||||||
|
argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != -1 || arg.RequiredMaximum != -1
|
||||||
|
|
||||||
|
if !argRequired {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if arg.isRemaining() {
|
||||||
|
if arg.value.Len() < arg.Required {
|
||||||
|
var arguments string
|
||||||
|
|
||||||
|
if arg.Required > 1 {
|
||||||
|
arguments = "arguments, but got only " + fmt.Sprintf("%d", arg.value.Len())
|
||||||
|
} else {
|
||||||
|
arguments = "argument"
|
||||||
|
}
|
||||||
|
|
||||||
|
reqnames = append(reqnames, "`"+arg.Name+" (at least "+fmt.Sprintf("%d", arg.Required)+" "+arguments+")`")
|
||||||
|
} else if arg.RequiredMaximum != -1 && arg.value.Len() > arg.RequiredMaximum {
|
||||||
|
if arg.RequiredMaximum == 0 {
|
||||||
|
reqnames = append(reqnames, "`"+arg.Name+" (zero arguments)`")
|
||||||
|
} else {
|
||||||
|
var arguments string
|
||||||
|
|
||||||
|
if arg.RequiredMaximum > 1 {
|
||||||
|
arguments = "arguments, but got " + fmt.Sprintf("%d", arg.value.Len())
|
||||||
|
} else {
|
||||||
|
arguments = "argument"
|
||||||
|
}
|
||||||
|
|
||||||
|
reqnames = append(reqnames, "`"+arg.Name+" (at most "+fmt.Sprintf("%d", arg.RequiredMaximum)+" "+arguments+")`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reqnames = append(reqnames, "`"+arg.Name+"`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reqnames) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if len(reqnames) == 1 {
|
||||||
|
msg = fmt.Sprintf("the required argument %s was not provided", reqnames[0])
|
||||||
|
} else {
|
||||||
|
msg = fmt.Sprintf("the required arguments %s and %s were not provided",
|
||||||
|
strings.Join(reqnames[:len(reqnames)-1], ", "), reqnames[len(reqnames)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
p.err = newError(ErrRequired, msg)
|
||||||
|
return p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
names := make([]string, 0, len(required))
|
||||||
|
|
||||||
|
for _, k := range required {
|
||||||
|
names = append(names, "`"+k.String()+"'")
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(names)
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if len(names) == 1 {
|
||||||
|
msg = fmt.Sprintf("the required flag %s was not specified", names[0])
|
||||||
|
} else {
|
||||||
|
msg = fmt.Sprintf("the required flags %s and %s were not specified",
|
||||||
|
strings.Join(names[:len(names)-1], ", "), names[len(names)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
p.err = newError(ErrRequired, msg)
|
||||||
|
return p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parseState) estimateCommand() error {
|
||||||
|
commands := p.command.sortedVisibleCommands()
|
||||||
|
cmdnames := make([]string, len(commands))
|
||||||
|
|
||||||
|
for i, v := range commands {
|
||||||
|
cmdnames[i] = v.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
var errtype ErrorType
|
||||||
|
|
||||||
|
if len(p.retargs) != 0 {
|
||||||
|
c, l := closestChoice(p.retargs[0], cmdnames)
|
||||||
|
msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0])
|
||||||
|
errtype = ErrUnknownCommand
|
||||||
|
|
||||||
|
if float32(l)/float32(len(c)) < 0.5 {
|
||||||
|
msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c)
|
||||||
|
} else if len(cmdnames) == 1 {
|
||||||
|
msg = fmt.Sprintf("%s. You should use the %s command",
|
||||||
|
msg,
|
||||||
|
cmdnames[0])
|
||||||
|
} else if len(cmdnames) > 1 {
|
||||||
|
msg = fmt.Sprintf("%s. Please specify one command of: %s or %s",
|
||||||
|
msg,
|
||||||
|
strings.Join(cmdnames[:len(cmdnames)-1], ", "),
|
||||||
|
cmdnames[len(cmdnames)-1])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errtype = ErrCommandRequired
|
||||||
|
|
||||||
|
if len(cmdnames) == 1 {
|
||||||
|
msg = fmt.Sprintf("Please specify the %s command", cmdnames[0])
|
||||||
|
} else if len(cmdnames) > 1 {
|
||||||
|
msg = fmt.Sprintf("Please specify one command of: %s or %s",
|
||||||
|
strings.Join(cmdnames[:len(cmdnames)-1], ", "),
|
||||||
|
cmdnames[len(cmdnames)-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newError(errtype, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) {
|
||||||
|
if !option.canArgument() {
|
||||||
|
if argument != nil {
|
||||||
|
return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = option.set(nil)
|
||||||
|
} else if argument != nil || (canarg && !s.eof()) {
|
||||||
|
var arg string
|
||||||
|
|
||||||
|
if argument != nil {
|
||||||
|
arg = *argument
|
||||||
|
} else {
|
||||||
|
arg = s.pop()
|
||||||
|
|
||||||
|
if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') {
|
||||||
|
return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg)
|
||||||
|
} else if p.Options&PassDoubleDash != 0 && arg == "--" {
|
||||||
|
return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.tag.Get("unquote") != "false" {
|
||||||
|
arg, err = unquoteIfPossible(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
err = option.set(&arg)
|
||||||
|
}
|
||||||
|
} else if option.OptionalArgument {
|
||||||
|
option.empty()
|
||||||
|
|
||||||
|
for _, v := range option.OptionalValue {
|
||||||
|
err = option.set(&v)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = newErrorf(ErrExpectedArgument, "expected argument for flag `%s'", option)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*Error); !ok {
|
||||||
|
err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s",
|
||||||
|
option,
|
||||||
|
option.value.Type(),
|
||||||
|
err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseLong(s *parseState, name string, argument *string) error {
|
||||||
|
if option := s.lookup.longNames[name]; option != nil {
|
||||||
|
// Only long options that are required can consume an argument
|
||||||
|
// from the argument list
|
||||||
|
canarg := !option.OptionalArgument
|
||||||
|
|
||||||
|
return p.parseOption(s, name, option, canarg, argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newErrorf(ErrUnknownFlag, "unknown flag `%s'", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) {
|
||||||
|
c, n := utf8.DecodeRuneInString(optname)
|
||||||
|
|
||||||
|
if n == len(optname) {
|
||||||
|
return optname, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
first := string(c)
|
||||||
|
|
||||||
|
if option := s.lookup.shortNames[first]; option != nil && option.canArgument() {
|
||||||
|
arg := optname[n:]
|
||||||
|
return first, &arg
|
||||||
|
}
|
||||||
|
|
||||||
|
return optname, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseShort(s *parseState, optname string, argument *string) error {
|
||||||
|
if argument == nil {
|
||||||
|
optname, argument = p.splitShortConcatArg(s, optname)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range optname {
|
||||||
|
shortname := string(c)
|
||||||
|
|
||||||
|
if option := s.lookup.shortNames[shortname]; option != nil {
|
||||||
|
// Only the last short argument can consume an argument from
|
||||||
|
// the arguments list, and only if it's non optional
|
||||||
|
canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument
|
||||||
|
|
||||||
|
if err := p.parseOption(s, shortname, option, canarg, argument); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return newErrorf(ErrUnknownFlag, "unknown flag `%s'", shortname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only the first option can have a concatted argument, so just
|
||||||
|
// clear argument here
|
||||||
|
argument = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parseState) addArgs(args ...string) error {
|
||||||
|
for len(p.positional) > 0 && len(args) > 0 {
|
||||||
|
arg := p.positional[0]
|
||||||
|
|
||||||
|
if err := convert(args[0], arg.value, arg.tag); err != nil {
|
||||||
|
p.err = err
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !arg.isRemaining() {
|
||||||
|
p.positional = p.positional[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
p.retargs = append(p.retargs, args...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseNonOption(s *parseState) error {
|
||||||
|
if len(s.positional) > 0 {
|
||||||
|
return s.addArgs(s.arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.command.commands) > 0 && len(s.retargs) == 0 {
|
||||||
|
if cmd := s.lookup.commands[s.arg]; cmd != nil {
|
||||||
|
s.command.Active = cmd
|
||||||
|
cmd.fillParseState(s)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
} else if !s.command.SubcommandsOptional {
|
||||||
|
s.addArgs(s.arg)
|
||||||
|
return newErrorf(ErrUnknownCommand, "Unknown command `%s'", s.arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.Options & PassAfterNonOption) != None {
|
||||||
|
// If PassAfterNonOption is set then all remaining arguments
|
||||||
|
// are considered positional
|
||||||
|
if err := s.addArgs(s.arg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.addArgs(s.args...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.args = []string{}
|
||||||
|
} else {
|
||||||
|
return s.addArgs(s.arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) showBuiltinHelp() error {
|
||||||
|
var b bytes.Buffer
|
||||||
|
|
||||||
|
p.WriteHelp(&b)
|
||||||
|
return newError(ErrHelp, b.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) printError(err error) error {
|
||||||
|
if err != nil && (p.Options&PrintErrors) != None {
|
||||||
|
flagsErr, ok := err.(*Error)
|
||||||
|
|
||||||
|
if ok && flagsErr.Type == ErrHelp {
|
||||||
|
fmt.Fprintln(os.Stdout, err)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) clearIsSet() {
|
||||||
|
p.eachCommand(func(c *Command) {
|
||||||
|
c.eachGroup(func(g *Group) {
|
||||||
|
for _, option := range g.options {
|
||||||
|
option.isSet = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, true)
|
||||||
|
}
|
28
vendor/github.com/jessevdk/go-flags/termsize.go
generated
vendored
Normal file
28
vendor/github.com/jessevdk/go-flags/termsize.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// +build !windows,!plan9,!solaris,!appengine
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type winsize struct {
|
||||||
|
row, col uint16
|
||||||
|
xpixel, ypixel uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTerminalColumns() int {
|
||||||
|
ws := winsize{}
|
||||||
|
|
||||||
|
if tIOCGWINSZ != 0 {
|
||||||
|
syscall.Syscall(syscall.SYS_IOCTL,
|
||||||
|
uintptr(0),
|
||||||
|
uintptr(tIOCGWINSZ),
|
||||||
|
uintptr(unsafe.Pointer(&ws)))
|
||||||
|
|
||||||
|
return int(ws.col)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 80
|
||||||
|
}
|
7
vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go
generated
vendored
Normal file
7
vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build windows plan9 solaris appengine
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
func getTerminalColumns() int {
|
||||||
|
return 80
|
||||||
|
}
|
7
vendor/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go
generated
vendored
Normal file
7
vendor/github.com/jessevdk/go-flags/tiocgwinsz_bsdish.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build darwin freebsd netbsd openbsd
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
const (
|
||||||
|
tIOCGWINSZ = 0x40087468
|
||||||
|
)
|
7
vendor/github.com/jessevdk/go-flags/tiocgwinsz_linux.go
generated
vendored
Normal file
7
vendor/github.com/jessevdk/go-flags/tiocgwinsz_linux.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
const (
|
||||||
|
tIOCGWINSZ = 0x5413
|
||||||
|
)
|
7
vendor/github.com/jessevdk/go-flags/tiocgwinsz_other.go
generated
vendored
Normal file
7
vendor/github.com/jessevdk/go-flags/tiocgwinsz_other.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build !darwin,!freebsd,!netbsd,!openbsd,!linux
|
||||||
|
|
||||||
|
package flags
|
||||||
|
|
||||||
|
const (
|
||||||
|
tIOCGWINSZ = 0
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user