You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-08-08 04:42:07 +03:00
Add self-contained gometalinter build tooling.
This commit is contained in:
24
tools/vendor/github.com/alexflint/go-arg/LICENSE
generated
vendored
Normal file
24
tools/vendor/github.com/alexflint/go-arg/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2015, Alex Flint
|
||||
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.
|
||||
|
||||
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 HOLDER 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.
|
||||
|
321
tools/vendor/github.com/alexflint/go-arg/README.md
generated
vendored
Normal file
321
tools/vendor/github.com/alexflint/go-arg/README.md
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
[](https://godoc.org/github.com/alexflint/go-arg)
|
||||
[](https://travis-ci.org/alexflint/go-arg)
|
||||
[](https://coveralls.io/github/alexflint/go-arg?branch=master)
|
||||
[](https://goreportcard.com/badge/github.com/alexflint/go-arg)
|
||||
|
||||
## Structured argument parsing for Go
|
||||
|
||||
```shell
|
||||
go get github.com/alexflint/go-arg
|
||||
```
|
||||
|
||||
Declare the command line arguments your program accepts by defining a struct.
|
||||
|
||||
```go
|
||||
var args struct {
|
||||
Foo string
|
||||
Bar bool
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
fmt.Println(args.Foo, args.Bar)
|
||||
```
|
||||
|
||||
```shell
|
||||
$ ./example --foo=hello --bar
|
||||
hello true
|
||||
```
|
||||
|
||||
### Required arguments
|
||||
|
||||
```go
|
||||
var args struct {
|
||||
ID int `arg:"required"`
|
||||
Timeout time.Duration
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
```
|
||||
|
||||
```shell
|
||||
$ ./example
|
||||
Usage: example --id ID [--timeout TIMEOUT]
|
||||
error: --id is required
|
||||
```
|
||||
|
||||
### Positional arguments
|
||||
|
||||
```go
|
||||
var args struct {
|
||||
Input string `arg:"positional"`
|
||||
Output []string `arg:"positional"`
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
fmt.Println("Input:", args.Input)
|
||||
fmt.Println("Output:", args.Output)
|
||||
```
|
||||
|
||||
```
|
||||
$ ./example src.txt x.out y.out z.out
|
||||
Input: src.txt
|
||||
Output: [x.out y.out z.out]
|
||||
```
|
||||
|
||||
### Environment variables
|
||||
|
||||
```go
|
||||
var args struct {
|
||||
Workers int `arg:"env"`
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
fmt.Println("Workers:", args.Workers)
|
||||
```
|
||||
|
||||
```
|
||||
$ WORKERS=4 ./example
|
||||
Workers: 4
|
||||
```
|
||||
|
||||
```
|
||||
$ WORKERS=4 ./example --workers=6
|
||||
Workers: 6
|
||||
```
|
||||
|
||||
You can also override the name of the environment variable:
|
||||
|
||||
```go
|
||||
var args struct {
|
||||
Workers int `arg:"env:NUM_WORKERS"`
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
fmt.Println("Workers:", args.Workers)
|
||||
```
|
||||
|
||||
```
|
||||
$ NUM_WORKERS=4 ./example
|
||||
Workers: 4
|
||||
```
|
||||
|
||||
### Usage strings
|
||||
```go
|
||||
var args struct {
|
||||
Input string `arg:"positional"`
|
||||
Output []string `arg:"positional"`
|
||||
Verbose bool `arg:"-v,help:verbosity level"`
|
||||
Dataset string `arg:"help:dataset to use"`
|
||||
Optimize int `arg:"-O,help:optimization level"`
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
```
|
||||
|
||||
```shell
|
||||
$ ./example -h
|
||||
Usage: [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--help] INPUT [OUTPUT [OUTPUT ...]]
|
||||
|
||||
Positional arguments:
|
||||
INPUT
|
||||
OUTPUT
|
||||
|
||||
Options:
|
||||
--verbose, -v verbosity level
|
||||
--dataset DATASET dataset to use
|
||||
--optimize OPTIMIZE, -O OPTIMIZE
|
||||
optimization level
|
||||
--help, -h print this help message
|
||||
```
|
||||
|
||||
### Default values
|
||||
|
||||
```go
|
||||
var args struct {
|
||||
Foo string
|
||||
Bar bool
|
||||
}
|
||||
args.Foo = "default value"
|
||||
arg.MustParse(&args)
|
||||
```
|
||||
|
||||
### Arguments with multiple values
|
||||
```go
|
||||
var args struct {
|
||||
Database string
|
||||
IDs []int64
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
fmt.Printf("Fetching the following IDs from %s: %q", args.Database, args.IDs)
|
||||
```
|
||||
|
||||
```shell
|
||||
./example -database foo -ids 1 2 3
|
||||
Fetching the following IDs from foo: [1 2 3]
|
||||
```
|
||||
|
||||
### Arguments that can be specified multiple times, mixed with positionals
|
||||
```go
|
||||
var args struct {
|
||||
Commands []string `arg:"-c,separate"`
|
||||
Files []string `arg:"-f,separate"`
|
||||
Databases []string `arg:"positional"`
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
./example -c cmd1 db1 -f file1 db2 -c cmd2 -f file2 -f file3 db3 -c cmd3
|
||||
Commands: [cmd1 cmd2 cmd3]
|
||||
Files [file1 file2 file3]
|
||||
Databases [db1 db2 db3]
|
||||
```
|
||||
|
||||
### Custom validation
|
||||
```go
|
||||
var args struct {
|
||||
Foo string
|
||||
Bar string
|
||||
}
|
||||
p := arg.MustParse(&args)
|
||||
if args.Foo == "" && args.Bar == "" {
|
||||
p.Fail("you must provide one of --foo and --bar")
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
./example
|
||||
Usage: samples [--foo FOO] [--bar BAR]
|
||||
error: you must provide one of --foo and --bar
|
||||
```
|
||||
|
||||
### Version strings
|
||||
|
||||
```go
|
||||
type args struct {
|
||||
...
|
||||
}
|
||||
|
||||
func (args) Version() string {
|
||||
return "someprogram 4.3.0"
|
||||
}
|
||||
|
||||
func main() {
|
||||
var args args
|
||||
arg.MustParse(&args)
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
$ ./example --version
|
||||
someprogram 4.3.0
|
||||
```
|
||||
|
||||
### Embedded structs
|
||||
|
||||
The fields of embedded structs are treated just like regular fields:
|
||||
|
||||
```go
|
||||
|
||||
type DatabaseOptions struct {
|
||||
Host string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type LogOptions struct {
|
||||
LogFile string
|
||||
Verbose bool
|
||||
}
|
||||
|
||||
func main() {
|
||||
var args struct {
|
||||
DatabaseOptions
|
||||
LogOptions
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
}
|
||||
```
|
||||
|
||||
As usual, any field tagged with `arg:"-"` is ignored.
|
||||
|
||||
### Custom parsing
|
||||
|
||||
You can implement your own argument parser by implementing `encoding.TextUnmarshaler`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alexflint/go-arg"
|
||||
)
|
||||
|
||||
// Accepts command line arguments of the form "head.tail"
|
||||
type NameDotName struct {
|
||||
Head, Tail string
|
||||
}
|
||||
|
||||
func (n *NameDotName) UnmarshalText(b []byte) error {
|
||||
s := string(b)
|
||||
pos := strings.Index(s, ".")
|
||||
if pos == -1 {
|
||||
return fmt.Errorf("missing period in %s", s)
|
||||
}
|
||||
n.Head = s[:pos]
|
||||
n.Tail = s[pos+1:]
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var args struct {
|
||||
Name *NameDotName
|
||||
}
|
||||
arg.MustParse(&args)
|
||||
fmt.Printf("%#v\n", args.Name)
|
||||
}
|
||||
```
|
||||
```shell
|
||||
$ ./example --name=foo.bar
|
||||
&main.NameDotName{Head:"foo", Tail:"bar"}
|
||||
|
||||
$ ./example --name=oops
|
||||
Usage: example [--name NAME]
|
||||
error: error processing --name: missing period in "oops"
|
||||
```
|
||||
|
||||
### Description strings
|
||||
|
||||
```go
|
||||
type args struct {
|
||||
Foo string
|
||||
}
|
||||
|
||||
func (args) Description() string {
|
||||
return "this program does this and that"
|
||||
}
|
||||
|
||||
func main() {
|
||||
var args args
|
||||
arg.MustParse(&args)
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
$ ./example -h
|
||||
this program does this and that
|
||||
Usage: example [--foo FOO]
|
||||
|
||||
Options:
|
||||
--foo FOO
|
||||
--help, -h display this help and exit
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
https://godoc.org/github.com/alexflint/go-arg
|
||||
|
||||
### Rationale
|
||||
|
||||
There are many command line argument parsing libraries for Go, including one in the standard library, so why build another?
|
||||
|
||||
The shortcomings of the `flag` library that ships in the standard library are well known. Positional arguments must preceed options, so `./prog x --foo=1` does what you expect but `./prog --foo=1 x` does not. Arguments cannot have both long (`--foo`) and short (`-f`) forms.
|
||||
|
||||
Many third-party argument parsing libraries are geared for writing sophisticated command line interfaces. The excellent `codegangsta/cli` is perfect for working with multiple sub-commands and nested flags, but is probably overkill for a simple script with a handful of flags.
|
||||
|
||||
The main idea behind `go-arg` is that Go already has an excellent way to describe data structures using Go structs, so there is no need to develop more levels of abstraction on top of this. Instead of one API to specify which arguments your program accepts, and then another API to get the values of those arguments, why not replace both with a single struct?
|
36
tools/vendor/github.com/alexflint/go-arg/doc.go
generated
vendored
Normal file
36
tools/vendor/github.com/alexflint/go-arg/doc.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Package arg parses command line arguments using the fields from a struct.
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
// var args struct {
|
||||
// Iter int
|
||||
// Debug bool
|
||||
// }
|
||||
// arg.MustParse(&args)
|
||||
//
|
||||
// defines two command line arguments, which can be set using any of
|
||||
//
|
||||
// ./example --iter=1 --debug // debug is a boolean flag so its value is set to true
|
||||
// ./example -iter 1 // debug defaults to its zero value (false)
|
||||
// ./example --debug=true // iter defaults to its zero value (zero)
|
||||
//
|
||||
// The fastest way to see how to use go-arg is to read the examples below.
|
||||
//
|
||||
// Fields can be bool, string, any float type, or any signed or unsigned integer type.
|
||||
// They can also be slices of any of the above, or slices of pointers to any of the above.
|
||||
//
|
||||
// Tags can be specified using the `arg` package name:
|
||||
//
|
||||
// var args struct {
|
||||
// Input string `arg:"positional"`
|
||||
// Log string `arg:"positional,required"`
|
||||
// Debug bool `arg:"-d,help:turn on debug mode"`
|
||||
// RealMode bool `arg:"--real"
|
||||
// Wr io.Writer `arg:"-"`
|
||||
// }
|
||||
//
|
||||
// The valid tag strings are `positional`, `required`, and `help`. Further, any tag string
|
||||
// that starts with a single hyphen is the short form for an argument (e.g. `./example -d`),
|
||||
// and any tag string that starts with two hyphens is the long form for the argument
|
||||
// (instead of the field name). Fields can be excluded from processing with `arg:"-"`.
|
||||
package arg
|
485
tools/vendor/github.com/alexflint/go-arg/parse.go
generated
vendored
Normal file
485
tools/vendor/github.com/alexflint/go-arg/parse.go
generated
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
package arg
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
scalar "github.com/alexflint/go-scalar"
|
||||
)
|
||||
|
||||
// spec represents a command line option
|
||||
type spec struct {
|
||||
dest reflect.Value
|
||||
long string
|
||||
short string
|
||||
multiple bool
|
||||
required bool
|
||||
positional bool
|
||||
separate bool
|
||||
help string
|
||||
env string
|
||||
wasPresent bool
|
||||
boolean bool
|
||||
}
|
||||
|
||||
// ErrHelp indicates that -h or --help were provided
|
||||
var ErrHelp = errors.New("help requested by user")
|
||||
|
||||
// ErrVersion indicates that --version was provided
|
||||
var ErrVersion = errors.New("version requested by user")
|
||||
|
||||
// MustParse processes command line arguments and exits upon failure
|
||||
func MustParse(dest ...interface{}) *Parser {
|
||||
p, err := NewParser(Config{}, dest...)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
err = p.Parse(flags())
|
||||
if err == ErrHelp {
|
||||
p.WriteHelp(os.Stdout)
|
||||
os.Exit(0)
|
||||
}
|
||||
if err == ErrVersion {
|
||||
fmt.Println(p.version)
|
||||
os.Exit(0)
|
||||
}
|
||||
if err != nil {
|
||||
p.Fail(err.Error())
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Parse processes command line arguments and stores them in dest
|
||||
func Parse(dest ...interface{}) error {
|
||||
p, err := NewParser(Config{}, dest...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return p.Parse(flags())
|
||||
}
|
||||
|
||||
// flags gets all command line arguments other than the first (program name)
|
||||
func flags() []string {
|
||||
if len(os.Args) == 0 { // os.Args could be empty
|
||||
return nil
|
||||
}
|
||||
return os.Args[1:]
|
||||
}
|
||||
|
||||
// Config represents configuration options for an argument parser
|
||||
type Config struct {
|
||||
Program string // Program is the name of the program used in the help text
|
||||
}
|
||||
|
||||
// Parser represents a set of command line options with destination values
|
||||
type Parser struct {
|
||||
spec []*spec
|
||||
config Config
|
||||
version string
|
||||
description string
|
||||
}
|
||||
|
||||
// Versioned is the interface that the destination struct should implement to
|
||||
// make a version string appear at the top of the help message.
|
||||
type Versioned interface {
|
||||
// Version returns the version string that will be printed on a line by itself
|
||||
// at the top of the help message.
|
||||
Version() string
|
||||
}
|
||||
|
||||
// Described is the interface that the destination struct should implement to
|
||||
// make a description string appear at the top of the help message.
|
||||
type Described interface {
|
||||
// Description returns the string that will be printed on a line by itself
|
||||
// at the top of the help message.
|
||||
Description() string
|
||||
}
|
||||
|
||||
// walkFields calls a function for each field of a struct, recursively expanding struct fields.
|
||||
func walkFields(v reflect.Value, visit func(field reflect.StructField, val reflect.Value, owner reflect.Type) bool) {
|
||||
t := v.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
val := v.Field(i)
|
||||
expand := visit(field, val, t)
|
||||
if expand && field.Type.Kind() == reflect.Struct {
|
||||
walkFields(val, visit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewParser constructs a parser from a list of destination structs
|
||||
func NewParser(config Config, dests ...interface{}) (*Parser, error) {
|
||||
p := Parser{
|
||||
config: config,
|
||||
}
|
||||
for _, dest := range dests {
|
||||
if dest, ok := dest.(Versioned); ok {
|
||||
p.version = dest.Version()
|
||||
}
|
||||
if dest, ok := dest.(Described); ok {
|
||||
p.description = dest.Description()
|
||||
}
|
||||
v := reflect.ValueOf(dest)
|
||||
if v.Kind() != reflect.Ptr {
|
||||
panic(fmt.Sprintf("%s is not a pointer (did you forget an ampersand?)", v.Type()))
|
||||
}
|
||||
v = v.Elem()
|
||||
if v.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("%T is not a struct pointer", dest))
|
||||
}
|
||||
|
||||
var errs []string
|
||||
walkFields(v, func(field reflect.StructField, val reflect.Value, t reflect.Type) bool {
|
||||
// Check for the ignore switch in the tag
|
||||
tag := field.Tag.Get("arg")
|
||||
if tag == "-" {
|
||||
return false
|
||||
}
|
||||
|
||||
// If this is an embedded struct then recurse into its fields
|
||||
if field.Anonymous && field.Type.Kind() == reflect.Struct {
|
||||
return true
|
||||
}
|
||||
|
||||
spec := spec{
|
||||
long: strings.ToLower(field.Name),
|
||||
dest: val,
|
||||
}
|
||||
|
||||
// Check whether this field is supported. It's good to do this here rather than
|
||||
// wait until setScalar because it means that a program with invalid argument
|
||||
// fields will always fail regardless of whether the arguments it received
|
||||
// exercised those fields.
|
||||
var parseable bool
|
||||
parseable, spec.boolean, spec.multiple = canParse(field.Type)
|
||||
if !parseable {
|
||||
errs = append(errs, fmt.Sprintf("%s.%s: %s fields are not supported",
|
||||
t.Name(), field.Name, field.Type.String()))
|
||||
return false
|
||||
}
|
||||
|
||||
// Look at the tag
|
||||
if tag != "" {
|
||||
for _, key := range strings.Split(tag, ",") {
|
||||
var value string
|
||||
if pos := strings.Index(key, ":"); pos != -1 {
|
||||
value = key[pos+1:]
|
||||
key = key[:pos]
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(key, "---"):
|
||||
errs = append(errs, fmt.Sprintf("%s.%s: too many hyphens", t.Name(), field.Name))
|
||||
case strings.HasPrefix(key, "--"):
|
||||
spec.long = key[2:]
|
||||
case strings.HasPrefix(key, "-"):
|
||||
if len(key) != 2 {
|
||||
errs = append(errs, fmt.Sprintf("%s.%s: short arguments must be one character only",
|
||||
t.Name(), field.Name))
|
||||
return false
|
||||
}
|
||||
spec.short = key[1:]
|
||||
case key == "required":
|
||||
spec.required = true
|
||||
case key == "positional":
|
||||
spec.positional = true
|
||||
case key == "separate":
|
||||
spec.separate = true
|
||||
case key == "help":
|
||||
spec.help = value
|
||||
case key == "env":
|
||||
// Use override name if provided
|
||||
if value != "" {
|
||||
spec.env = value
|
||||
} else {
|
||||
spec.env = strings.ToUpper(field.Name)
|
||||
}
|
||||
default:
|
||||
errs = append(errs, fmt.Sprintf("unrecognized tag '%s' on field %s", key, tag))
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
p.spec = append(p.spec, &spec)
|
||||
|
||||
// if this was an embedded field then we already returned true up above
|
||||
return false
|
||||
})
|
||||
|
||||
if len(errs) > 0 {
|
||||
return nil, errors.New(strings.Join(errs, "\n"))
|
||||
}
|
||||
}
|
||||
if p.config.Program == "" {
|
||||
p.config.Program = "program"
|
||||
if len(os.Args) > 0 {
|
||||
p.config.Program = filepath.Base(os.Args[0])
|
||||
}
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
// Parse processes the given command line option, storing the results in the field
|
||||
// of the structs from which NewParser was constructed
|
||||
func (p *Parser) Parse(args []string) error {
|
||||
// If -h or --help were specified then print usage
|
||||
for _, arg := range args {
|
||||
if arg == "-h" || arg == "--help" {
|
||||
return ErrHelp
|
||||
}
|
||||
if arg == "--version" {
|
||||
return ErrVersion
|
||||
}
|
||||
if arg == "--" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Process all command line arguments
|
||||
err := process(p.spec, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate
|
||||
return validate(p.spec)
|
||||
}
|
||||
|
||||
// process goes through arguments one-by-one, parses them, and assigns the result to
|
||||
// the underlying struct field
|
||||
func process(specs []*spec, args []string) error {
|
||||
// construct a map from --option to spec
|
||||
optionMap := make(map[string]*spec)
|
||||
for _, spec := range specs {
|
||||
if spec.positional {
|
||||
continue
|
||||
}
|
||||
if spec.long != "" {
|
||||
optionMap[spec.long] = spec
|
||||
}
|
||||
if spec.short != "" {
|
||||
optionMap[spec.short] = spec
|
||||
}
|
||||
if spec.env != "" {
|
||||
if value, found := os.LookupEnv(spec.env); found {
|
||||
err := setScalar(spec.dest, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
|
||||
}
|
||||
spec.wasPresent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process each string from the command line
|
||||
var allpositional bool
|
||||
var positionals []string
|
||||
|
||||
// must use explicit for loop, not range, because we manipulate i inside the loop
|
||||
for i := 0; i < len(args); i++ {
|
||||
arg := args[i]
|
||||
if arg == "--" {
|
||||
allpositional = true
|
||||
continue
|
||||
}
|
||||
|
||||
if !isFlag(arg) || allpositional {
|
||||
positionals = append(positionals, arg)
|
||||
continue
|
||||
}
|
||||
|
||||
// check for an equals sign, as in "--foo=bar"
|
||||
var value string
|
||||
opt := strings.TrimLeft(arg, "-")
|
||||
if pos := strings.Index(opt, "="); pos != -1 {
|
||||
value = opt[pos+1:]
|
||||
opt = opt[:pos]
|
||||
}
|
||||
|
||||
// lookup the spec for this option
|
||||
spec, ok := optionMap[opt]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown argument %s", arg)
|
||||
}
|
||||
spec.wasPresent = true
|
||||
|
||||
// deal with the case of multiple values
|
||||
if spec.multiple {
|
||||
var values []string
|
||||
if value == "" {
|
||||
for i+1 < len(args) && !isFlag(args[i+1]) {
|
||||
values = append(values, args[i+1])
|
||||
i++
|
||||
if spec.separate {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
values = append(values, value)
|
||||
}
|
||||
err := setSlice(spec.dest, values, !spec.separate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing %s: %v", arg, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// if it's a flag and it has no value then set the value to true
|
||||
// use boolean because this takes account of TextUnmarshaler
|
||||
if spec.boolean && value == "" {
|
||||
value = "true"
|
||||
}
|
||||
|
||||
// if we have something like "--foo" then the value is the next argument
|
||||
if value == "" {
|
||||
if i+1 == len(args) || isFlag(args[i+1]) {
|
||||
return fmt.Errorf("missing value for %s", arg)
|
||||
}
|
||||
value = args[i+1]
|
||||
i++
|
||||
}
|
||||
|
||||
err := setScalar(spec.dest, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing %s: %v", arg, err)
|
||||
}
|
||||
}
|
||||
|
||||
// process positionals
|
||||
for _, spec := range specs {
|
||||
if spec.positional {
|
||||
if spec.multiple {
|
||||
if spec.required && len(positionals) == 0 {
|
||||
return fmt.Errorf("%s is required", spec.long)
|
||||
}
|
||||
err := setSlice(spec.dest, positionals, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing %s: %v", spec.long, err)
|
||||
}
|
||||
positionals = nil
|
||||
} else if len(positionals) > 0 {
|
||||
err := setScalar(spec.dest, positionals[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("error processing %s: %v", spec.long, err)
|
||||
}
|
||||
positionals = positionals[1:]
|
||||
} else if spec.required {
|
||||
return fmt.Errorf("%s is required", spec.long)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(positionals) > 0 {
|
||||
return fmt.Errorf("too many positional arguments at '%s'", positionals[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isFlag returns true if a token is a flag such as "-v" or "--user" but not "-" or "--"
|
||||
func isFlag(s string) bool {
|
||||
return strings.HasPrefix(s, "-") && strings.TrimLeft(s, "-") != ""
|
||||
}
|
||||
|
||||
// validate an argument spec after arguments have been parse
|
||||
func validate(spec []*spec) error {
|
||||
for _, arg := range spec {
|
||||
if !arg.positional && arg.required && !arg.wasPresent {
|
||||
return fmt.Errorf("--%s is required", arg.long)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parse a value as the appropriate type and store it in the struct
|
||||
func setSlice(dest reflect.Value, values []string, trunc bool) error {
|
||||
if !dest.CanSet() {
|
||||
return fmt.Errorf("field is not writable")
|
||||
}
|
||||
|
||||
var ptr bool
|
||||
elem := dest.Type().Elem()
|
||||
if elem.Kind() == reflect.Ptr {
|
||||
ptr = true
|
||||
elem = elem.Elem()
|
||||
}
|
||||
|
||||
// Truncate the dest slice in case default values exist
|
||||
if trunc && !dest.IsNil() {
|
||||
dest.SetLen(0)
|
||||
}
|
||||
|
||||
for _, s := range values {
|
||||
v := reflect.New(elem)
|
||||
if err := setScalar(v.Elem(), s); err != nil {
|
||||
return err
|
||||
}
|
||||
if !ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
dest.Set(reflect.Append(dest, v))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// canParse returns true if the type can be parsed from a string
|
||||
func canParse(t reflect.Type) (parseable, boolean, multiple bool) {
|
||||
parseable, boolean = isScalar(t)
|
||||
if parseable {
|
||||
return
|
||||
}
|
||||
|
||||
// Look inside pointer types
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// Look inside slice types
|
||||
if t.Kind() == reflect.Slice {
|
||||
multiple = true
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
parseable, boolean = isScalar(t)
|
||||
if parseable {
|
||||
return
|
||||
}
|
||||
|
||||
// Look inside pointer types (again, in case of []*Type)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
parseable, boolean = isScalar(t)
|
||||
if parseable {
|
||||
return
|
||||
}
|
||||
|
||||
return false, false, false
|
||||
}
|
||||
|
||||
var textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
|
||||
|
||||
// isScalar returns true if the type can be parsed from a single string
|
||||
func isScalar(t reflect.Type) (parseable, boolean bool) {
|
||||
parseable = scalar.CanParse(t)
|
||||
switch {
|
||||
case t.Implements(textUnmarshalerType):
|
||||
return parseable, false
|
||||
case t.Kind() == reflect.Bool:
|
||||
return parseable, true
|
||||
case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Bool:
|
||||
return parseable, true
|
||||
default:
|
||||
return parseable, false
|
||||
}
|
||||
}
|
||||
|
||||
// set a value from a string
|
||||
func setScalar(v reflect.Value, s string) error {
|
||||
return scalar.ParseValue(v, s)
|
||||
}
|
148
tools/vendor/github.com/alexflint/go-arg/usage.go
generated
vendored
Normal file
148
tools/vendor/github.com/alexflint/go-arg/usage.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package arg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// the width of the left column
|
||||
const colWidth = 25
|
||||
|
||||
// Fail prints usage information to stderr and exits with non-zero status
|
||||
func (p *Parser) Fail(msg string) {
|
||||
p.WriteUsage(os.Stderr)
|
||||
fmt.Fprintln(os.Stderr, "error:", msg)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
// WriteUsage writes usage information to the given writer
|
||||
func (p *Parser) WriteUsage(w io.Writer) {
|
||||
var positionals, options []*spec
|
||||
for _, spec := range p.spec {
|
||||
if spec.positional {
|
||||
positionals = append(positionals, spec)
|
||||
} else {
|
||||
options = append(options, spec)
|
||||
}
|
||||
}
|
||||
|
||||
if p.version != "" {
|
||||
fmt.Fprintln(w, p.version)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "Usage: %s", p.config.Program)
|
||||
|
||||
// write the option component of the usage message
|
||||
for _, spec := range options {
|
||||
// prefix with a space
|
||||
fmt.Fprint(w, " ")
|
||||
if !spec.required {
|
||||
fmt.Fprint(w, "[")
|
||||
}
|
||||
fmt.Fprint(w, synopsis(spec, "--"+spec.long))
|
||||
if !spec.required {
|
||||
fmt.Fprint(w, "]")
|
||||
}
|
||||
}
|
||||
|
||||
// write the positional component of the usage message
|
||||
for _, spec := range positionals {
|
||||
// prefix with a space
|
||||
fmt.Fprint(w, " ")
|
||||
up := strings.ToUpper(spec.long)
|
||||
if spec.multiple {
|
||||
if !spec.required {
|
||||
fmt.Fprint(w, "[")
|
||||
}
|
||||
fmt.Fprintf(w, "%s [%s ...]", up, up)
|
||||
if !spec.required {
|
||||
fmt.Fprint(w, "]")
|
||||
}
|
||||
} else {
|
||||
fmt.Fprint(w, up)
|
||||
}
|
||||
}
|
||||
fmt.Fprint(w, "\n")
|
||||
}
|
||||
|
||||
// WriteHelp writes the usage string followed by the full help string for each option
|
||||
func (p *Parser) WriteHelp(w io.Writer) {
|
||||
var positionals, options []*spec
|
||||
for _, spec := range p.spec {
|
||||
if spec.positional {
|
||||
positionals = append(positionals, spec)
|
||||
} else {
|
||||
options = append(options, spec)
|
||||
}
|
||||
}
|
||||
|
||||
if p.description != "" {
|
||||
fmt.Fprintln(w, p.description)
|
||||
}
|
||||
p.WriteUsage(w)
|
||||
|
||||
// write the list of positionals
|
||||
if len(positionals) > 0 {
|
||||
fmt.Fprint(w, "\nPositional arguments:\n")
|
||||
for _, spec := range positionals {
|
||||
left := " " + strings.ToUpper(spec.long)
|
||||
fmt.Fprint(w, left)
|
||||
if spec.help != "" {
|
||||
if len(left)+2 < colWidth {
|
||||
fmt.Fprint(w, strings.Repeat(" ", colWidth-len(left)))
|
||||
} else {
|
||||
fmt.Fprint(w, "\n"+strings.Repeat(" ", colWidth))
|
||||
}
|
||||
fmt.Fprint(w, spec.help)
|
||||
}
|
||||
fmt.Fprint(w, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
// write the list of options
|
||||
fmt.Fprint(w, "\nOptions:\n")
|
||||
for _, spec := range options {
|
||||
printOption(w, spec)
|
||||
}
|
||||
|
||||
// write the list of built in options
|
||||
printOption(w, &spec{boolean: true, long: "help", short: "h", help: "display this help and exit"})
|
||||
if p.version != "" {
|
||||
printOption(w, &spec{boolean: true, long: "version", help: "display version and exit"})
|
||||
}
|
||||
}
|
||||
|
||||
func printOption(w io.Writer, spec *spec) {
|
||||
left := " " + synopsis(spec, "--"+spec.long)
|
||||
if spec.short != "" {
|
||||
left += ", " + synopsis(spec, "-"+spec.short)
|
||||
}
|
||||
fmt.Fprint(w, left)
|
||||
if spec.help != "" {
|
||||
if len(left)+2 < colWidth {
|
||||
fmt.Fprint(w, strings.Repeat(" ", colWidth-len(left)))
|
||||
} else {
|
||||
fmt.Fprint(w, "\n"+strings.Repeat(" ", colWidth))
|
||||
}
|
||||
fmt.Fprint(w, spec.help)
|
||||
}
|
||||
// If spec.dest is not the zero value then a default value has been added.
|
||||
v := spec.dest
|
||||
if v.IsValid() {
|
||||
z := reflect.Zero(v.Type())
|
||||
if (v.Type().Comparable() && z.Type().Comparable() && v.Interface() != z.Interface()) || v.Kind() == reflect.Slice && !v.IsNil() {
|
||||
fmt.Fprintf(w, " [default: %v]", v)
|
||||
}
|
||||
}
|
||||
fmt.Fprint(w, "\n")
|
||||
}
|
||||
|
||||
func synopsis(spec *spec, form string) string {
|
||||
if spec.boolean {
|
||||
return form
|
||||
}
|
||||
return form + " " + strings.ToUpper(spec.long)
|
||||
}
|
Reference in New Issue
Block a user