mirror of
https://github.com/Luzifer/elastic_cron.git
synced 2024-12-23 02:41:20 +00:00
Update dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
da8edd41c2
commit
421f2bfe84
66 changed files with 4427 additions and 458 deletions
23
Gopkg.lock
generated
23
Gopkg.lock
generated
|
@ -4,24 +4,26 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/Luzifer/rconfig"
|
name = "github.com/Luzifer/rconfig"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "c27bd3a64b5b19556914d9fec69922cf3852d585"
|
revision = "7aef1d393c1e2d0758901853b59981c7adc67c7e"
|
||||||
version = "v1.1.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/cenkalti/backoff"
|
name = "github.com/cenkalti/backoff"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "9831e1e25c874e0a0601b6dc43641071414eec7a"
|
revision = "61153c768f31ee5f130071d08fc82b85208528de"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "v1"
|
|
||||||
name = "github.com/robfig/cron"
|
name = "github.com/robfig/cron"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "67823cd24dece1b04cced3a0a0b3ca2bc84d875e"
|
revision = "b024fc5ea0e34bc3f83d9941c8d60b0622bfaca4"
|
||||||
|
version = "v1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/spf13/pflag"
|
name = "github.com/spf13/pflag"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "c7e63cf4530bcd3ba943729cee0efeff2ebea63f"
|
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -30,9 +32,16 @@
|
||||||
revision = "b129b8e0fbeb39c8358e51a07ab6c50ad415e72e"
|
revision = "b129b8e0fbeb39c8358e51a07ab6c50ad415e72e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/validator.v2"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "460c83432a98c35224a6fe352acf8b23e067ad06"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "31c299268d302dd0aa9a0dcf765a3d58971ac83f"
|
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
|
|
4
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
4
vendor/github.com/Luzifer/rconfig/.travis.yml
generated
vendored
|
@ -1,8 +1,8 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.4
|
- 1.6
|
||||||
- 1.5
|
- 1.7
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
script: go test -v -race -cover ./...
|
script: go test -v -race -cover ./...
|
||||||
|
|
4
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
4
vendor/github.com/Luzifer/rconfig/History.md
generated
vendored
|
@ -1,3 +1,7 @@
|
||||||
|
# 1.2.0 / 2017-06-19
|
||||||
|
|
||||||
|
* Add ParseAndValidate method
|
||||||
|
|
||||||
# 1.1.0 / 2016-06-28
|
# 1.1.0 / 2016-06-28
|
||||||
|
|
||||||
* Support time.Duration config parameters
|
* Support time.Duration config parameters
|
||||||
|
|
39
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
39
vendor/github.com/Luzifer/rconfig/README.md
generated
vendored
|
@ -29,31 +29,28 @@ go test -v -race -cover github.com/Luzifer/rconfig
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
As a first step define a struct holding your configuration:
|
A very simple usecase is to just configure a struct inside the vars section of your `main.go` and to parse the commandline flags from the `main()` function:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type config struct {
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Luzifer/rconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cfg = struct {
|
||||||
Username string `default:"unknown" flag:"user" description:"Your name"`
|
Username string `default:"unknown" flag:"user" description:"Your name"`
|
||||||
Details struct {
|
Details struct {
|
||||||
Age int `default:"25" flag:"age" env:"age" description:"Your age"`
|
Age int `default:"25" flag:"age" env:"age" description:"Your age"`
|
||||||
}
|
}
|
||||||
}
|
}{}
|
||||||
```
|
)
|
||||||
|
|
||||||
Next create an instance of that struct and let `rconfig` fill that config:
|
|
||||||
|
|
||||||
```go
|
|
||||||
var cfg config
|
|
||||||
func init() {
|
|
||||||
cfg = config{}
|
|
||||||
rconfig.Parse(&cfg)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You're ready to access your configuration:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
func main() {
|
||||||
|
rconfig.Parse(&cfg)
|
||||||
|
|
||||||
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
||||||
cfg.Username,
|
cfg.Username,
|
||||||
cfg.Details.Age)
|
cfg.Details.Age)
|
||||||
|
@ -72,18 +69,14 @@ The order of the directives (lower number = higher precedence):
|
||||||
1. `default` tag in the struct
|
1. `default` tag in the struct
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type config struct {
|
var cfg = struct {
|
||||||
Username string `vardefault:"username" flag:"username" description:"Your username"`
|
Username string `vardefault:"username" flag:"username" description:"Your username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg = config{}
|
func main() {
|
||||||
|
|
||||||
func init() {
|
|
||||||
rconfig.SetVariableDefaults(rconfig.VarDefaultsFromYAMLFile("~/.myapp.yml"))
|
rconfig.SetVariableDefaults(rconfig.VarDefaultsFromYAMLFile("~/.myapp.yml"))
|
||||||
rconfig.Parse(&cfg)
|
rconfig.Parse(&cfg)
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Printf("Username = %s", cfg.Username)
|
fmt.Printf("Username = %s", cfg.Username)
|
||||||
// Output: Username = luzifer
|
// Output: Username = luzifer
|
||||||
}
|
}
|
||||||
|
|
18
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
18
vendor/github.com/Luzifer/rconfig/config.go
generated
vendored
|
@ -13,6 +13,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
validator "gopkg.in/validator.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -45,6 +46,15 @@ func Parse(config interface{}) error {
|
||||||
return parse(config, nil)
|
return parse(config, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseAndValidate works exactly like Parse but implements an additional run of
|
||||||
|
// the go-validator package on the configuration struct. Therefore additonal struct
|
||||||
|
// tags are supported like described in the readme file of the go-validator package:
|
||||||
|
//
|
||||||
|
// https://github.com/go-validator/validator/tree/v2#usage
|
||||||
|
func ParseAndValidate(config interface{}) error {
|
||||||
|
return parseAndValidate(config, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// Args returns the non-flag command-line arguments.
|
// Args returns the non-flag command-line arguments.
|
||||||
func Args() []string {
|
func Args() []string {
|
||||||
return fs.Args()
|
return fs.Args()
|
||||||
|
@ -65,6 +75,14 @@ func SetVariableDefaults(defaults map[string]string) {
|
||||||
variableDefaults = defaults
|
variableDefaults = defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseAndValidate(in interface{}, args []string) error {
|
||||||
|
if err := parse(in, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return validator.Validate(in)
|
||||||
|
}
|
||||||
|
|
||||||
func parse(in interface{}, args []string) error {
|
func parse(in interface{}, args []string) error {
|
||||||
if args == nil {
|
if args == nil {
|
||||||
args = os.Args
|
args = os.Args
|
||||||
|
|
19
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
19
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
|
@ -15,6 +15,10 @@ var _ = Describe("Testing general parsing", func() {
|
||||||
SadFlag string
|
SadFlag string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tValidated struct {
|
||||||
|
Test string `flag:"test" default:"" validate:"nonzero"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
args []string
|
args []string
|
||||||
|
@ -106,4 +110,19 @@ var _ = Describe("Testing general parsing", func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("making use of the validator package", func() {
|
||||||
|
var cfgValidated tValidated
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfgValidated = tValidated{}
|
||||||
|
args = []string{}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parseAndValidate(&cfgValidated, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should have errored", func() { Expect(err).To(HaveOccurred()) })
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
9
vendor/github.com/cenkalti/backoff/.travis.yml
generated
vendored
9
vendor/github.com/cenkalti/backoff/.travis.yml
generated
vendored
|
@ -1,2 +1,9 @@
|
||||||
language: go
|
language: go
|
||||||
go: 1.3.3
|
go:
|
||||||
|
- 1.3.3
|
||||||
|
- tip
|
||||||
|
before_install:
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -service=travis-ci
|
||||||
|
|
75
vendor/github.com/cenkalti/backoff/README.md
generated
vendored
75
vendor/github.com/cenkalti/backoff/README.md
generated
vendored
|
@ -1,69 +1,30 @@
|
||||||
# backoff
|
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/cenkalti/backoff?status.png)](https://godoc.org/github.com/cenkalti/backoff)
|
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
|
||||||
[![Build Status](https://travis-ci.org/cenkalti/backoff.png)](https://travis-ci.org/cenkalti/backoff)
|
|
||||||
|
|
||||||
This is a Go port of the exponential backoff algorithm from
|
[Exponential backoff][exponential backoff wiki]
|
||||||
[google-http-java-client](https://code.google.com/p/google-http-java-client/wiki/ExponentialBackoff).
|
|
||||||
|
|
||||||
[Exponential backoff](http://en.wikipedia.org/wiki/Exponential_backoff)
|
|
||||||
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
|
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
|
||||||
in order to gradually find an acceptable rate.
|
in order to gradually find an acceptable rate.
|
||||||
The retries exponentially increase and stop increasing when a certain threshold is met.
|
The retries exponentially increase and stop increasing when a certain threshold is met.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
See https://godoc.org/github.com/cenkalti/backoff#pkg-examples
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
## Install
|
* I would like to keep this library as small as possible.
|
||||||
|
* Please don't send a PR without opening an issue and discussing it first.
|
||||||
|
* If proposed change is not a common use case, I will probably not accept it.
|
||||||
|
|
||||||
```bash
|
[godoc]: https://godoc.org/github.com/cenkalti/backoff
|
||||||
go get github.com/cenkalti/backoff
|
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
|
||||||
```
|
[travis]: https://travis-ci.org/cenkalti/backoff
|
||||||
|
[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
|
||||||
|
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
|
||||||
|
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
|
||||||
|
|
||||||
## Example
|
[google-http-java-client]: https://github.com/google/google-http-java-client
|
||||||
|
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
|
||||||
|
|
||||||
Simple retry helper that uses exponential back-off algorithm:
|
[advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_
|
||||||
|
|
||||||
```go
|
|
||||||
operation := func() error {
|
|
||||||
// An operation that might fail
|
|
||||||
}
|
|
||||||
|
|
||||||
err := backoff.Retry(operation, backoff.NewExponentialBackOff())
|
|
||||||
if err != nil {
|
|
||||||
// handle error
|
|
||||||
}
|
|
||||||
|
|
||||||
// operation is successfull
|
|
||||||
```
|
|
||||||
|
|
||||||
Ticker example:
|
|
||||||
|
|
||||||
```go
|
|
||||||
operation := func() error {
|
|
||||||
// An operation that may fail
|
|
||||||
}
|
|
||||||
|
|
||||||
b := backoff.NewExponentialBackOff()
|
|
||||||
ticker := backoff.NewTicker(b)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Ticks will continue to arrive when the previous operation is still running,
|
|
||||||
// so operations that take a while to fail could run in quick succession.
|
|
||||||
for t = range ticker.C {
|
|
||||||
if err = operation(); err != nil {
|
|
||||||
log.Println(err, "will retry...")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker.Stop()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
// Operation has failed.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operation is successfull.
|
|
||||||
```
|
|
||||||
|
|
32
vendor/github.com/cenkalti/backoff/backoff.go
generated
vendored
32
vendor/github.com/cenkalti/backoff/backoff.go
generated
vendored
|
@ -1,22 +1,29 @@
|
||||||
// Package backoff implements backoff algorithms for retrying operations.
|
// Package backoff implements backoff algorithms for retrying operations.
|
||||||
//
|
//
|
||||||
// Also has a Retry() helper for retrying operations that may fail.
|
// Use Retry function for retrying operations that may fail.
|
||||||
|
// If Retry does not meet your needs,
|
||||||
|
// copy/paste the function into your project and modify as you wish.
|
||||||
|
//
|
||||||
|
// There is also Ticker type similar to time.Ticker.
|
||||||
|
// You can use it if you need to work with channels.
|
||||||
|
//
|
||||||
|
// See Examples section below for usage examples.
|
||||||
package backoff
|
package backoff
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Back-off policy when retrying an operation.
|
// BackOff is a backoff policy for retrying an operation.
|
||||||
type BackOff interface {
|
type BackOff interface {
|
||||||
// Gets the duration to wait before retrying the operation or
|
// NextBackOff returns the duration to wait before retrying the operation,
|
||||||
// backoff.Stop to indicate that no retries should be made.
|
// or backoff.Stop to indicate that no more retries should be made.
|
||||||
//
|
//
|
||||||
// Example usage:
|
// Example usage:
|
||||||
//
|
//
|
||||||
// duration := backoff.NextBackOff();
|
// duration := backoff.NextBackOff();
|
||||||
// if (duration == backoff.Stop) {
|
// if (duration == backoff.Stop) {
|
||||||
// // do not retry operation
|
// // Do not retry operation.
|
||||||
// } else {
|
// } else {
|
||||||
// // sleep for duration and retry operation
|
// // Sleep for duration and retry operation.
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
NextBackOff() time.Duration
|
NextBackOff() time.Duration
|
||||||
|
@ -25,25 +32,28 @@ type BackOff interface {
|
||||||
Reset()
|
Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates that no more retries should be made for use in NextBackOff().
|
// Stop indicates that no more retries should be made for use in NextBackOff().
|
||||||
const Stop time.Duration = -1
|
const Stop time.Duration = -1
|
||||||
|
|
||||||
// ZeroBackOff is a fixed back-off policy whose back-off time is always zero,
|
// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
|
||||||
// meaning that the operation is retried immediately without waiting.
|
// meaning that the operation is retried immediately without waiting, indefinitely.
|
||||||
type ZeroBackOff struct{}
|
type ZeroBackOff struct{}
|
||||||
|
|
||||||
func (b *ZeroBackOff) Reset() {}
|
func (b *ZeroBackOff) Reset() {}
|
||||||
|
|
||||||
func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
|
func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
|
||||||
|
|
||||||
// StopBackOff is a fixed back-off policy that always returns backoff.Stop for
|
// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
|
||||||
// NextBackOff(), meaning that the operation should not be retried.
|
// NextBackOff(), meaning that the operation should never be retried.
|
||||||
type StopBackOff struct{}
|
type StopBackOff struct{}
|
||||||
|
|
||||||
func (b *StopBackOff) Reset() {}
|
func (b *StopBackOff) Reset() {}
|
||||||
|
|
||||||
func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
|
func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
|
||||||
|
|
||||||
|
// ConstantBackOff is a backoff policy that always returns the same backoff delay.
|
||||||
|
// This is in contrast to an exponential backoff policy,
|
||||||
|
// which returns a delay that grows longer as you call NextBackOff() over and over again.
|
||||||
type ConstantBackOff struct {
|
type ConstantBackOff struct {
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
}
|
}
|
||||||
|
|
3
vendor/github.com/cenkalti/backoff/backoff_test.go
generated
vendored
3
vendor/github.com/cenkalti/backoff/backoff_test.go
generated
vendored
|
@ -1,9 +1,8 @@
|
||||||
package backoff
|
package backoff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNextBackOffMillis(t *testing.T) {
|
func TestNextBackOffMillis(t *testing.T) {
|
||||||
|
|
60
vendor/github.com/cenkalti/backoff/context.go
generated
vendored
Normal file
60
vendor/github.com/cenkalti/backoff/context.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BackOffContext is a backoff policy that stops retrying after the context
|
||||||
|
// is canceled.
|
||||||
|
type BackOffContext interface {
|
||||||
|
BackOff
|
||||||
|
Context() context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type backOffContext struct {
|
||||||
|
BackOff
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext returns a BackOffContext with context ctx
|
||||||
|
//
|
||||||
|
// ctx must not be nil
|
||||||
|
func WithContext(b BackOff, ctx context.Context) BackOffContext {
|
||||||
|
if ctx == nil {
|
||||||
|
panic("nil context")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, ok := b.(*backOffContext); ok {
|
||||||
|
return &backOffContext{
|
||||||
|
BackOff: b.BackOff,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &backOffContext{
|
||||||
|
BackOff: b,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureContext(b BackOff) BackOffContext {
|
||||||
|
if cb, ok := b.(BackOffContext); ok {
|
||||||
|
return cb
|
||||||
|
}
|
||||||
|
return WithContext(b, context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backOffContext) Context() context.Context {
|
||||||
|
return b.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backOffContext) NextBackOff() time.Duration {
|
||||||
|
select {
|
||||||
|
case <-b.Context().Done():
|
||||||
|
return Stop
|
||||||
|
default:
|
||||||
|
return b.BackOff.NextBackOff()
|
||||||
|
}
|
||||||
|
}
|
26
vendor/github.com/cenkalti/backoff/context_test.go
generated
vendored
Normal file
26
vendor/github.com/cenkalti/backoff/context_test.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContext(t *testing.T) {
|
||||||
|
b := NewConstantBackOff(time.Millisecond)
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cb := WithContext(b, ctx)
|
||||||
|
|
||||||
|
if cb.Context() != ctx {
|
||||||
|
t.Error("invalid context")
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if cb.NextBackOff() != Stop {
|
||||||
|
t.Error("invalid next back off")
|
||||||
|
}
|
||||||
|
}
|
73
vendor/github.com/cenkalti/backoff/example_test.go
generated
vendored
Normal file
73
vendor/github.com/cenkalti/backoff/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleRetry() {
|
||||||
|
// An operation that may fail.
|
||||||
|
operation := func() error {
|
||||||
|
return nil // or an error
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Retry(operation, NewExponentialBackOff())
|
||||||
|
if err != nil {
|
||||||
|
// Handle error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation is successful.
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleRetryContext() {
|
||||||
|
// A context
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// An operation that may fail.
|
||||||
|
operation := func() error {
|
||||||
|
return nil // or an error
|
||||||
|
}
|
||||||
|
|
||||||
|
b := WithContext(NewExponentialBackOff(), ctx)
|
||||||
|
|
||||||
|
err := Retry(operation, b)
|
||||||
|
if err != nil {
|
||||||
|
// Handle error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation is successful.
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleTicker() {
|
||||||
|
// An operation that may fail.
|
||||||
|
operation := func() error {
|
||||||
|
return nil // or an error
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker := NewTicker(NewExponentialBackOff())
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Ticks will continue to arrive when the previous operation is still running,
|
||||||
|
// so operations that take a while to fail could run in quick succession.
|
||||||
|
for _ = range ticker.C {
|
||||||
|
if err = operation(); err != nil {
|
||||||
|
log.Println(err, "will retry...")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker.Stop()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Operation has failed.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation is successful.
|
||||||
|
return
|
||||||
|
}
|
51
vendor/github.com/cenkalti/backoff/exponential.go
generated
vendored
51
vendor/github.com/cenkalti/backoff/exponential.go
generated
vendored
|
@ -6,30 +6,37 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ExponentialBackOff is an implementation of BackOff that increases the back off
|
ExponentialBackOff is a backoff implementation that increases the backoff
|
||||||
period for each retry attempt using a randomization function that grows exponentially.
|
period for each retry attempt using a randomization function that grows exponentially.
|
||||||
|
|
||||||
NextBackOff() is calculated using the following formula:
|
NextBackOff() is calculated using the following formula:
|
||||||
|
|
||||||
randomized_interval =
|
randomized interval =
|
||||||
retry_interval * (random value in range [1 - randomization_factor, 1 + randomization_factor])
|
RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
|
||||||
|
|
||||||
In other words NextBackOff() will range between the randomization factor
|
In other words NextBackOff() will range between the randomization factor
|
||||||
percentage below and above the retry interval. For example, using 2 seconds as the base retry
|
percentage below and above the retry interval.
|
||||||
interval and 0.5 as the randomization factor, the actual back off period used in the next retry
|
|
||||||
attempt will be between 1 and 3 seconds.
|
|
||||||
|
|
||||||
Note: max_interval caps the retry_interval and not the randomized_interval.
|
For example, given the following parameters:
|
||||||
|
|
||||||
|
RetryInterval = 2
|
||||||
|
RandomizationFactor = 0.5
|
||||||
|
Multiplier = 2
|
||||||
|
|
||||||
|
the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
|
||||||
|
multiplied by the exponential, that is, between 2 and 6 seconds.
|
||||||
|
|
||||||
|
Note: MaxInterval caps the RetryInterval and not the randomized interval.
|
||||||
|
|
||||||
If the time elapsed since an ExponentialBackOff instance is created goes past the
|
If the time elapsed since an ExponentialBackOff instance is created goes past the
|
||||||
max_elapsed_time then the method NextBackOff() starts returning backoff.Stop.
|
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
|
||||||
|
|
||||||
The elapsed time can be reset by calling Reset().
|
The elapsed time can be reset by calling Reset().
|
||||||
|
|
||||||
Example: The default retry_interval is .5 seconds, default randomization_factor is 0.5, default
|
Example: Given the following default arguments, for 10 tries the sequence will be,
|
||||||
multiplier is 1.5 and the default max_interval is 1 minute. For 10 tries the sequence will be
|
and assuming we go over the MaxElapsedTime on the 10th try:
|
||||||
(values in seconds) and assuming we go over the max_elapsed_time on the 10th try:
|
|
||||||
|
|
||||||
request# retry_interval randomized_interval
|
Request # RetryInterval (seconds) Randomized Interval (seconds)
|
||||||
|
|
||||||
1 0.5 [0.25, 0.75]
|
1 0.5 [0.25, 0.75]
|
||||||
2 0.75 [0.375, 1.125]
|
2 0.75 [0.375, 1.125]
|
||||||
|
@ -42,7 +49,7 @@ multiplier is 1.5 and the default max_interval is 1 minute. For 10 tries the seq
|
||||||
9 12.807 [6.403, 19.210]
|
9 12.807 [6.403, 19.210]
|
||||||
10 19.210 backoff.Stop
|
10 19.210 backoff.Stop
|
||||||
|
|
||||||
Implementation is not thread-safe.
|
Note: Implementation is not thread-safe.
|
||||||
*/
|
*/
|
||||||
type ExponentialBackOff struct {
|
type ExponentialBackOff struct {
|
||||||
InitialInterval time.Duration
|
InitialInterval time.Duration
|
||||||
|
@ -56,6 +63,7 @@ type ExponentialBackOff struct {
|
||||||
|
|
||||||
currentInterval time.Duration
|
currentInterval time.Duration
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
|
random *rand.Rand
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clock is an interface that returns current time for BackOff.
|
// Clock is an interface that returns current time for BackOff.
|
||||||
|
@ -74,14 +82,17 @@ const (
|
||||||
|
|
||||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
||||||
func NewExponentialBackOff() *ExponentialBackOff {
|
func NewExponentialBackOff() *ExponentialBackOff {
|
||||||
return &ExponentialBackOff{
|
b := &ExponentialBackOff{
|
||||||
InitialInterval: DefaultInitialInterval,
|
InitialInterval: DefaultInitialInterval,
|
||||||
RandomizationFactor: DefaultRandomizationFactor,
|
RandomizationFactor: DefaultRandomizationFactor,
|
||||||
Multiplier: DefaultMultiplier,
|
Multiplier: DefaultMultiplier,
|
||||||
MaxInterval: DefaultMaxInterval,
|
MaxInterval: DefaultMaxInterval,
|
||||||
MaxElapsedTime: DefaultMaxElapsedTime,
|
MaxElapsedTime: DefaultMaxElapsedTime,
|
||||||
Clock: SystemClock,
|
Clock: SystemClock,
|
||||||
|
random: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||||
}
|
}
|
||||||
|
b.Reset()
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
type systemClock struct{}
|
type systemClock struct{}
|
||||||
|
@ -99,15 +110,18 @@ func (b *ExponentialBackOff) Reset() {
|
||||||
b.startTime = b.Clock.Now()
|
b.startTime = b.Clock.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextBackOff calculates the next back off interval using the formula:
|
// NextBackOff calculates the next backoff interval using the formula:
|
||||||
// randomized_interval = retry_interval +/- (randomization_factor * retry_interval)
|
// Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval)
|
||||||
func (b *ExponentialBackOff) NextBackOff() time.Duration {
|
func (b *ExponentialBackOff) NextBackOff() time.Duration {
|
||||||
// Make sure we have not gone over the maximum elapsed time.
|
// Make sure we have not gone over the maximum elapsed time.
|
||||||
if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
|
if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
|
||||||
return Stop
|
return Stop
|
||||||
}
|
}
|
||||||
defer b.incrementCurrentInterval()
|
defer b.incrementCurrentInterval()
|
||||||
return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
|
if b.random == nil {
|
||||||
|
b.random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
}
|
||||||
|
return getRandomValueFromInterval(b.RandomizationFactor, b.random.Float64(), b.currentInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
|
// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
|
||||||
|
@ -128,12 +142,13 @@ func (b *ExponentialBackOff) incrementCurrentInterval() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a random value from the interval:
|
// Returns a random value from the following interval:
|
||||||
// [randomizationFactor * currentInterval, randomizationFactor * currentInterval].
|
// [randomizationFactor * currentInterval, randomizationFactor * currentInterval].
|
||||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
||||||
var delta = randomizationFactor * float64(currentInterval)
|
var delta = randomizationFactor * float64(currentInterval)
|
||||||
var minInterval = float64(currentInterval) - delta
|
var minInterval = float64(currentInterval) - delta
|
||||||
var maxInterval = float64(currentInterval) + delta
|
var maxInterval = float64(currentInterval) + delta
|
||||||
|
|
||||||
// Get a random value from the range [minInterval, maxInterval].
|
// Get a random value from the range [minInterval, maxInterval].
|
||||||
// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
|
// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
|
||||||
// we want a 33% chance for selecting either 1, 2 or 3.
|
// we want a 33% chance for selecting either 1, 2 or 3.
|
||||||
|
|
7
vendor/github.com/cenkalti/backoff/exponential_test.go
generated
vendored
7
vendor/github.com/cenkalti/backoff/exponential_test.go
generated
vendored
|
@ -30,7 +30,7 @@ func TestBackOff(t *testing.T) {
|
||||||
|
|
||||||
for _, expected := range expectedResults {
|
for _, expected := range expectedResults {
|
||||||
assertEquals(t, expected, exp.currentInterval)
|
assertEquals(t, expected, exp.currentInterval)
|
||||||
// Assert that the next back off falls in the expected range.
|
// Assert that the next backoff falls in the expected range.
|
||||||
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
|
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
|
||||||
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
|
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
|
||||||
var actualInterval = exp.NextBackOff()
|
var actualInterval = exp.NextBackOff()
|
||||||
|
@ -77,9 +77,6 @@ func TestGetElapsedTime(t *testing.T) {
|
||||||
func TestMaxElapsedTime(t *testing.T) {
|
func TestMaxElapsedTime(t *testing.T) {
|
||||||
var exp = NewExponentialBackOff()
|
var exp = NewExponentialBackOff()
|
||||||
exp.Clock = &TestClock{start: time.Time{}.Add(10000 * time.Second)}
|
exp.Clock = &TestClock{start: time.Time{}.Add(10000 * time.Second)}
|
||||||
if exp.NextBackOff() != Stop {
|
|
||||||
t.Error("error2")
|
|
||||||
}
|
|
||||||
// Change the currentElapsedTime to be 0 ensuring that the elapsed time will be greater
|
// Change the currentElapsedTime to be 0 ensuring that the elapsed time will be greater
|
||||||
// than the max elapsed time.
|
// than the max elapsed time.
|
||||||
exp.startTime = time.Time{}
|
exp.startTime = time.Time{}
|
||||||
|
@ -90,7 +87,7 @@ func TestBackOffOverflow(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
testInitialInterval time.Duration = math.MaxInt64 / 2
|
testInitialInterval time.Duration = math.MaxInt64 / 2
|
||||||
testMaxInterval time.Duration = math.MaxInt64
|
testMaxInterval time.Duration = math.MaxInt64
|
||||||
testMultiplier float64 = 2.1
|
testMultiplier = 2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
exp := NewExponentialBackOff()
|
exp := NewExponentialBackOff()
|
||||||
|
|
71
vendor/github.com/cenkalti/backoff/retry.go
generated
vendored
71
vendor/github.com/cenkalti/backoff/retry.go
generated
vendored
|
@ -2,38 +2,46 @@ package backoff
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Retry the function f until it does not return error or BackOff stops.
|
// An Operation is executing by Retry() or RetryNotify().
|
||||||
// f is guaranteed to be run at least once.
|
// The operation will be retried using a backoff policy if it returns an error.
|
||||||
|
type Operation func() error
|
||||||
|
|
||||||
|
// Notify is a notify-on-error function. It receives an operation error and
|
||||||
|
// backoff delay if the operation failed (with an error).
|
||||||
|
//
|
||||||
|
// NOTE that if the backoff policy stated to stop retrying,
|
||||||
|
// the notify function isn't called.
|
||||||
|
type Notify func(error, time.Duration)
|
||||||
|
|
||||||
|
// Retry the operation o until it does not return error or BackOff stops.
|
||||||
|
// o is guaranteed to be run at least once.
|
||||||
// It is the caller's responsibility to reset b after Retry returns.
|
// It is the caller's responsibility to reset b after Retry returns.
|
||||||
//
|
//
|
||||||
|
// If o returns a *PermanentError, the operation is not retried, and the
|
||||||
|
// wrapped error is returned.
|
||||||
|
//
|
||||||
// Retry sleeps the goroutine for the duration returned by BackOff after a
|
// Retry sleeps the goroutine for the duration returned by BackOff after a
|
||||||
// failed operation returns.
|
// failed operation returns.
|
||||||
//
|
func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) }
|
||||||
// Usage:
|
|
||||||
// operation := func() error {
|
|
||||||
// // An operation that may fail
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// err := backoff.Retry(operation, backoff.NewExponentialBackOff())
|
|
||||||
// if err != nil {
|
|
||||||
// // Operation has failed.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Operation is successfull.
|
|
||||||
//
|
|
||||||
func Retry(f func() error, b BackOff) error { return RetryNotify(f, b, nil) }
|
|
||||||
|
|
||||||
// RetryNotify calls notify function with the error and wait duration for each failed attempt before sleep.
|
// RetryNotify calls notify function with the error and wait duration
|
||||||
func RetryNotify(f func() error, b BackOff, notify func(err error, wait time.Duration)) error {
|
// for each failed attempt before sleep.
|
||||||
|
func RetryNotify(operation Operation, b BackOff, notify Notify) error {
|
||||||
var err error
|
var err error
|
||||||
var next time.Duration
|
var next time.Duration
|
||||||
|
|
||||||
|
cb := ensureContext(b)
|
||||||
|
|
||||||
b.Reset()
|
b.Reset()
|
||||||
for {
|
for {
|
||||||
if err = f(); err == nil {
|
if err = operation(); err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if permanent, ok := err.(*PermanentError); ok {
|
||||||
|
return permanent.Err
|
||||||
|
}
|
||||||
|
|
||||||
if next = b.NextBackOff(); next == Stop {
|
if next = b.NextBackOff(); next == Stop {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -42,6 +50,29 @@ func RetryNotify(f func() error, b BackOff, notify func(err error, wait time.Dur
|
||||||
notify(err, next)
|
notify(err, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(next)
|
t := time.NewTimer(next)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-cb.Context().Done():
|
||||||
|
t.Stop()
|
||||||
|
return err
|
||||||
|
case <-t.C:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PermanentError signals that the operation should not be retried.
|
||||||
|
type PermanentError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PermanentError) Error() string {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permanent wraps the given err in a *PermanentError.
|
||||||
|
func Permanent(err error) *PermanentError {
|
||||||
|
return &PermanentError{
|
||||||
|
Err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
67
vendor/github.com/cenkalti/backoff/retry_test.go
generated
vendored
67
vendor/github.com/cenkalti/backoff/retry_test.go
generated
vendored
|
@ -2,15 +2,19 @@ package backoff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRetry(t *testing.T) {
|
func TestRetry(t *testing.T) {
|
||||||
const successOn = 3
|
const successOn = 3
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
// This function is successfull on "successOn" calls.
|
// This function is successful on "successOn" calls.
|
||||||
f := func() error {
|
f := func() error {
|
||||||
i++
|
i++
|
||||||
log.Printf("function is called %d. time\n", i)
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
@ -32,3 +36,64 @@ func TestRetry(t *testing.T) {
|
||||||
t.Errorf("invalid number of retries: %d", i)
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRetryContext(t *testing.T) {
|
||||||
|
var cancelOn = 3
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// This function cancels context on "cancelOn" calls.
|
||||||
|
f := func() error {
|
||||||
|
i++
|
||||||
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
|
||||||
|
// cancelling the context in the operation function is not a typical
|
||||||
|
// use-case, however it allows to get predictable test results.
|
||||||
|
if i == cancelOn {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("error")
|
||||||
|
return fmt.Errorf("error (%d)", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Retry(f, WithContext(NewConstantBackOff(time.Millisecond), ctx))
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("error is unexpectedly nil")
|
||||||
|
}
|
||||||
|
if err.Error() != "error (3)" {
|
||||||
|
t.Errorf("unexpected error: %s", err.Error())
|
||||||
|
}
|
||||||
|
if i != cancelOn {
|
||||||
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRetryPermenent(t *testing.T) {
|
||||||
|
const permanentOn = 3
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
// This function fails permanently after permanentOn tries
|
||||||
|
f := func() error {
|
||||||
|
i++
|
||||||
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
|
||||||
|
if i == permanentOn {
|
||||||
|
log.Println("permanent error")
|
||||||
|
return Permanent(errors.New("permanent error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("error")
|
||||||
|
return errors.New("error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Retry(f, NewExponentialBackOff())
|
||||||
|
if err == nil || err.Error() != "permanent error" {
|
||||||
|
t.Errorf("unexpected error: %s", err)
|
||||||
|
}
|
||||||
|
if i != permanentOn {
|
||||||
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
vendor/github.com/cenkalti/backoff/ticker.go
generated
vendored
32
vendor/github.com/cenkalti/backoff/ticker.go
generated
vendored
|
@ -10,36 +10,10 @@ import (
|
||||||
//
|
//
|
||||||
// Ticks will continue to arrive when the previous operation is still running,
|
// Ticks will continue to arrive when the previous operation is still running,
|
||||||
// so operations that take a while to fail could run in quick succession.
|
// so operations that take a while to fail could run in quick succession.
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
// operation := func() error {
|
|
||||||
// // An operation that may fail
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// b := backoff.NewExponentialBackOff()
|
|
||||||
// ticker := backoff.NewTicker(b)
|
|
||||||
//
|
|
||||||
// var err error
|
|
||||||
// for _ = range ticker.C {
|
|
||||||
// if err = operation(); err != nil {
|
|
||||||
// log.Println(err, "will retry...")
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ticker.Stop()
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// // Operation has failed.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Operation is successfull.
|
|
||||||
//
|
|
||||||
type Ticker struct {
|
type Ticker struct {
|
||||||
C <-chan time.Time
|
C <-chan time.Time
|
||||||
c chan time.Time
|
c chan time.Time
|
||||||
b BackOff
|
b BackOffContext
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
stopOnce sync.Once
|
stopOnce sync.Once
|
||||||
}
|
}
|
||||||
|
@ -52,7 +26,7 @@ func NewTicker(b BackOff) *Ticker {
|
||||||
t := &Ticker{
|
t := &Ticker{
|
||||||
C: c,
|
C: c,
|
||||||
c: c,
|
c: c,
|
||||||
b: b,
|
b: ensureContext(b),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
}
|
}
|
||||||
go t.run()
|
go t.run()
|
||||||
|
@ -84,6 +58,8 @@ func (t *Ticker) run() {
|
||||||
case <-t.stop:
|
case <-t.stop:
|
||||||
t.c = nil // Prevent future ticks from being sent to the channel.
|
t.c = nil // Prevent future ticks from being sent to the channel.
|
||||||
return
|
return
|
||||||
|
case <-t.b.Context().Done():
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
51
vendor/github.com/cenkalti/backoff/ticker_test.go
generated
vendored
51
vendor/github.com/cenkalti/backoff/ticker_test.go
generated
vendored
|
@ -2,15 +2,19 @@ package backoff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTicker(t *testing.T) {
|
func TestTicker(t *testing.T) {
|
||||||
const successOn = 3
|
const successOn = 3
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
||||||
// This function is successfull on "successOn" calls.
|
// This function is successful on "successOn" calls.
|
||||||
f := func() error {
|
f := func() error {
|
||||||
i++
|
i++
|
||||||
log.Printf("function is called %d. time\n", i)
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
@ -43,3 +47,48 @@ func TestTicker(t *testing.T) {
|
||||||
t.Errorf("invalid number of retries: %d", i)
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTickerContext(t *testing.T) {
|
||||||
|
const cancelOn = 3
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// This function cancels context on "cancelOn" calls.
|
||||||
|
f := func() error {
|
||||||
|
i++
|
||||||
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
|
||||||
|
// cancelling the context in the operation function is not a typical
|
||||||
|
// use-case, however it allows to get predictable test results.
|
||||||
|
if i == cancelOn {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("error")
|
||||||
|
return fmt.Errorf("error (%d)", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := WithContext(NewConstantBackOff(time.Millisecond), ctx)
|
||||||
|
ticker := NewTicker(b)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _ = range ticker.C {
|
||||||
|
if err = f(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("error is unexpectedly nil")
|
||||||
|
}
|
||||||
|
if err.Error() != "error (3)" {
|
||||||
|
t.Errorf("unexpected error: %s", err.Error())
|
||||||
|
}
|
||||||
|
if i != cancelOn {
|
||||||
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
35
vendor/github.com/cenkalti/backoff/tries.go
generated
vendored
Normal file
35
vendor/github.com/cenkalti/backoff/tries.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
/*
|
||||||
|
WithMaxTries creates a wrapper around another BackOff, which will
|
||||||
|
return Stop if NextBackOff() has been called too many times since
|
||||||
|
the last time Reset() was called
|
||||||
|
|
||||||
|
Note: Implementation is not thread-safe.
|
||||||
|
*/
|
||||||
|
func WithMaxTries(b BackOff, max uint64) BackOff {
|
||||||
|
return &backOffTries{delegate: b, maxTries: max}
|
||||||
|
}
|
||||||
|
|
||||||
|
type backOffTries struct {
|
||||||
|
delegate BackOff
|
||||||
|
maxTries uint64
|
||||||
|
numTries uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backOffTries) NextBackOff() time.Duration {
|
||||||
|
if b.maxTries > 0 {
|
||||||
|
if b.maxTries <= b.numTries {
|
||||||
|
return Stop
|
||||||
|
}
|
||||||
|
b.numTries++
|
||||||
|
}
|
||||||
|
return b.delegate.NextBackOff()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backOffTries) Reset() {
|
||||||
|
b.numTries = 0
|
||||||
|
b.delegate.Reset()
|
||||||
|
}
|
55
vendor/github.com/cenkalti/backoff/tries_test.go
generated
vendored
Normal file
55
vendor/github.com/cenkalti/backoff/tries_test.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMaxTriesHappy(t *testing.T) {
|
||||||
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
max := 17 + r.Intn(13)
|
||||||
|
bo := WithMaxTries(&ZeroBackOff{}, uint64(max))
|
||||||
|
|
||||||
|
// Load up the tries count, but reset should clear the record
|
||||||
|
for ix := 0; ix < max/2; ix++ {
|
||||||
|
bo.NextBackOff()
|
||||||
|
}
|
||||||
|
bo.Reset()
|
||||||
|
|
||||||
|
// Now fill the tries count all the way up
|
||||||
|
for ix := 0; ix < max; ix++ {
|
||||||
|
d := bo.NextBackOff()
|
||||||
|
if d == Stop {
|
||||||
|
t.Errorf("returned Stop on try %d", ix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have now called the BackOff max number of times, we expect
|
||||||
|
// the next result to be Stop, even if we try it multiple times
|
||||||
|
for ix := 0; ix < 7; ix++ {
|
||||||
|
d := bo.NextBackOff()
|
||||||
|
if d != Stop {
|
||||||
|
t.Error("invalid next back off")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset makes it all work again
|
||||||
|
bo.Reset()
|
||||||
|
d := bo.NextBackOff()
|
||||||
|
if d == Stop {
|
||||||
|
t.Error("returned Stop after reset")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMaxTriesZero(t *testing.T) {
|
||||||
|
// It might not make sense, but its okay to send a zero
|
||||||
|
bo := WithMaxTries(&ZeroBackOff{}, uint64(0))
|
||||||
|
for ix := 0; ix < 11; ix++ {
|
||||||
|
d := bo.NextBackOff()
|
||||||
|
if d == Stop {
|
||||||
|
t.Errorf("returned Stop on try %d", ix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
vendor/github.com/robfig/cron/.travis.yml
generated
vendored
1
vendor/github.com/robfig/cron/.travis.yml
generated
vendored
|
@ -1 +0,0 @@
|
||||||
language: go
|
|
10
vendor/github.com/robfig/cron/spec.go
generated
vendored
10
vendor/github.com/robfig/cron/spec.go
generated
vendored
|
@ -1,6 +1,8 @@
|
||||||
package cron
|
package cron
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
|
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
|
||||||
// traditional crontab specification. It is computed initially and stored as bit sets.
|
// traditional crontab specification. It is computed initially and stored as bit sets.
|
||||||
|
@ -108,7 +110,7 @@ WRAP:
|
||||||
for 1<<uint(t.Hour())&s.Hour == 0 {
|
for 1<<uint(t.Hour())&s.Hour == 0 {
|
||||||
if !added {
|
if !added {
|
||||||
added = true
|
added = true
|
||||||
t = t.Truncate(time.Hour)
|
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location())
|
||||||
}
|
}
|
||||||
t = t.Add(1 * time.Hour)
|
t = t.Add(1 * time.Hour)
|
||||||
|
|
||||||
|
@ -120,7 +122,7 @@ WRAP:
|
||||||
for 1<<uint(t.Minute())&s.Minute == 0 {
|
for 1<<uint(t.Minute())&s.Minute == 0 {
|
||||||
if !added {
|
if !added {
|
||||||
added = true
|
added = true
|
||||||
t = t.Truncate(time.Minute)
|
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), 0, 0, t.Location())
|
||||||
}
|
}
|
||||||
t = t.Add(1 * time.Minute)
|
t = t.Add(1 * time.Minute)
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ WRAP:
|
||||||
for 1<<uint(t.Second())&s.Second == 0 {
|
for 1<<uint(t.Second())&s.Second == 0 {
|
||||||
if !added {
|
if !added {
|
||||||
added = true
|
added = true
|
||||||
t = t.Truncate(time.Second)
|
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location())
|
||||||
}
|
}
|
||||||
t = t.Add(1 * time.Second)
|
t = t.Add(1 * time.Second)
|
||||||
|
|
||||||
|
|
35
vendor/github.com/robfig/cron/spec_test.go
generated
vendored
35
vendor/github.com/robfig/cron/spec_test.go
generated
vendored
|
@ -109,44 +109,13 @@ func TestNext(t *testing.T) {
|
||||||
// Leap year
|
// Leap year
|
||||||
{"Mon Jul 9 23:35 2012", "0 0 0 29 Feb ?", "Mon Feb 29 00:00 2016"},
|
{"Mon Jul 9 23:35 2012", "0 0 0 29 Feb ?", "Mon Feb 29 00:00 2016"},
|
||||||
|
|
||||||
// Daylight savings time 2am EST (-5) -> 3am EDT (-4)
|
// Daylight savings time EST -> EDT
|
||||||
{"2012-03-11T00:00:00-0500", "0 30 2 11 Mar ?", "2013-03-11T02:30:00-0400"},
|
{"2012-03-11T00:00:00-0500", "0 30 2 11 Mar ?", "2013-03-11T02:30:00-0400"},
|
||||||
|
|
||||||
// hourly job
|
// Daylight savings time EDT -> EST
|
||||||
{"2012-03-11T00:00:00-0500", "0 0 * * * ?", "2012-03-11T01:00:00-0500"},
|
|
||||||
{"2012-03-11T01:00:00-0500", "0 0 * * * ?", "2012-03-11T03:00:00-0400"},
|
|
||||||
{"2012-03-11T03:00:00-0400", "0 0 * * * ?", "2012-03-11T04:00:00-0400"},
|
|
||||||
{"2012-03-11T04:00:00-0400", "0 0 * * * ?", "2012-03-11T05:00:00-0400"},
|
|
||||||
|
|
||||||
// 1am nightly job
|
|
||||||
{"2012-03-11T00:00:00-0500", "0 0 1 * * ?", "2012-03-11T01:00:00-0500"},
|
|
||||||
{"2012-03-11T01:00:00-0500", "0 0 1 * * ?", "2012-03-12T01:00:00-0400"},
|
|
||||||
|
|
||||||
// 2am nightly job (skipped)
|
|
||||||
{"2012-03-11T00:00:00-0500", "0 0 2 * * ?", "2012-03-12T02:00:00-0400"},
|
|
||||||
|
|
||||||
// Daylight savings time 2am EDT (-4) => 1am EST (-5)
|
|
||||||
{"2012-11-04T00:00:00-0400", "0 30 2 04 Nov ?", "2012-11-04T02:30:00-0500"},
|
{"2012-11-04T00:00:00-0400", "0 30 2 04 Nov ?", "2012-11-04T02:30:00-0500"},
|
||||||
{"2012-11-04T01:45:00-0400", "0 30 1 04 Nov ?", "2012-11-04T01:30:00-0500"},
|
{"2012-11-04T01:45:00-0400", "0 30 1 04 Nov ?", "2012-11-04T01:30:00-0500"},
|
||||||
|
|
||||||
// hourly job
|
|
||||||
{"2012-11-04T00:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0400"},
|
|
||||||
{"2012-11-04T01:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0500"},
|
|
||||||
{"2012-11-04T01:00:00-0500", "0 0 * * * ?", "2012-11-04T02:00:00-0500"},
|
|
||||||
|
|
||||||
// 1am nightly job (runs twice)
|
|
||||||
{"2012-11-04T00:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0400"},
|
|
||||||
{"2012-11-04T01:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0500"},
|
|
||||||
{"2012-11-04T01:00:00-0500", "0 0 1 * * ?", "2012-11-05T01:00:00-0500"},
|
|
||||||
|
|
||||||
// 2am nightly job
|
|
||||||
{"2012-11-04T00:00:00-0400", "0 0 2 * * ?", "2012-11-04T02:00:00-0500"},
|
|
||||||
{"2012-11-04T02:00:00-0500", "0 0 2 * * ?", "2012-11-05T02:00:00-0500"},
|
|
||||||
|
|
||||||
// 3am nightly job
|
|
||||||
{"2012-11-04T00:00:00-0400", "0 0 3 * * ?", "2012-11-04T03:00:00-0500"},
|
|
||||||
{"2012-11-04T03:00:00-0500", "0 0 3 * * ?", "2012-11-05T03:00:00-0500"},
|
|
||||||
|
|
||||||
// Unsatisfiable
|
// Unsatisfiable
|
||||||
{"Mon Jul 9 23:35 2012", "0 0 0 30 Feb ?", ""},
|
{"Mon Jul 9 23:35 2012", "0 0 0 30 Feb ?", ""},
|
||||||
{"Mon Jul 9 23:35 2012", "0 0 0 31 Apr ?", ""},
|
{"Mon Jul 9 23:35 2012", "0 0 0 31 Apr ?", ""},
|
||||||
|
|
2
vendor/github.com/spf13/pflag/.gitignore
generated
vendored
Normal file
2
vendor/github.com/spf13/pflag/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.idea/*
|
||||||
|
|
6
vendor/github.com/spf13/pflag/.travis.yml
generated
vendored
6
vendor/github.com/spf13/pflag/.travis.yml
generated
vendored
|
@ -3,14 +3,14 @@ sudo: false
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.5.4
|
- 1.7.3
|
||||||
- 1.6.3
|
- 1.8.1
|
||||||
- 1.7
|
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- go: tip
|
- go: tip
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go get github.com/golang/lint/golint
|
- go get github.com/golang/lint/golint
|
||||||
- export PATH=$GOPATH/bin:$PATH
|
- export PATH=$GOPATH/bin:$PATH
|
||||||
|
|
31
vendor/github.com/spf13/pflag/README.md
generated
vendored
31
vendor/github.com/spf13/pflag/README.md
generated
vendored
|
@ -1,4 +1,6 @@
|
||||||
[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag)
|
[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag)
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
@ -106,9 +108,9 @@ that give one-letter shorthands for flags. You can use these by appending
|
||||||
var ip = flag.IntP("flagname", "f", 1234, "help message")
|
var ip = flag.IntP("flagname", "f", 1234, "help message")
|
||||||
var flagvar bool
|
var flagvar bool
|
||||||
func init() {
|
func init() {
|
||||||
flag.BoolVarP("boolname", "b", true, "help message")
|
flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
|
||||||
}
|
}
|
||||||
flag.VarP(&flagVar, "varname", "v", 1234, "help message")
|
flag.VarP(&flagVal, "varname", "v", "help message")
|
||||||
```
|
```
|
||||||
|
|
||||||
Shorthand letters can be used with single dashes on the command line.
|
Shorthand letters can be used with single dashes on the command line.
|
||||||
|
@ -244,6 +246,25 @@ It is possible to mark a flag as hidden, meaning it will still function as norma
|
||||||
flags.MarkHidden("secretFlag")
|
flags.MarkHidden("secretFlag")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Disable sorting of flags
|
||||||
|
`pflag` allows you to disable sorting of flags for help and usage message.
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```go
|
||||||
|
flags.BoolP("verbose", "v", false, "verbose output")
|
||||||
|
flags.String("coolflag", "yeaah", "it's really cool flag")
|
||||||
|
flags.Int("usefulflag", 777, "sometimes it's very useful")
|
||||||
|
flags.SortFlags = false
|
||||||
|
flags.PrintDefaults()
|
||||||
|
```
|
||||||
|
**Output**:
|
||||||
|
```
|
||||||
|
-v, --verbose verbose output
|
||||||
|
--coolflag string it's really cool flag (default "yeaah")
|
||||||
|
--usefulflag int sometimes it's very useful (default 777)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Supporting Go flags when using pflag
|
## Supporting Go flags when using pflag
|
||||||
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
|
In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary
|
||||||
to support flags defined by third-party dependencies (e.g. `golang/glog`).
|
to support flags defined by third-party dependencies (e.g. `golang/glog`).
|
||||||
|
@ -268,8 +289,8 @@ func main() {
|
||||||
You can see the full reference documentation of the pflag package
|
You can see the full reference documentation of the pflag package
|
||||||
[at godoc.org][3], or through go's standard documentation system by
|
[at godoc.org][3], or through go's standard documentation system by
|
||||||
running `godoc -http=:6060` and browsing to
|
running `godoc -http=:6060` and browsing to
|
||||||
[http://localhost:6060/pkg/github.com/ogier/pflag][2] after
|
[http://localhost:6060/pkg/github.com/spf13/pflag][2] after
|
||||||
installation.
|
installation.
|
||||||
|
|
||||||
[2]: http://localhost:6060/pkg/github.com/ogier/pflag
|
[2]: http://localhost:6060/pkg/github.com/spf13/pflag
|
||||||
[3]: http://godoc.org/github.com/ogier/pflag
|
[3]: http://godoc.org/github.com/spf13/pflag
|
||||||
|
|
147
vendor/github.com/spf13/pflag/bool_slice.go
generated
vendored
Normal file
147
vendor/github.com/spf13/pflag/bool_slice.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -- boolSlice Value
|
||||||
|
type boolSliceValue struct {
|
||||||
|
value *[]bool
|
||||||
|
changed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue {
|
||||||
|
bsv := new(boolSliceValue)
|
||||||
|
bsv.value = p
|
||||||
|
*bsv.value = val
|
||||||
|
return bsv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag.
|
||||||
|
// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended.
|
||||||
|
func (s *boolSliceValue) Set(val string) error {
|
||||||
|
|
||||||
|
// remove all quote characters
|
||||||
|
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
|
||||||
|
|
||||||
|
// read flag arguments with CSV parser
|
||||||
|
boolStrSlice, err := readAsCSV(rmQuote.Replace(val))
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse boolean values into slice
|
||||||
|
out := make([]bool, 0, len(boolStrSlice))
|
||||||
|
for _, boolStr := range boolStrSlice {
|
||||||
|
b, err := strconv.ParseBool(strings.TrimSpace(boolStr))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out = append(out, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.changed {
|
||||||
|
*s.value = out
|
||||||
|
} else {
|
||||||
|
*s.value = append(*s.value, out...)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.changed = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns a string that uniquely represents this flag's type.
|
||||||
|
func (s *boolSliceValue) Type() string {
|
||||||
|
return "boolSlice"
|
||||||
|
}
|
||||||
|
|
||||||
|
// String defines a "native" format for this boolean slice flag value.
|
||||||
|
func (s *boolSliceValue) String() string {
|
||||||
|
|
||||||
|
boolStrSlice := make([]string, len(*s.value))
|
||||||
|
for i, b := range *s.value {
|
||||||
|
boolStrSlice[i] = strconv.FormatBool(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, _ := writeAsCSV(boolStrSlice)
|
||||||
|
|
||||||
|
return "[" + out + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolSliceConv(val string) (interface{}, error) {
|
||||||
|
val = strings.Trim(val, "[]")
|
||||||
|
// Empty string would cause a slice with one (empty) entry
|
||||||
|
if len(val) == 0 {
|
||||||
|
return []bool{}, nil
|
||||||
|
}
|
||||||
|
ss := strings.Split(val, ",")
|
||||||
|
out := make([]bool, len(ss))
|
||||||
|
for i, t := range ss {
|
||||||
|
var err error
|
||||||
|
out[i], err = strconv.ParseBool(t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBoolSlice returns the []bool value of a flag with the given name.
|
||||||
|
func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) {
|
||||||
|
val, err := f.getFlagType(name, "boolSlice", boolSliceConv)
|
||||||
|
if err != nil {
|
||||||
|
return []bool{}, err
|
||||||
|
}
|
||||||
|
return val.([]bool), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a []bool variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
|
||||||
|
f.VarP(newBoolSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
|
||||||
|
f.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSliceVar defines a []bool flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a []bool variable in which to store the value of the flag.
|
||||||
|
func BoolSliceVar(p *[]bool, name string, value []bool, usage string) {
|
||||||
|
CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) {
|
||||||
|
CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []bool variable that stores the value of the flag.
|
||||||
|
func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool {
|
||||||
|
p := []bool{}
|
||||||
|
f.BoolSliceVarP(&p, name, "", value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
|
||||||
|
p := []bool{}
|
||||||
|
f.BoolSliceVarP(&p, name, shorthand, value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice defines a []bool flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []bool variable that stores the value of the flag.
|
||||||
|
func BoolSlice(name string, value []bool, usage string) *[]bool {
|
||||||
|
return CommandLine.BoolSliceP(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool {
|
||||||
|
return CommandLine.BoolSliceP(name, shorthand, value, usage)
|
||||||
|
}
|
215
vendor/github.com/spf13/pflag/bool_slice_test.go
generated
vendored
Normal file
215
vendor/github.com/spf13/pflag/bool_slice_test.go
generated
vendored
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpBSFlagSet(bsp *[]bool) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.BoolSliceVar(bsp, "bs", []bool{}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpBSFlagSetWithDefault(bsp *[]bool) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.BoolSliceVar(bsp, "bs", []bool{false, true}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyBS(t *testing.T) {
|
||||||
|
var bs []bool
|
||||||
|
f := setUpBSFlagSet(&bs)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getBS, err := f.GetBoolSlice("bs")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetBoolSlice():", err)
|
||||||
|
}
|
||||||
|
if len(getBS) != 0 {
|
||||||
|
t.Fatalf("got bs %v with len=%d but expected length=0", getBS, len(getBS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBS(t *testing.T) {
|
||||||
|
var bs []bool
|
||||||
|
f := setUpBSFlagSet(&bs)
|
||||||
|
|
||||||
|
vals := []string{"1", "F", "TRUE", "0"}
|
||||||
|
arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range bs {
|
||||||
|
b, err := strconv.ParseBool(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if b != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %s but got: %t", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getBS, err := f.GetBoolSlice("bs")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
for i, v := range getBS {
|
||||||
|
b, err := strconv.ParseBool(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if b != v {
|
||||||
|
t.Fatalf("expected bs[%d] to be %s but got: %t from GetBoolSlice", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBSDefault(t *testing.T) {
|
||||||
|
var bs []bool
|
||||||
|
f := setUpBSFlagSetWithDefault(&bs)
|
||||||
|
|
||||||
|
vals := []string{"false", "T"}
|
||||||
|
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range bs {
|
||||||
|
b, err := strconv.ParseBool(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if b != v {
|
||||||
|
t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBS, err := f.GetBoolSlice("bs")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetBoolSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getBS {
|
||||||
|
b, err := strconv.ParseBool(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetBoolSlice():", err)
|
||||||
|
}
|
||||||
|
if b != v {
|
||||||
|
t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBSWithDefault(t *testing.T) {
|
||||||
|
var bs []bool
|
||||||
|
f := setUpBSFlagSetWithDefault(&bs)
|
||||||
|
|
||||||
|
vals := []string{"FALSE", "1"}
|
||||||
|
arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range bs {
|
||||||
|
b, err := strconv.ParseBool(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if b != v {
|
||||||
|
t.Fatalf("expected bs[%d] to be %t but got: %t", i, b, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBS, err := f.GetBoolSlice("bs")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetBoolSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getBS {
|
||||||
|
b, err := strconv.ParseBool(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if b != v {
|
||||||
|
t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBSCalledTwice(t *testing.T) {
|
||||||
|
var bs []bool
|
||||||
|
f := setUpBSFlagSet(&bs)
|
||||||
|
|
||||||
|
in := []string{"T,F", "T"}
|
||||||
|
expected := []bool{true, false, true}
|
||||||
|
argfmt := "--bs=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range bs {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected bs[%d] to be %t but got %t", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBSBadQuoting(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
Want []bool
|
||||||
|
FlagArg []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Want: []bool{true, false, true},
|
||||||
|
FlagArg: []string{"1", "0", "true"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []bool{true, false},
|
||||||
|
FlagArg: []string{"True", "F"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []bool{true, false},
|
||||||
|
FlagArg: []string{"T", "0"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []bool{true, false},
|
||||||
|
FlagArg: []string{"1", "0"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []bool{true, false, false},
|
||||||
|
FlagArg: []string{"true,false", "false"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []bool{true, false, false, true, false, true, false},
|
||||||
|
FlagArg: []string{`"true,false,false,1,0, T"`, " false "},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []bool{false, false, true, false, true, false, true},
|
||||||
|
FlagArg: []string{`"0, False, T,false , true,F"`, "true"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
|
||||||
|
var bs []bool
|
||||||
|
f := setUpBSFlagSet(&bs)
|
||||||
|
|
||||||
|
if err := f.Parse([]string{fmt.Sprintf("--bs=%s", strings.Join(test.FlagArg, ","))}); err != nil {
|
||||||
|
t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%#v",
|
||||||
|
err, test.FlagArg, test.Want[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
for j, b := range bs {
|
||||||
|
if b != test.Want[j] {
|
||||||
|
t.Fatalf("bad value parsed for test %d on bool %d:\nwant:\t%t\ngot:\t%t", i, j, test.Want[j], b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
vendor/github.com/spf13/pflag/bool_test.go
generated
vendored
3
vendor/github.com/spf13/pflag/bool_test.go
generated
vendored
|
@ -6,7 +6,6 @@ package pflag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -48,7 +47,7 @@ func (v *triStateValue) String() string {
|
||||||
if *v == triStateMaybe {
|
if *v == triStateMaybe {
|
||||||
return strTriStateMaybe
|
return strTriStateMaybe
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%v", bool(*v == triStateTrue))
|
return strconv.FormatBool(*v == triStateTrue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The type of the flag as required by the pflag.Value interface
|
// The type of the flag as required by the pflag.Value interface
|
||||||
|
|
4
vendor/github.com/spf13/pflag/count.go
generated
vendored
4
vendor/github.com/spf13/pflag/count.go
generated
vendored
|
@ -83,7 +83,9 @@ func (f *FlagSet) CountP(name, shorthand string, usage string) *int {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count like Count only the flag is placed on the CommandLine isntead of a given flag set
|
// Count defines a count flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of an int variable that stores the value of the flag.
|
||||||
|
// A count flag will add 1 to its value evey time it is found on the command line
|
||||||
func Count(name string, usage string) *int {
|
func Count(name string, usage string) *int {
|
||||||
return CommandLine.CountP(name, "", usage)
|
return CommandLine.CountP(name, "", usage)
|
||||||
}
|
}
|
||||||
|
|
3
vendor/github.com/spf13/pflag/count_test.go
generated
vendored
3
vendor/github.com/spf13/pflag/count_test.go
generated
vendored
|
@ -1,13 +1,10 @@
|
||||||
package pflag
|
package pflag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Printf
|
|
||||||
|
|
||||||
func setUpCount(c *int) *FlagSet {
|
func setUpCount(c *int) *FlagSet {
|
||||||
f := NewFlagSet("test", ContinueOnError)
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
f.CountVarP(c, "verbose", "v", "a counter")
|
f.CountVarP(c, "verbose", "v", "a counter")
|
||||||
|
|
79
vendor/github.com/spf13/pflag/example_test.go
generated
vendored
79
vendor/github.com/spf13/pflag/example_test.go
generated
vendored
|
@ -2,76 +2,35 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// These examples demonstrate more intricate uses of the flag package.
|
|
||||||
package pflag_test
|
package pflag_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
flag "github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Example 1: A single string flag called "species" with default value "gopher".
|
func ExampleShorthandLookup() {
|
||||||
var species = flag.String("species", "gopher", "the species we are studying")
|
name := "verbose"
|
||||||
|
short := name[:1]
|
||||||
|
|
||||||
// Example 2: A flag with a shorthand letter.
|
pflag.BoolP(name, short, false, "verbose output")
|
||||||
var gopherType = flag.StringP("gopher_type", "g", "pocket", "the variety of gopher")
|
|
||||||
|
|
||||||
// Example 3: A user-defined flag type, a slice of durations.
|
// len(short) must be == 1
|
||||||
type interval []time.Duration
|
flag := pflag.ShorthandLookup(short)
|
||||||
|
|
||||||
// String is the method to format the flag's value, part of the flag.Value interface.
|
fmt.Println(flag.Name)
|
||||||
// The String method's output will be used in diagnostics.
|
|
||||||
func (i *interval) String() string {
|
|
||||||
return fmt.Sprint(*i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interval) Type() string {
|
func ExampleFlagSet_ShorthandLookup() {
|
||||||
return "interval"
|
name := "verbose"
|
||||||
}
|
short := name[:1]
|
||||||
|
|
||||||
// Set is the method to set the flag value, part of the flag.Value interface.
|
fs := pflag.NewFlagSet("Example", pflag.ContinueOnError)
|
||||||
// Set's argument is a string to be parsed to set the flag.
|
fs.BoolP(name, short, false, "verbose output")
|
||||||
// It's a comma-separated list, so we split it.
|
|
||||||
func (i *interval) Set(value string) error {
|
// len(short) must be == 1
|
||||||
// If we wanted to allow the flag to be set multiple times,
|
flag := fs.ShorthandLookup(short)
|
||||||
// accumulating values, we would delete this if statement.
|
|
||||||
// That would permit usages such as
|
fmt.Println(flag.Name)
|
||||||
// -deltaT 10s -deltaT 15s
|
|
||||||
// and other combinations.
|
|
||||||
if len(*i) > 0 {
|
|
||||||
return errors.New("interval flag already set")
|
|
||||||
}
|
|
||||||
for _, dt := range strings.Split(value, ",") {
|
|
||||||
duration, err := time.ParseDuration(dt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*i = append(*i, duration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define a flag to accumulate durations. Because it has a special type,
|
|
||||||
// we need to use the Var function and therefore create the flag during
|
|
||||||
// init.
|
|
||||||
|
|
||||||
var intervalFlag interval
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Tie the command-line flag to the intervalFlag variable and
|
|
||||||
// set a usage message.
|
|
||||||
flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example() {
|
|
||||||
// All the interesting pieces are with the variables declared above, but
|
|
||||||
// to enable the flag package to see the flags defined there, one must
|
|
||||||
// execute, typically at the start of main (not init!):
|
|
||||||
// flag.Parse()
|
|
||||||
// We don't run it here because this is not a main function and
|
|
||||||
// the testing suite has already parsed the flags.
|
|
||||||
}
|
}
|
||||||
|
|
365
vendor/github.com/spf13/pflag/flag.go
generated
vendored
365
vendor/github.com/spf13/pflag/flag.go
generated
vendored
|
@ -16,9 +16,9 @@ pflag is a drop-in replacement of Go's native flag package. If you import
|
||||||
pflag under the name "flag" then all code should continue to function
|
pflag under the name "flag" then all code should continue to function
|
||||||
with no changes.
|
with no changes.
|
||||||
|
|
||||||
import flag "github.com/ogier/pflag"
|
import flag "github.com/spf13/pflag"
|
||||||
|
|
||||||
There is one exception to this: if you directly instantiate the Flag struct
|
There is one exception to this: if you directly instantiate the Flag struct
|
||||||
there is one more field "Shorthand" that you will need to set.
|
there is one more field "Shorthand" that you will need to set.
|
||||||
Most code never instantiates this struct directly, and instead uses
|
Most code never instantiates this struct directly, and instead uses
|
||||||
functions such as String(), BoolVar(), and Var(), and is therefore
|
functions such as String(), BoolVar(), and Var(), and is therefore
|
||||||
|
@ -134,14 +134,21 @@ type FlagSet struct {
|
||||||
// a custom error handler.
|
// a custom error handler.
|
||||||
Usage func()
|
Usage func()
|
||||||
|
|
||||||
|
// SortFlags is used to indicate, if user wants to have sorted flags in
|
||||||
|
// help/usage messages.
|
||||||
|
SortFlags bool
|
||||||
|
|
||||||
name string
|
name string
|
||||||
parsed bool
|
parsed bool
|
||||||
actual map[NormalizedName]*Flag
|
actual map[NormalizedName]*Flag
|
||||||
|
orderedActual []*Flag
|
||||||
|
sortedActual []*Flag
|
||||||
formal map[NormalizedName]*Flag
|
formal map[NormalizedName]*Flag
|
||||||
|
orderedFormal []*Flag
|
||||||
|
sortedFormal []*Flag
|
||||||
shorthands map[byte]*Flag
|
shorthands map[byte]*Flag
|
||||||
args []string // arguments after flags
|
args []string // arguments after flags
|
||||||
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
|
argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no --
|
||||||
exitOnError bool // does the program exit if there's an error?
|
|
||||||
errorHandling ErrorHandling
|
errorHandling ErrorHandling
|
||||||
output io.Writer // nil means stderr; use out() accessor
|
output io.Writer // nil means stderr; use out() accessor
|
||||||
interspersed bool // allow interspersed option/non-option args
|
interspersed bool // allow interspersed option/non-option args
|
||||||
|
@ -156,7 +163,7 @@ type Flag struct {
|
||||||
Value Value // value as set
|
Value Value // value as set
|
||||||
DefValue string // default value (as text); for usage message
|
DefValue string // default value (as text); for usage message
|
||||||
Changed bool // If the user set the value (or if left to default)
|
Changed bool // If the user set the value (or if left to default)
|
||||||
NoOptDefVal string //default value (as text); if the flag is on the command line without any options
|
NoOptDefVal string // default value (as text); if the flag is on the command line without any options
|
||||||
Deprecated string // If this flag is deprecated, this string is the new or now thing to use
|
Deprecated string // If this flag is deprecated, this string is the new or now thing to use
|
||||||
Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
|
Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text
|
||||||
ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
|
ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use
|
||||||
|
@ -194,11 +201,13 @@ func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
|
||||||
// "--getUrl" which may also be translated to "geturl" and everything will work.
|
// "--getUrl" which may also be translated to "geturl" and everything will work.
|
||||||
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
|
func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) {
|
||||||
f.normalizeNameFunc = n
|
f.normalizeNameFunc = n
|
||||||
for k, v := range f.formal {
|
f.sortedFormal = f.sortedFormal[:0]
|
||||||
delete(f.formal, k)
|
for k, v := range f.orderedFormal {
|
||||||
nname := f.normalizeFlagName(string(k))
|
delete(f.formal, NormalizedName(v.Name))
|
||||||
f.formal[nname] = v
|
nname := f.normalizeFlagName(v.Name)
|
||||||
v.Name = string(nname)
|
v.Name = string(nname)
|
||||||
|
f.formal[nname] = v
|
||||||
|
f.orderedFormal[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,10 +238,25 @@ func (f *FlagSet) SetOutput(output io.Writer) {
|
||||||
f.output = output
|
f.output = output
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisitAll visits the flags in lexicographical order, calling fn for each.
|
// VisitAll visits the flags in lexicographical order or
|
||||||
|
// in primordial order if f.SortFlags is false, calling fn for each.
|
||||||
// It visits all flags, even those not set.
|
// It visits all flags, even those not set.
|
||||||
func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
func (f *FlagSet) VisitAll(fn func(*Flag)) {
|
||||||
for _, flag := range sortFlags(f.formal) {
|
if len(f.formal) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags []*Flag
|
||||||
|
if f.SortFlags {
|
||||||
|
if len(f.formal) != len(f.sortedFormal) {
|
||||||
|
f.sortedFormal = sortFlags(f.formal)
|
||||||
|
}
|
||||||
|
flags = f.sortedFormal
|
||||||
|
} else {
|
||||||
|
flags = f.orderedFormal
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, flag := range flags {
|
||||||
fn(flag)
|
fn(flag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,22 +277,39 @@ func (f *FlagSet) HasAvailableFlags() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisitAll visits the command-line flags in lexicographical order, calling
|
// VisitAll visits the command-line flags in lexicographical order or
|
||||||
// fn for each. It visits all flags, even those not set.
|
// in primordial order if f.SortFlags is false, calling fn for each.
|
||||||
|
// It visits all flags, even those not set.
|
||||||
func VisitAll(fn func(*Flag)) {
|
func VisitAll(fn func(*Flag)) {
|
||||||
CommandLine.VisitAll(fn)
|
CommandLine.VisitAll(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit visits the flags in lexicographical order, calling fn for each.
|
// Visit visits the flags in lexicographical order or
|
||||||
|
// in primordial order if f.SortFlags is false, calling fn for each.
|
||||||
// It visits only those flags that have been set.
|
// It visits only those flags that have been set.
|
||||||
func (f *FlagSet) Visit(fn func(*Flag)) {
|
func (f *FlagSet) Visit(fn func(*Flag)) {
|
||||||
for _, flag := range sortFlags(f.actual) {
|
if len(f.actual) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags []*Flag
|
||||||
|
if f.SortFlags {
|
||||||
|
if len(f.actual) != len(f.sortedActual) {
|
||||||
|
f.sortedActual = sortFlags(f.actual)
|
||||||
|
}
|
||||||
|
flags = f.sortedActual
|
||||||
|
} else {
|
||||||
|
flags = f.orderedActual
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, flag := range flags {
|
||||||
fn(flag)
|
fn(flag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit visits the command-line flags in lexicographical order, calling fn
|
// Visit visits the command-line flags in lexicographical order or
|
||||||
// for each. It visits only those flags that have been set.
|
// in primordial order if f.SortFlags is false, calling fn for each.
|
||||||
|
// It visits only those flags that have been set.
|
||||||
func Visit(fn func(*Flag)) {
|
func Visit(fn func(*Flag)) {
|
||||||
CommandLine.Visit(fn)
|
CommandLine.Visit(fn)
|
||||||
}
|
}
|
||||||
|
@ -278,6 +319,22 @@ func (f *FlagSet) Lookup(name string) *Flag {
|
||||||
return f.lookup(f.normalizeFlagName(name))
|
return f.lookup(f.normalizeFlagName(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShorthandLookup returns the Flag structure of the short handed flag,
|
||||||
|
// returning nil if none exists.
|
||||||
|
// It panics, if len(name) > 1.
|
||||||
|
func (f *FlagSet) ShorthandLookup(name string) *Flag {
|
||||||
|
if name == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(name) > 1 {
|
||||||
|
msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name)
|
||||||
|
fmt.Fprintf(f.out(), msg)
|
||||||
|
panic(msg)
|
||||||
|
}
|
||||||
|
c := name[0]
|
||||||
|
return f.shorthands[c]
|
||||||
|
}
|
||||||
|
|
||||||
// lookup returns the Flag structure of the named flag, returning nil if none exists.
|
// lookup returns the Flag structure of the named flag, returning nil if none exists.
|
||||||
func (f *FlagSet) lookup(name NormalizedName) *Flag {
|
func (f *FlagSet) lookup(name NormalizedName) *Flag {
|
||||||
return f.formal[name]
|
return f.formal[name]
|
||||||
|
@ -319,7 +376,7 @@ func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error {
|
||||||
if flag == nil {
|
if flag == nil {
|
||||||
return fmt.Errorf("flag %q does not exist", name)
|
return fmt.Errorf("flag %q does not exist", name)
|
||||||
}
|
}
|
||||||
if len(usageMessage) == 0 {
|
if usageMessage == "" {
|
||||||
return fmt.Errorf("deprecated message for flag %q must be set", name)
|
return fmt.Errorf("deprecated message for flag %q must be set", name)
|
||||||
}
|
}
|
||||||
flag.Deprecated = usageMessage
|
flag.Deprecated = usageMessage
|
||||||
|
@ -334,7 +391,7 @@ func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) erro
|
||||||
if flag == nil {
|
if flag == nil {
|
||||||
return fmt.Errorf("flag %q does not exist", name)
|
return fmt.Errorf("flag %q does not exist", name)
|
||||||
}
|
}
|
||||||
if len(usageMessage) == 0 {
|
if usageMessage == "" {
|
||||||
return fmt.Errorf("deprecated message for flag %q must be set", name)
|
return fmt.Errorf("deprecated message for flag %q must be set", name)
|
||||||
}
|
}
|
||||||
flag.ShorthandDeprecated = usageMessage
|
flag.ShorthandDeprecated = usageMessage
|
||||||
|
@ -358,6 +415,12 @@ func Lookup(name string) *Flag {
|
||||||
return CommandLine.Lookup(name)
|
return CommandLine.Lookup(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ShorthandLookup returns the Flag structure of the short handed flag,
|
||||||
|
// returning nil if none exists.
|
||||||
|
func ShorthandLookup(name string) *Flag {
|
||||||
|
return CommandLine.ShorthandLookup(name)
|
||||||
|
}
|
||||||
|
|
||||||
// Set sets the value of the named flag.
|
// Set sets the value of the named flag.
|
||||||
func (f *FlagSet) Set(name, value string) error {
|
func (f *FlagSet) Set(name, value string) error {
|
||||||
normalName := f.normalizeFlagName(name)
|
normalName := f.normalizeFlagName(name)
|
||||||
|
@ -365,17 +428,28 @@ func (f *FlagSet) Set(name, value string) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("no such flag -%v", name)
|
return fmt.Errorf("no such flag -%v", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := flag.Value.Set(value)
|
err := flag.Value.Set(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
var flagName string
|
||||||
|
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
|
||||||
|
flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name)
|
||||||
|
} else {
|
||||||
|
flagName = fmt.Sprintf("--%s", flag.Name)
|
||||||
}
|
}
|
||||||
|
return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err)
|
||||||
|
}
|
||||||
|
|
||||||
if f.actual == nil {
|
if f.actual == nil {
|
||||||
f.actual = make(map[NormalizedName]*Flag)
|
f.actual = make(map[NormalizedName]*Flag)
|
||||||
}
|
}
|
||||||
f.actual[normalName] = flag
|
f.actual[normalName] = flag
|
||||||
|
f.orderedActual = append(f.orderedActual, flag)
|
||||||
|
|
||||||
flag.Changed = true
|
flag.Changed = true
|
||||||
if len(flag.Deprecated) > 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
|
if flag.Deprecated != "" {
|
||||||
|
fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -416,7 +490,7 @@ func Set(name, value string) error {
|
||||||
// otherwise, the default values of all defined flags in the set.
|
// otherwise, the default values of all defined flags in the set.
|
||||||
func (f *FlagSet) PrintDefaults() {
|
func (f *FlagSet) PrintDefaults() {
|
||||||
usages := f.FlagUsages()
|
usages := f.FlagUsages()
|
||||||
fmt.Fprintf(f.out(), "%s", usages)
|
fmt.Fprint(f.out(), usages)
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultIsZeroValue returns true if the default value for this flag represents
|
// defaultIsZeroValue returns true if the default value for this flag represents
|
||||||
|
@ -487,34 +561,101 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlagUsages Returns a string containing the usage information for all flags in
|
// Splits the string `s` on whitespace into an initial substring up to
|
||||||
// the FlagSet
|
// `i` runes in length and the remainder. Will go `slop` over `i` if
|
||||||
func (f *FlagSet) FlagUsages() string {
|
// that encompasses the entire string (which allows the caller to
|
||||||
x := new(bytes.Buffer)
|
// avoid short orphan words on the final line).
|
||||||
|
func wrapN(i, slop int, s string) (string, string) {
|
||||||
|
if i+slop > len(s) {
|
||||||
|
return s, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
w := strings.LastIndexAny(s[:i], " \t")
|
||||||
|
if w <= 0 {
|
||||||
|
return s, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[:w], s[w+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wraps the string `s` to a maximum width `w` with leading indent
|
||||||
|
// `i`. The first line is not indented (this is assumed to be done by
|
||||||
|
// caller). Pass `w` == 0 to do no wrapping
|
||||||
|
func wrap(i, w int, s string) string {
|
||||||
|
if w == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// space between indent i and end of line width w into which
|
||||||
|
// we should wrap the text.
|
||||||
|
wrap := w - i
|
||||||
|
|
||||||
|
var r, l string
|
||||||
|
|
||||||
|
// Not enough space for sensible wrapping. Wrap as a block on
|
||||||
|
// the next line instead.
|
||||||
|
if wrap < 24 {
|
||||||
|
i = 16
|
||||||
|
wrap = w - i
|
||||||
|
r += "\n" + strings.Repeat(" ", i)
|
||||||
|
}
|
||||||
|
// If still not enough space then don't even try to wrap.
|
||||||
|
if wrap < 24 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to avoid short orphan words on the final line, by
|
||||||
|
// allowing wrapN to go a bit over if that would fit in the
|
||||||
|
// remainder of the line.
|
||||||
|
slop := 5
|
||||||
|
wrap = wrap - slop
|
||||||
|
|
||||||
|
// Handle first line, which is indented by the caller (or the
|
||||||
|
// special case above)
|
||||||
|
l, s = wrapN(wrap, slop, s)
|
||||||
|
r = r + l
|
||||||
|
|
||||||
|
// Now wrap the rest
|
||||||
|
for s != "" {
|
||||||
|
var t string
|
||||||
|
|
||||||
|
t, s = wrapN(wrap, slop, s)
|
||||||
|
r = r + "\n" + strings.Repeat(" ", i) + t
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlagUsagesWrapped returns a string containing the usage information
|
||||||
|
// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no
|
||||||
|
// wrapping)
|
||||||
|
func (f *FlagSet) FlagUsagesWrapped(cols int) string {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
lines := make([]string, 0, len(f.formal))
|
lines := make([]string, 0, len(f.formal))
|
||||||
|
|
||||||
maxlen := 0
|
maxlen := 0
|
||||||
f.VisitAll(func(flag *Flag) {
|
f.VisitAll(func(flag *Flag) {
|
||||||
if len(flag.Deprecated) > 0 || flag.Hidden {
|
if flag.Deprecated != "" || flag.Hidden {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
line := ""
|
line := ""
|
||||||
if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 {
|
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
|
||||||
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
|
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
|
||||||
} else {
|
} else {
|
||||||
line = fmt.Sprintf(" --%s", flag.Name)
|
line = fmt.Sprintf(" --%s", flag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
varname, usage := UnquoteUsage(flag)
|
varname, usage := UnquoteUsage(flag)
|
||||||
if len(varname) > 0 {
|
if varname != "" {
|
||||||
line += " " + varname
|
line += " " + varname
|
||||||
}
|
}
|
||||||
if len(flag.NoOptDefVal) > 0 {
|
if flag.NoOptDefVal != "" {
|
||||||
switch flag.Value.Type() {
|
switch flag.Value.Type() {
|
||||||
case "string":
|
case "string":
|
||||||
line += fmt.Sprintf("[=%q]", flag.NoOptDefVal)
|
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
|
||||||
case "bool":
|
case "bool":
|
||||||
if flag.NoOptDefVal != "true" {
|
if flag.NoOptDefVal != "true" {
|
||||||
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
|
@ -546,10 +687,17 @@ func (f *FlagSet) FlagUsages() string {
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
sidx := strings.Index(line, "\x00")
|
sidx := strings.Index(line, "\x00")
|
||||||
spacing := strings.Repeat(" ", maxlen-sidx)
|
spacing := strings.Repeat(" ", maxlen-sidx)
|
||||||
fmt.Fprintln(x, line[:sidx], spacing, line[sidx+1:])
|
// maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx
|
||||||
|
fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return x.String()
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlagUsages returns a string containing the usage information for all flags in
|
||||||
|
// the FlagSet
|
||||||
|
func (f *FlagSet) FlagUsages() string {
|
||||||
|
return f.FlagUsagesWrapped(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintDefaults prints to standard error the default values of all defined command-line flags.
|
// PrintDefaults prints to standard error the default values of all defined command-line flags.
|
||||||
|
@ -635,16 +783,15 @@ func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag {
|
||||||
|
|
||||||
// VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
|
// VarP is like Var, but accepts a shorthand letter that can be used after a single dash.
|
||||||
func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
|
func (f *FlagSet) VarP(value Value, name, shorthand, usage string) {
|
||||||
_ = f.VarPF(value, name, shorthand, usage)
|
f.VarPF(value, name, shorthand, usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFlag will add the flag to the FlagSet
|
// AddFlag will add the flag to the FlagSet
|
||||||
func (f *FlagSet) AddFlag(flag *Flag) {
|
func (f *FlagSet) AddFlag(flag *Flag) {
|
||||||
// Call normalizeFlagName function only once
|
|
||||||
normalizedFlagName := f.normalizeFlagName(flag.Name)
|
normalizedFlagName := f.normalizeFlagName(flag.Name)
|
||||||
|
|
||||||
_, alreadythere := f.formal[normalizedFlagName]
|
_, alreadyThere := f.formal[normalizedFlagName]
|
||||||
if alreadythere {
|
if alreadyThere {
|
||||||
msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
|
msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name)
|
||||||
fmt.Fprintln(f.out(), msg)
|
fmt.Fprintln(f.out(), msg)
|
||||||
panic(msg) // Happens only if flags are declared with identical names
|
panic(msg) // Happens only if flags are declared with identical names
|
||||||
|
@ -655,28 +802,31 @@ func (f *FlagSet) AddFlag(flag *Flag) {
|
||||||
|
|
||||||
flag.Name = string(normalizedFlagName)
|
flag.Name = string(normalizedFlagName)
|
||||||
f.formal[normalizedFlagName] = flag
|
f.formal[normalizedFlagName] = flag
|
||||||
|
f.orderedFormal = append(f.orderedFormal, flag)
|
||||||
|
|
||||||
if len(flag.Shorthand) == 0 {
|
if flag.Shorthand == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(flag.Shorthand) > 1 {
|
if len(flag.Shorthand) > 1 {
|
||||||
fmt.Fprintf(f.out(), "%s shorthand more than ASCII character: %s\n", f.name, flag.Shorthand)
|
msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand)
|
||||||
panic("shorthand is more than one character")
|
fmt.Fprintf(f.out(), msg)
|
||||||
|
panic(msg)
|
||||||
}
|
}
|
||||||
if f.shorthands == nil {
|
if f.shorthands == nil {
|
||||||
f.shorthands = make(map[byte]*Flag)
|
f.shorthands = make(map[byte]*Flag)
|
||||||
}
|
}
|
||||||
c := flag.Shorthand[0]
|
c := flag.Shorthand[0]
|
||||||
old, alreadythere := f.shorthands[c]
|
used, alreadyThere := f.shorthands[c]
|
||||||
if alreadythere {
|
if alreadyThere {
|
||||||
fmt.Fprintf(f.out(), "%s shorthand reused: %q for %s already used for %s\n", f.name, c, flag.Name, old.Name)
|
msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name)
|
||||||
panic("shorthand redefinition")
|
fmt.Fprintf(f.out(), msg)
|
||||||
|
panic(msg)
|
||||||
}
|
}
|
||||||
f.shorthands[c] = flag
|
f.shorthands[c] = flag
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFlagSet adds one FlagSet to another. If a flag is already present in f
|
// AddFlagSet adds one FlagSet to another. If a flag is already present in f
|
||||||
// the flag from newSet will be ignored
|
// the flag from newSet will be ignored.
|
||||||
func (f *FlagSet) AddFlagSet(newSet *FlagSet) {
|
func (f *FlagSet) AddFlagSet(newSet *FlagSet) {
|
||||||
if newSet == nil {
|
if newSet == nil {
|
||||||
return
|
return
|
||||||
|
@ -724,45 +874,18 @@ func (f *FlagSet) usage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlagSet) setFlag(flag *Flag, value string, origArg string) error {
|
func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) {
|
||||||
if err := flag.Value.Set(value); err != nil {
|
|
||||||
return f.failf("invalid argument %q for %s: %v", value, origArg, err)
|
|
||||||
}
|
|
||||||
// mark as visited for Visit()
|
|
||||||
if f.actual == nil {
|
|
||||||
f.actual = make(map[NormalizedName]*Flag)
|
|
||||||
}
|
|
||||||
f.actual[f.normalizeFlagName(flag.Name)] = flag
|
|
||||||
flag.Changed = true
|
|
||||||
if len(flag.Deprecated) > 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated)
|
|
||||||
}
|
|
||||||
if len(flag.ShorthandDeprecated) > 0 && containsShorthand(origArg, flag.Shorthand) {
|
|
||||||
fmt.Fprintf(os.Stderr, "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsShorthand(arg, shorthand string) bool {
|
|
||||||
// filter out flags --<flag_name>
|
|
||||||
if strings.HasPrefix(arg, "-") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
arg = strings.SplitN(arg, "=", 2)[0]
|
|
||||||
return strings.Contains(arg, shorthand)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error) {
|
|
||||||
a = args
|
a = args
|
||||||
name := s[2:]
|
name := s[2:]
|
||||||
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
|
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
|
||||||
err = f.failf("bad flag syntax: %s", s)
|
err = f.failf("bad flag syntax: %s", s)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
split := strings.SplitN(name, "=", 2)
|
split := strings.SplitN(name, "=", 2)
|
||||||
name = split[0]
|
name = split[0]
|
||||||
flag, alreadythere := f.formal[f.normalizeFlagName(name)]
|
flag, exists := f.formal[f.normalizeFlagName(name)]
|
||||||
if !alreadythere {
|
if !exists {
|
||||||
if name == "help" { // special case for nice help message.
|
if name == "help" { // special case for nice help message.
|
||||||
f.usage()
|
f.usage()
|
||||||
return a, ErrHelp
|
return a, ErrHelp
|
||||||
|
@ -770,11 +893,12 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
|
||||||
err = f.failf("unknown flag: --%s", name)
|
err = f.failf("unknown flag: --%s", name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var value string
|
var value string
|
||||||
if len(split) == 2 {
|
if len(split) == 2 {
|
||||||
// '--flag=arg'
|
// '--flag=arg'
|
||||||
value = split[1]
|
value = split[1]
|
||||||
} else if len(flag.NoOptDefVal) > 0 {
|
} else if flag.NoOptDefVal != "" {
|
||||||
// '--flag' (arg was optional)
|
// '--flag' (arg was optional)
|
||||||
value = flag.NoOptDefVal
|
value = flag.NoOptDefVal
|
||||||
} else if len(a) > 0 {
|
} else if len(a) > 0 {
|
||||||
|
@ -786,55 +910,68 @@ func (f *FlagSet) parseLongArg(s string, args []string) (a []string, err error)
|
||||||
err = f.failf("flag needs an argument: %s", s)
|
err = f.failf("flag needs an argument: %s", s)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = f.setFlag(flag, value, s)
|
|
||||||
|
err = fn(flag, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string) (outShorts string, outArgs []string, err error) {
|
func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) {
|
||||||
if strings.HasPrefix(shorthands, "test.") {
|
if strings.HasPrefix(shorthands, "test.") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
outArgs = args
|
outArgs = args
|
||||||
outShorts = shorthands[1:]
|
outShorts = shorthands[1:]
|
||||||
c := shorthands[0]
|
c := shorthands[0]
|
||||||
|
|
||||||
flag, alreadythere := f.shorthands[c]
|
flag, exists := f.shorthands[c]
|
||||||
if !alreadythere {
|
if !exists {
|
||||||
if c == 'h' { // special case for nice help message.
|
if c == 'h' { // special case for nice help message.
|
||||||
f.usage()
|
f.usage()
|
||||||
err = ErrHelp
|
err = ErrHelp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//TODO continue on error
|
|
||||||
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
|
err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var value string
|
var value string
|
||||||
if len(shorthands) > 2 && shorthands[1] == '=' {
|
if len(shorthands) > 2 && shorthands[1] == '=' {
|
||||||
|
// '-f=arg'
|
||||||
value = shorthands[2:]
|
value = shorthands[2:]
|
||||||
outShorts = ""
|
outShorts = ""
|
||||||
} else if len(flag.NoOptDefVal) > 0 {
|
} else if flag.NoOptDefVal != "" {
|
||||||
|
// '-f' (arg was optional)
|
||||||
value = flag.NoOptDefVal
|
value = flag.NoOptDefVal
|
||||||
} else if len(shorthands) > 1 {
|
} else if len(shorthands) > 1 {
|
||||||
|
// '-farg'
|
||||||
value = shorthands[1:]
|
value = shorthands[1:]
|
||||||
outShorts = ""
|
outShorts = ""
|
||||||
} else if len(args) > 0 {
|
} else if len(args) > 0 {
|
||||||
|
// '-f arg'
|
||||||
value = args[0]
|
value = args[0]
|
||||||
outArgs = args[1:]
|
outArgs = args[1:]
|
||||||
} else {
|
} else {
|
||||||
|
// '-f' (arg was required)
|
||||||
err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
|
err = f.failf("flag needs an argument: %q in -%s", c, shorthands)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = f.setFlag(flag, value, shorthands)
|
|
||||||
|
if flag.ShorthandDeprecated != "" {
|
||||||
|
fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fn(flag, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error) {
|
func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) {
|
||||||
a = args
|
a = args
|
||||||
shorthands := s[1:]
|
shorthands := s[1:]
|
||||||
|
|
||||||
|
// "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv").
|
||||||
for len(shorthands) > 0 {
|
for len(shorthands) > 0 {
|
||||||
shorthands, a, err = f.parseSingleShortArg(shorthands, args)
|
shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -843,7 +980,7 @@ func (f *FlagSet) parseShortArg(s string, args []string) (a []string, err error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlagSet) parseArgs(args []string) (err error) {
|
func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) {
|
||||||
for len(args) > 0 {
|
for len(args) > 0 {
|
||||||
s := args[0]
|
s := args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
|
@ -863,9 +1000,9 @@ func (f *FlagSet) parseArgs(args []string) (err error) {
|
||||||
f.args = append(f.args, args...)
|
f.args = append(f.args, args...)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
args, err = f.parseLongArg(s, args)
|
args, err = f.parseLongArg(s, args, fn)
|
||||||
} else {
|
} else {
|
||||||
args, err = f.parseShortArg(s, args)
|
args, err = f.parseShortArg(s, args, fn)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -880,8 +1017,43 @@ func (f *FlagSet) parseArgs(args []string) (err error) {
|
||||||
// The return value will be ErrHelp if -help was set but not defined.
|
// The return value will be ErrHelp if -help was set but not defined.
|
||||||
func (f *FlagSet) Parse(arguments []string) error {
|
func (f *FlagSet) Parse(arguments []string) error {
|
||||||
f.parsed = true
|
f.parsed = true
|
||||||
|
|
||||||
|
if len(arguments) < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
f.args = make([]string, 0, len(arguments))
|
f.args = make([]string, 0, len(arguments))
|
||||||
err := f.parseArgs(arguments)
|
|
||||||
|
set := func(flag *Flag, value string) error {
|
||||||
|
return f.Set(flag.Name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := f.parseArgs(arguments, set)
|
||||||
|
if err != nil {
|
||||||
|
switch f.errorHandling {
|
||||||
|
case ContinueOnError:
|
||||||
|
return err
|
||||||
|
case ExitOnError:
|
||||||
|
os.Exit(2)
|
||||||
|
case PanicOnError:
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseFunc func(flag *Flag, value string) error
|
||||||
|
|
||||||
|
// ParseAll parses flag definitions from the argument list, which should not
|
||||||
|
// include the command name. The arguments for fn are flag and value. Must be
|
||||||
|
// called after all flags in the FlagSet are defined and before flags are
|
||||||
|
// accessed by the program. The return value will be ErrHelp if -help was set
|
||||||
|
// but not defined.
|
||||||
|
func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error {
|
||||||
|
f.parsed = true
|
||||||
|
f.args = make([]string, 0, len(arguments))
|
||||||
|
|
||||||
|
err := f.parseArgs(arguments, fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch f.errorHandling {
|
switch f.errorHandling {
|
||||||
case ContinueOnError:
|
case ContinueOnError:
|
||||||
|
@ -907,6 +1079,14 @@ func Parse() {
|
||||||
CommandLine.Parse(os.Args[1:])
|
CommandLine.Parse(os.Args[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseAll parses the command-line flags from os.Args[1:] and called fn for each.
|
||||||
|
// The arguments for fn are flag and value. Must be called after all flags are
|
||||||
|
// defined and before flags are accessed by the program.
|
||||||
|
func ParseAll(fn func(flag *Flag, value string) error) {
|
||||||
|
// Ignore errors; CommandLine is set for ExitOnError.
|
||||||
|
CommandLine.ParseAll(os.Args[1:], fn)
|
||||||
|
}
|
||||||
|
|
||||||
// SetInterspersed sets whether to support interspersed option/non-option arguments.
|
// SetInterspersed sets whether to support interspersed option/non-option arguments.
|
||||||
func SetInterspersed(interspersed bool) {
|
func SetInterspersed(interspersed bool) {
|
||||||
CommandLine.SetInterspersed(interspersed)
|
CommandLine.SetInterspersed(interspersed)
|
||||||
|
@ -920,14 +1100,15 @@ func Parsed() bool {
|
||||||
// CommandLine is the default set of command-line flags, parsed from os.Args.
|
// CommandLine is the default set of command-line flags, parsed from os.Args.
|
||||||
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
|
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
|
||||||
|
|
||||||
// NewFlagSet returns a new, empty flag set with the specified name and
|
// NewFlagSet returns a new, empty flag set with the specified name,
|
||||||
// error handling property.
|
// error handling property and SortFlags set to true.
|
||||||
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
|
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
|
||||||
f := &FlagSet{
|
f := &FlagSet{
|
||||||
name: name,
|
name: name,
|
||||||
errorHandling: errorHandling,
|
errorHandling: errorHandling,
|
||||||
argsLenAtDash: -1,
|
argsLenAtDash: -1,
|
||||||
interspersed: true,
|
interspersed: true,
|
||||||
|
SortFlags: true,
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
145
vendor/github.com/spf13/pflag/flag_test.go
generated
vendored
145
vendor/github.com/spf13/pflag/flag_test.go
generated
vendored
|
@ -333,6 +333,59 @@ func testParse(f *FlagSet, t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testParseAll(f *FlagSet, t *testing.T) {
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
f.BoolP("boola", "a", false, "bool value")
|
||||||
|
f.BoolP("boolb", "b", false, "bool2 value")
|
||||||
|
f.BoolP("boolc", "c", false, "bool3 value")
|
||||||
|
f.BoolP("boold", "d", false, "bool4 value")
|
||||||
|
f.StringP("stringa", "s", "0", "string value")
|
||||||
|
f.StringP("stringz", "z", "0", "string value")
|
||||||
|
f.StringP("stringx", "x", "0", "string value")
|
||||||
|
f.StringP("stringy", "y", "0", "string value")
|
||||||
|
f.Lookup("stringx").NoOptDefVal = "1"
|
||||||
|
args := []string{
|
||||||
|
"-ab",
|
||||||
|
"-cs=xx",
|
||||||
|
"--stringz=something",
|
||||||
|
"-d=true",
|
||||||
|
"-x",
|
||||||
|
"-y",
|
||||||
|
"ee",
|
||||||
|
}
|
||||||
|
want := []string{
|
||||||
|
"boola", "true",
|
||||||
|
"boolb", "true",
|
||||||
|
"boolc", "true",
|
||||||
|
"stringa", "xx",
|
||||||
|
"stringz", "something",
|
||||||
|
"boold", "true",
|
||||||
|
"stringx", "1",
|
||||||
|
"stringy", "ee",
|
||||||
|
}
|
||||||
|
got := []string{}
|
||||||
|
store := func(flag *Flag, value string) error {
|
||||||
|
got = append(got, flag.Name)
|
||||||
|
if len(value) > 0 {
|
||||||
|
got = append(got, value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := f.ParseAll(args, store); err != nil {
|
||||||
|
t.Errorf("expected no error, got %s", err)
|
||||||
|
}
|
||||||
|
if !f.Parsed() {
|
||||||
|
t.Errorf("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("f.ParseAll() fail to restore the args")
|
||||||
|
t.Errorf("Got: %v", got)
|
||||||
|
t.Errorf("Want: %v", want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestShorthand(t *testing.T) {
|
func TestShorthand(t *testing.T) {
|
||||||
f := NewFlagSet("shorthand", ContinueOnError)
|
f := NewFlagSet("shorthand", ContinueOnError)
|
||||||
if f.Parsed() {
|
if f.Parsed() {
|
||||||
|
@ -393,21 +446,62 @@ func TestShorthand(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShorthandLookup(t *testing.T) {
|
||||||
|
f := NewFlagSet("shorthand", ContinueOnError)
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
f.BoolP("boola", "a", false, "bool value")
|
||||||
|
f.BoolP("boolb", "b", false, "bool2 value")
|
||||||
|
args := []string{
|
||||||
|
"-ab",
|
||||||
|
}
|
||||||
|
f.SetOutput(ioutil.Discard)
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Error("expected no error, got ", err)
|
||||||
|
}
|
||||||
|
if !f.Parsed() {
|
||||||
|
t.Error("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
flag := f.ShorthandLookup("a")
|
||||||
|
if flag == nil {
|
||||||
|
t.Errorf("f.ShorthandLookup(\"a\") returned nil")
|
||||||
|
}
|
||||||
|
if flag.Name != "boola" {
|
||||||
|
t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name)
|
||||||
|
}
|
||||||
|
flag = f.ShorthandLookup("")
|
||||||
|
if flag != nil {
|
||||||
|
t.Errorf("f.ShorthandLookup(\"\") did not return nil")
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
flag = f.ShorthandLookup("ab")
|
||||||
|
// should NEVER get here. lookup should panic. defer'd func should recover it.
|
||||||
|
t.Errorf("f.ShorthandLookup(\"ab\") did not panic")
|
||||||
|
}
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
ResetForTesting(func() { t.Error("bad parse") })
|
ResetForTesting(func() { t.Error("bad parse") })
|
||||||
testParse(GetCommandLine(), t)
|
testParse(GetCommandLine(), t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseAll(t *testing.T) {
|
||||||
|
ResetForTesting(func() { t.Error("bad parse") })
|
||||||
|
testParseAll(GetCommandLine(), t)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFlagSetParse(t *testing.T) {
|
func TestFlagSetParse(t *testing.T) {
|
||||||
testParse(NewFlagSet("test", ContinueOnError), t)
|
testParse(NewFlagSet("test", ContinueOnError), t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChangedHelper(t *testing.T) {
|
func TestChangedHelper(t *testing.T) {
|
||||||
f := NewFlagSet("changedtest", ContinueOnError)
|
f := NewFlagSet("changedtest", ContinueOnError)
|
||||||
_ = f.Bool("changed", false, "changed bool")
|
f.Bool("changed", false, "changed bool")
|
||||||
_ = f.Bool("settrue", true, "true to true")
|
f.Bool("settrue", true, "true to true")
|
||||||
_ = f.Bool("setfalse", false, "false to false")
|
f.Bool("setfalse", false, "false to false")
|
||||||
_ = f.Bool("unchanged", false, "unchanged bool")
|
f.Bool("unchanged", false, "unchanged bool")
|
||||||
|
|
||||||
args := []string{"--changed", "--settrue", "--setfalse=false"}
|
args := []string{"--changed", "--settrue", "--setfalse=false"}
|
||||||
if err := f.Parse(args); err != nil {
|
if err := f.Parse(args); err != nil {
|
||||||
|
@ -878,6 +972,7 @@ const defaultOutput = ` --A for bootstrapping, allo
|
||||||
--Alongflagname disable bounds checking
|
--Alongflagname disable bounds checking
|
||||||
-C, --CCC a boolean defaulting to true (default true)
|
-C, --CCC a boolean defaulting to true (default true)
|
||||||
--D path set relative path for local imports
|
--D path set relative path for local imports
|
||||||
|
-E, --EEE num[=1234] a num with NoOptDefVal (default 4321)
|
||||||
--F number a non-zero number (default 2.7)
|
--F number a non-zero number (default 2.7)
|
||||||
--G float a float that defaults to zero
|
--G float a float that defaults to zero
|
||||||
--IP ip IP address with no default
|
--IP ip IP address with no default
|
||||||
|
@ -929,6 +1024,8 @@ func TestPrintDefaults(t *testing.T) {
|
||||||
fs.Lookup("ND1").NoOptDefVal = "bar"
|
fs.Lookup("ND1").NoOptDefVal = "bar"
|
||||||
fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
|
fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
|
||||||
fs.Lookup("ND2").NoOptDefVal = "4321"
|
fs.Lookup("ND2").NoOptDefVal = "4321"
|
||||||
|
fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal")
|
||||||
|
fs.ShorthandLookup("E").NoOptDefVal = "1234"
|
||||||
fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
|
fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
|
||||||
fs.StringArray("StringArray", []string{}, "string array with zero default")
|
fs.StringArray("StringArray", []string{}, "string array with zero default")
|
||||||
|
|
||||||
|
@ -946,3 +1043,43 @@ func TestPrintDefaults(t *testing.T) {
|
||||||
t.Errorf("got %q want %q\n", got, defaultOutput)
|
t.Errorf("got %q want %q\n", got, defaultOutput)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVisitAllFlagOrder(t *testing.T) {
|
||||||
|
fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError)
|
||||||
|
fs.SortFlags = false
|
||||||
|
// https://github.com/spf13/pflag/issues/120
|
||||||
|
fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName {
|
||||||
|
return NormalizedName(name)
|
||||||
|
})
|
||||||
|
|
||||||
|
names := []string{"C", "B", "A", "D"}
|
||||||
|
for _, name := range names {
|
||||||
|
fs.Bool(name, false, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
fs.VisitAll(func(f *Flag) {
|
||||||
|
if names[i] != f.Name {
|
||||||
|
t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVisitFlagOrder(t *testing.T) {
|
||||||
|
fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError)
|
||||||
|
fs.SortFlags = false
|
||||||
|
names := []string{"C", "B", "A", "D"}
|
||||||
|
for _, name := range names {
|
||||||
|
fs.Bool(name, false, "")
|
||||||
|
fs.Set(name, "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
fs.Visit(func(f *Flag) {
|
||||||
|
if names[i] != f.Name {
|
||||||
|
t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
3
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
3
vendor/github.com/spf13/pflag/golangflag.go
generated
vendored
|
@ -6,13 +6,10 @@ package pflag
|
||||||
|
|
||||||
import (
|
import (
|
||||||
goflag "flag"
|
goflag "flag"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Print
|
|
||||||
|
|
||||||
// flagValueWrapper implements pflag.Value around a flag.Value. The main
|
// flagValueWrapper implements pflag.Value around a flag.Value. The main
|
||||||
// difference here is the addition of the Type method that returns a string
|
// difference here is the addition of the Type method that returns a string
|
||||||
// name of the type. As this is generally unknown, we approximate that with
|
// name of the type. As this is generally unknown, we approximate that with
|
||||||
|
|
2
vendor/github.com/spf13/pflag/ip.go
generated
vendored
2
vendor/github.com/spf13/pflag/ip.go
generated
vendored
|
@ -6,8 +6,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = strings.TrimSpace
|
|
||||||
|
|
||||||
// -- net.IP value
|
// -- net.IP value
|
||||||
type ipValue net.IP
|
type ipValue net.IP
|
||||||
|
|
||||||
|
|
148
vendor/github.com/spf13/pflag/ip_slice.go
generated
vendored
Normal file
148
vendor/github.com/spf13/pflag/ip_slice.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -- ipSlice Value
|
||||||
|
type ipSliceValue struct {
|
||||||
|
value *[]net.IP
|
||||||
|
changed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue {
|
||||||
|
ipsv := new(ipSliceValue)
|
||||||
|
ipsv.value = p
|
||||||
|
*ipsv.value = val
|
||||||
|
return ipsv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag.
|
||||||
|
// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended.
|
||||||
|
func (s *ipSliceValue) Set(val string) error {
|
||||||
|
|
||||||
|
// remove all quote characters
|
||||||
|
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")
|
||||||
|
|
||||||
|
// read flag arguments with CSV parser
|
||||||
|
ipStrSlice, err := readAsCSV(rmQuote.Replace(val))
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse ip values into slice
|
||||||
|
out := make([]net.IP, 0, len(ipStrSlice))
|
||||||
|
for _, ipStr := range ipStrSlice {
|
||||||
|
ip := net.ParseIP(strings.TrimSpace(ipStr))
|
||||||
|
if ip == nil {
|
||||||
|
return fmt.Errorf("invalid string being converted to IP address: %s", ipStr)
|
||||||
|
}
|
||||||
|
out = append(out, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.changed {
|
||||||
|
*s.value = out
|
||||||
|
} else {
|
||||||
|
*s.value = append(*s.value, out...)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.changed = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns a string that uniquely represents this flag's type.
|
||||||
|
func (s *ipSliceValue) Type() string {
|
||||||
|
return "ipSlice"
|
||||||
|
}
|
||||||
|
|
||||||
|
// String defines a "native" format for this net.IP slice flag value.
|
||||||
|
func (s *ipSliceValue) String() string {
|
||||||
|
|
||||||
|
ipStrSlice := make([]string, len(*s.value))
|
||||||
|
for i, ip := range *s.value {
|
||||||
|
ipStrSlice[i] = ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
out, _ := writeAsCSV(ipStrSlice)
|
||||||
|
|
||||||
|
return "[" + out + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipSliceConv(val string) (interface{}, error) {
|
||||||
|
val = strings.Trim(val, "[]")
|
||||||
|
// Emtpy string would cause a slice with one (empty) entry
|
||||||
|
if len(val) == 0 {
|
||||||
|
return []net.IP{}, nil
|
||||||
|
}
|
||||||
|
ss := strings.Split(val, ",")
|
||||||
|
out := make([]net.IP, len(ss))
|
||||||
|
for i, sval := range ss {
|
||||||
|
ip := net.ParseIP(strings.TrimSpace(sval))
|
||||||
|
if ip == nil {
|
||||||
|
return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval)
|
||||||
|
}
|
||||||
|
out[i] = ip
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIPSlice returns the []net.IP value of a flag with the given name
|
||||||
|
func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) {
|
||||||
|
val, err := f.getFlagType(name, "ipSlice", ipSliceConv)
|
||||||
|
if err != nil {
|
||||||
|
return []net.IP{}, err
|
||||||
|
}
|
||||||
|
return val.([]net.IP), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a []net.IP variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
|
||||||
|
f.VarP(newIPSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
|
||||||
|
f.VarP(newIPSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a []net.IP variable in which to store the value of the flag.
|
||||||
|
func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) {
|
||||||
|
CommandLine.VarP(newIPSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) {
|
||||||
|
CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []net.IP variable that stores the value of that flag.
|
||||||
|
func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP {
|
||||||
|
p := []net.IP{}
|
||||||
|
f.IPSliceVarP(&p, name, "", value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
|
||||||
|
p := []net.IP{}
|
||||||
|
f.IPSliceVarP(&p, name, shorthand, value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSlice defines a []net.IP flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []net.IP variable that stores the value of the flag.
|
||||||
|
func IPSlice(name string, value []net.IP, usage string) *[]net.IP {
|
||||||
|
return CommandLine.IPSliceP(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP {
|
||||||
|
return CommandLine.IPSliceP(name, shorthand, value, usage)
|
||||||
|
}
|
222
vendor/github.com/spf13/pflag/ip_slice_test.go
generated
vendored
Normal file
222
vendor/github.com/spf13/pflag/ip_slice_test.go
generated
vendored
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpIPSFlagSet(ipsp *[]net.IP) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.IPSliceVar(ipsp, "ips", []net.IP{}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpIPSFlagSetWithDefault(ipsp *[]net.IP) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.IPSliceVar(ipsp, "ips",
|
||||||
|
[]net.IP{
|
||||||
|
net.ParseIP("192.168.1.1"),
|
||||||
|
net.ParseIP("0:0:0:0:0:0:0:1"),
|
||||||
|
},
|
||||||
|
"Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyIP(t *testing.T) {
|
||||||
|
var ips []net.IP
|
||||||
|
f := setUpIPSFlagSet(&ips)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getIPS, err := f.GetIPSlice("ips")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIPSlice():", err)
|
||||||
|
}
|
||||||
|
if len(getIPS) != 0 {
|
||||||
|
t.Fatalf("got ips %v with len=%d but expected length=0", getIPS, len(getIPS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPS(t *testing.T) {
|
||||||
|
var ips []net.IP
|
||||||
|
f := setUpIPSFlagSet(&ips)
|
||||||
|
|
||||||
|
vals := []string{"192.168.1.1", "10.0.0.1", "0:0:0:0:0:0:0:2"}
|
||||||
|
arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ips {
|
||||||
|
if ip := net.ParseIP(vals[i]); ip == nil {
|
||||||
|
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
|
||||||
|
} else if !ip.Equal(v) {
|
||||||
|
t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPSDefault(t *testing.T) {
|
||||||
|
var ips []net.IP
|
||||||
|
f := setUpIPSFlagSetWithDefault(&ips)
|
||||||
|
|
||||||
|
vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"}
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ips {
|
||||||
|
if ip := net.ParseIP(vals[i]); ip == nil {
|
||||||
|
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
|
||||||
|
} else if !ip.Equal(v) {
|
||||||
|
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIPS, err := f.GetIPSlice("ips")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIPSlice")
|
||||||
|
}
|
||||||
|
for i, v := range getIPS {
|
||||||
|
if ip := net.ParseIP(vals[i]); ip == nil {
|
||||||
|
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
|
||||||
|
} else if !ip.Equal(v) {
|
||||||
|
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPSWithDefault(t *testing.T) {
|
||||||
|
var ips []net.IP
|
||||||
|
f := setUpIPSFlagSetWithDefault(&ips)
|
||||||
|
|
||||||
|
vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"}
|
||||||
|
arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ips {
|
||||||
|
if ip := net.ParseIP(vals[i]); ip == nil {
|
||||||
|
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
|
||||||
|
} else if !ip.Equal(v) {
|
||||||
|
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIPS, err := f.GetIPSlice("ips")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIPSlice")
|
||||||
|
}
|
||||||
|
for i, v := range getIPS {
|
||||||
|
if ip := net.ParseIP(vals[i]); ip == nil {
|
||||||
|
t.Fatalf("invalid string being converted to IP address: %s", vals[i])
|
||||||
|
} else if !ip.Equal(v) {
|
||||||
|
t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPSCalledTwice(t *testing.T) {
|
||||||
|
var ips []net.IP
|
||||||
|
f := setUpIPSFlagSet(&ips)
|
||||||
|
|
||||||
|
in := []string{"192.168.1.2,0:0:0:0:0:0:0:1", "10.0.0.1"}
|
||||||
|
expected := []net.IP{net.ParseIP("192.168.1.2"), net.ParseIP("0:0:0:0:0:0:0:1"), net.ParseIP("10.0.0.1")}
|
||||||
|
argfmt := "ips=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ips {
|
||||||
|
if !expected[i].Equal(v) {
|
||||||
|
t.Fatalf("expected ips[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPSBadQuoting(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
Want []net.IP
|
||||||
|
FlagArg []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Want: []net.IP{
|
||||||
|
net.ParseIP("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568"),
|
||||||
|
net.ParseIP("203.107.49.208"),
|
||||||
|
net.ParseIP("14.57.204.90"),
|
||||||
|
},
|
||||||
|
FlagArg: []string{
|
||||||
|
"a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568",
|
||||||
|
"203.107.49.208",
|
||||||
|
"14.57.204.90",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []net.IP{
|
||||||
|
net.ParseIP("204.228.73.195"),
|
||||||
|
net.ParseIP("86.141.15.94"),
|
||||||
|
},
|
||||||
|
FlagArg: []string{
|
||||||
|
"204.228.73.195",
|
||||||
|
"86.141.15.94",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []net.IP{
|
||||||
|
net.ParseIP("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f"),
|
||||||
|
net.ParseIP("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472"),
|
||||||
|
},
|
||||||
|
FlagArg: []string{
|
||||||
|
"c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f",
|
||||||
|
"4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []net.IP{
|
||||||
|
net.ParseIP("5170:f971:cfac:7be3:512a:af37:952c:bc33"),
|
||||||
|
net.ParseIP("93.21.145.140"),
|
||||||
|
net.ParseIP("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca"),
|
||||||
|
},
|
||||||
|
FlagArg: []string{
|
||||||
|
" 5170:f971:cfac:7be3:512a:af37:952c:bc33 , 93.21.145.140 ",
|
||||||
|
"2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Want: []net.IP{
|
||||||
|
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
|
||||||
|
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
|
||||||
|
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
|
||||||
|
net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"),
|
||||||
|
},
|
||||||
|
FlagArg: []string{
|
||||||
|
`"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b "`,
|
||||||
|
" 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
|
||||||
|
var ips []net.IP
|
||||||
|
f := setUpIPSFlagSet(&ips)
|
||||||
|
|
||||||
|
if err := f.Parse([]string{fmt.Sprintf("--ips=%s", strings.Join(test.FlagArg, ","))}); err != nil {
|
||||||
|
t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s",
|
||||||
|
err, test.FlagArg, test.Want[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
for j, b := range ips {
|
||||||
|
if !b.Equal(test.Want[j]) {
|
||||||
|
t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
vendor/github.com/spf13/pflag/ipnet.go
generated
vendored
2
vendor/github.com/spf13/pflag/ipnet.go
generated
vendored
|
@ -27,8 +27,6 @@ func (*ipNetValue) Type() string {
|
||||||
return "ipNet"
|
return "ipNet"
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = strings.TrimSpace
|
|
||||||
|
|
||||||
func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue {
|
func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue {
|
||||||
*p = val
|
*p = val
|
||||||
return (*ipNetValue)(p)
|
return (*ipNetValue)(p)
|
||||||
|
|
9
vendor/github.com/spf13/pflag/string_array.go
generated
vendored
9
vendor/github.com/spf13/pflag/string_array.go
generated
vendored
|
@ -1,12 +1,5 @@
|
||||||
package pflag
|
package pflag
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = fmt.Fprint
|
|
||||||
|
|
||||||
// -- stringArray Value
|
// -- stringArray Value
|
||||||
type stringArrayValue struct {
|
type stringArrayValue struct {
|
||||||
value *[]string
|
value *[]string
|
||||||
|
@ -40,7 +33,7 @@ func (s *stringArrayValue) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringArrayConv(sval string) (interface{}, error) {
|
func stringArrayConv(sval string) (interface{}, error) {
|
||||||
sval = strings.Trim(sval, "[]")
|
sval = sval[1 : len(sval)-1]
|
||||||
// An empty string would cause a array with one (empty) string
|
// An empty string would cause a array with one (empty) string
|
||||||
if len(sval) == 0 {
|
if len(sval) == 0 {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
|
|
39
vendor/github.com/spf13/pflag/string_array_test.go
generated
vendored
39
vendor/github.com/spf13/pflag/string_array_test.go
generated
vendored
|
@ -192,3 +192,42 @@ func TestSAWithSpecialChar(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSAWithSquareBrackets(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSet(&sa)
|
||||||
|
|
||||||
|
in := []string{"][]-[", "[a-z]", "[a-z]+"}
|
||||||
|
expected := []string{"][]-[", "[a-z]", "[a-z]+"}
|
||||||
|
argfmt := "--sa=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
arg3 := fmt.Sprintf(argfmt, in[2])
|
||||||
|
err := f.Parse([]string{arg1, arg2, arg3})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(sa) {
|
||||||
|
t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa))
|
||||||
|
}
|
||||||
|
for i, v := range sa {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(values) {
|
||||||
|
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
7
vendor/github.com/spf13/pflag/string_slice.go
generated
vendored
7
vendor/github.com/spf13/pflag/string_slice.go
generated
vendored
|
@ -3,12 +3,9 @@ package pflag
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Fprint
|
|
||||||
|
|
||||||
// -- stringSlice Value
|
// -- stringSlice Value
|
||||||
type stringSliceValue struct {
|
type stringSliceValue struct {
|
||||||
value *[]string
|
value *[]string
|
||||||
|
@ -39,7 +36,7 @@ func writeAsCSV(vals []string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
w.Flush()
|
w.Flush()
|
||||||
return strings.TrimSuffix(b.String(), fmt.Sprintln()), nil
|
return strings.TrimSuffix(b.String(), "\n"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stringSliceValue) Set(val string) error {
|
func (s *stringSliceValue) Set(val string) error {
|
||||||
|
@ -66,7 +63,7 @@ func (s *stringSliceValue) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringSliceConv(sval string) (interface{}, error) {
|
func stringSliceConv(sval string) (interface{}, error) {
|
||||||
sval = strings.Trim(sval, "[]")
|
sval = sval[1 : len(sval)-1]
|
||||||
// An empty string would cause a slice with one (empty) string
|
// An empty string would cause a slice with one (empty) string
|
||||||
if len(sval) == 0 {
|
if len(sval) == 0 {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
|
|
38
vendor/github.com/spf13/pflag/string_slice_test.go
generated
vendored
38
vendor/github.com/spf13/pflag/string_slice_test.go
generated
vendored
|
@ -213,3 +213,41 @@ func TestSSWithComma(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSSWithSquareBrackets(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSet(&ss)
|
||||||
|
|
||||||
|
in := []string{`"[a-z]"`, `"[a-z]+"`}
|
||||||
|
expected := []string{"[a-z]", "[a-z]+"}
|
||||||
|
argfmt := "--ss=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(ss) {
|
||||||
|
t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss))
|
||||||
|
}
|
||||||
|
for i, v := range ss {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(values) {
|
||||||
|
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
126
vendor/github.com/spf13/pflag/uint_slice.go
generated
vendored
Normal file
126
vendor/github.com/spf13/pflag/uint_slice.go
generated
vendored
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -- uintSlice Value
|
||||||
|
type uintSliceValue struct {
|
||||||
|
value *[]uint
|
||||||
|
changed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue {
|
||||||
|
uisv := new(uintSliceValue)
|
||||||
|
uisv.value = p
|
||||||
|
*uisv.value = val
|
||||||
|
return uisv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *uintSliceValue) Set(val string) error {
|
||||||
|
ss := strings.Split(val, ",")
|
||||||
|
out := make([]uint, len(ss))
|
||||||
|
for i, d := range ss {
|
||||||
|
u, err := strconv.ParseUint(d, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out[i] = uint(u)
|
||||||
|
}
|
||||||
|
if !s.changed {
|
||||||
|
*s.value = out
|
||||||
|
} else {
|
||||||
|
*s.value = append(*s.value, out...)
|
||||||
|
}
|
||||||
|
s.changed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *uintSliceValue) Type() string {
|
||||||
|
return "uintSlice"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *uintSliceValue) String() string {
|
||||||
|
out := make([]string, len(*s.value))
|
||||||
|
for i, d := range *s.value {
|
||||||
|
out[i] = fmt.Sprintf("%d", d)
|
||||||
|
}
|
||||||
|
return "[" + strings.Join(out, ",") + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func uintSliceConv(val string) (interface{}, error) {
|
||||||
|
val = strings.Trim(val, "[]")
|
||||||
|
// Empty string would cause a slice with one (empty) entry
|
||||||
|
if len(val) == 0 {
|
||||||
|
return []uint{}, nil
|
||||||
|
}
|
||||||
|
ss := strings.Split(val, ",")
|
||||||
|
out := make([]uint, len(ss))
|
||||||
|
for i, d := range ss {
|
||||||
|
u, err := strconv.ParseUint(d, 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out[i] = uint(u)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUintSlice returns the []uint value of a flag with the given name.
|
||||||
|
func (f *FlagSet) GetUintSlice(name string) ([]uint, error) {
|
||||||
|
val, err := f.getFlagType(name, "uintSlice", uintSliceConv)
|
||||||
|
if err != nil {
|
||||||
|
return []uint{}, err
|
||||||
|
}
|
||||||
|
return val.([]uint), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a []uint variable in which to store the value of the flag.
|
||||||
|
func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) {
|
||||||
|
f.VarP(newUintSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
|
||||||
|
f.VarP(newUintSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSliceVar defines a uint[] flag with specified name, default value, and usage string.
|
||||||
|
// The argument p points to a uint[] variable in which to store the value of the flag.
|
||||||
|
func UintSliceVar(p *[]uint, name string, value []uint, usage string) {
|
||||||
|
CommandLine.VarP(newUintSliceValue(value, p), name, "", usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) {
|
||||||
|
CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSlice defines a []uint flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []uint variable that stores the value of the flag.
|
||||||
|
func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint {
|
||||||
|
p := []uint{}
|
||||||
|
f.UintSliceVarP(&p, name, "", value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
|
||||||
|
p := []uint{}
|
||||||
|
f.UintSliceVarP(&p, name, shorthand, value, usage)
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSlice defines a []uint flag with specified name, default value, and usage string.
|
||||||
|
// The return value is the address of a []uint variable that stores the value of the flag.
|
||||||
|
func UintSlice(name string, value []uint, usage string) *[]uint {
|
||||||
|
return CommandLine.UintSliceP(name, "", value, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash.
|
||||||
|
func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint {
|
||||||
|
return CommandLine.UintSliceP(name, shorthand, value, usage)
|
||||||
|
}
|
161
vendor/github.com/spf13/pflag/uint_slice_test.go
generated
vendored
Normal file
161
vendor/github.com/spf13/pflag/uint_slice_test.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpUISFlagSet(uisp *[]uint) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.UintSliceVar(uisp, "uis", []uint{}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpUISFlagSetWithDefault(uisp *[]uint) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.UintSliceVar(uisp, "uis", []uint{0, 1}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyUIS(t *testing.T) {
|
||||||
|
var uis []uint
|
||||||
|
f := setUpUISFlagSet(&uis)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getUIS, err := f.GetUintSlice("uis")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetUintSlice():", err)
|
||||||
|
}
|
||||||
|
if len(getUIS) != 0 {
|
||||||
|
t.Fatalf("got is %v with len=%d but expected length=0", getUIS, len(getUIS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUIS(t *testing.T) {
|
||||||
|
var uis []uint
|
||||||
|
f := setUpUISFlagSet(&uis)
|
||||||
|
|
||||||
|
vals := []string{"1", "2", "4", "3"}
|
||||||
|
arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range uis {
|
||||||
|
u, err := strconv.ParseUint(vals[i], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if uint(u) != v {
|
||||||
|
t.Fatalf("expected uis[%d] to be %s but got %d", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getUIS, err := f.GetUintSlice("uis")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
for i, v := range getUIS {
|
||||||
|
u, err := strconv.ParseUint(vals[i], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if uint(u) != v {
|
||||||
|
t.Fatalf("expected uis[%d] to be %s but got: %d from GetUintSlice", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUISDefault(t *testing.T) {
|
||||||
|
var uis []uint
|
||||||
|
f := setUpUISFlagSetWithDefault(&uis)
|
||||||
|
|
||||||
|
vals := []string{"0", "1"}
|
||||||
|
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range uis {
|
||||||
|
u, err := strconv.ParseUint(vals[i], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if uint(u) != v {
|
||||||
|
t.Fatalf("expect uis[%d] to be %d but got: %d", i, u, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getUIS, err := f.GetUintSlice("uis")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetUintSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getUIS {
|
||||||
|
u, err := strconv.ParseUint(vals[i], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIntSlice():", err)
|
||||||
|
}
|
||||||
|
if uint(u) != v {
|
||||||
|
t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUISWithDefault(t *testing.T) {
|
||||||
|
var uis []uint
|
||||||
|
f := setUpUISFlagSetWithDefault(&uis)
|
||||||
|
|
||||||
|
vals := []string{"1", "2"}
|
||||||
|
arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range uis {
|
||||||
|
u, err := strconv.ParseUint(vals[i], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if uint(u) != v {
|
||||||
|
t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getUIS, err := f.GetUintSlice("uis")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetUintSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getUIS {
|
||||||
|
u, err := strconv.ParseUint(vals[i], 10, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if uint(u) != v {
|
||||||
|
t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUISCalledTwice(t *testing.T) {
|
||||||
|
var uis []uint
|
||||||
|
f := setUpUISFlagSet(&uis)
|
||||||
|
|
||||||
|
in := []string{"1,2", "3"}
|
||||||
|
expected := []int{1, 2, 3}
|
||||||
|
argfmt := "--uis=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range uis {
|
||||||
|
if uint(expected[i]) != v {
|
||||||
|
t.Fatalf("expected uis[%d] to be %d but got: %d", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
vendor/gopkg.in/validator.v2/.gitignore
generated
vendored
Normal file
23
vendor/gopkg.in/validator.v2/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
10
vendor/gopkg.in/validator.v2/.travis.yml
generated
vendored
Normal file
10
vendor/gopkg.in/validator.v2/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
go_import_path: gopkg.in/validator.v2
|
||||||
|
script:
|
||||||
|
- go test -race -v -bench=.
|
||||||
|
notifications:
|
||||||
|
email: false
|
201
vendor/gopkg.in/validator.v2/LICENSE
generated
vendored
Normal file
201
vendor/gopkg.in/validator.v2/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
167
vendor/gopkg.in/validator.v2/README.md
generated
vendored
Normal file
167
vendor/gopkg.in/validator.v2/README.md
generated
vendored
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
Package validator
|
||||||
|
================
|
||||||
|
|
||||||
|
Package validator implements variable validations
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Just use go get.
|
||||||
|
|
||||||
|
go get gopkg.in/validator.v2
|
||||||
|
|
||||||
|
And then just import the package into your own code.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/validator.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
Please see http://godoc.org/gopkg.in/validator.v2 for detailed usage docs.
|
||||||
|
A simple example would be.
|
||||||
|
|
||||||
|
type NewUserRequest struct {
|
||||||
|
Username string `validate:"min=3,max=40,regexp=^[a-zA-Z]*$"`
|
||||||
|
Name string `validate:"nonzero"`
|
||||||
|
Age int `validate:"min=21"`
|
||||||
|
Password string `validate:"min=8"`
|
||||||
|
}
|
||||||
|
|
||||||
|
nur := NewUserRequest{Username: "something", Age: 20}
|
||||||
|
if errs := validator.Validate(nur); errs != nil {
|
||||||
|
// values not valid, deal with errors here
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Builtin validators
|
||||||
|
|
||||||
|
Here is the list of validators buildin in the package.
|
||||||
|
|
||||||
|
len
|
||||||
|
For numeric numbers, max will simply make sure that the
|
||||||
|
value is equal to the parameter given. For strings, it
|
||||||
|
checks that the string length is exactly that number of
|
||||||
|
characters. For slices, arrays, and maps, validates the
|
||||||
|
number of items. (Usage: len=10)
|
||||||
|
|
||||||
|
max
|
||||||
|
For numeric numbers, max will simply make sure that the
|
||||||
|
value is lesser or equal to the parameter given. For strings,
|
||||||
|
it checks that the string length is at most that number of
|
||||||
|
characters. For slices, arrays, and maps, validates the
|
||||||
|
number of items. (Usage: max=10)
|
||||||
|
|
||||||
|
min
|
||||||
|
For numeric numbers, min will simply make sure that the value
|
||||||
|
is greater or equal to the parameter given. For strings, it
|
||||||
|
checks that the string length is at least that number of
|
||||||
|
characters. For slices, arrays, and maps, validates the
|
||||||
|
number of items. (Usage: min=10)
|
||||||
|
|
||||||
|
nonzero
|
||||||
|
This validates that the value is not zero. The appropriate
|
||||||
|
zero value is given by the Go spec (e.g. for int it's 0, for
|
||||||
|
string it's "", for pointers is nil, etc.) For structs, it
|
||||||
|
will not check to see if the struct itself has all zero
|
||||||
|
values, instead use a pointer or put nonzero on the struct's
|
||||||
|
keys that you care about. (Usage: nonzero)
|
||||||
|
|
||||||
|
regexp
|
||||||
|
Only valid for string types, it will validator that the
|
||||||
|
value matches the regular expression provided as parameter.
|
||||||
|
(Usage: regexp=^a.*b$)
|
||||||
|
|
||||||
|
Custom validators
|
||||||
|
|
||||||
|
It is possible to define custom validators by using SetValidationFunc.
|
||||||
|
First, one needs to create a validation function.
|
||||||
|
|
||||||
|
// Very simple validator
|
||||||
|
func notZZ(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
if st.Kind() != reflect.String {
|
||||||
|
return errors.New("notZZ only validates strings")
|
||||||
|
}
|
||||||
|
if st.String() == "ZZ" {
|
||||||
|
return errors.New("value cannot be ZZ")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Then one needs to add it to the list of validators and give it a "tag"
|
||||||
|
name.
|
||||||
|
|
||||||
|
validator.SetValidationFunc("notzz", notZZ)
|
||||||
|
|
||||||
|
Then it is possible to use the notzz validation tag. This will print
|
||||||
|
"Field A error: value cannot be ZZ"
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
A string `validate:"nonzero,notzz"`
|
||||||
|
}
|
||||||
|
t := T{"ZZ"}
|
||||||
|
if errs := validator.Validate(t); errs != nil {
|
||||||
|
fmt.Printf("Field A error: %s\n", errs["A"][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
You can also have multiple sets of validator rules with SetTag().
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
A int `foo:"nonzero" bar:"min=10"`
|
||||||
|
}
|
||||||
|
t := T{5}
|
||||||
|
SetTag("foo")
|
||||||
|
validator.Validate(t) // valid as it's nonzero
|
||||||
|
SetTag("bar")
|
||||||
|
validator.Validate(t) // invalid as it's less than 10
|
||||||
|
|
||||||
|
SetTag is probably better used with multiple validators.
|
||||||
|
|
||||||
|
fooValidator := validator.NewValidator()
|
||||||
|
fooValidator.SetTag("foo")
|
||||||
|
barValidator := validator.NewValidator()
|
||||||
|
barValidator.SetTag("bar")
|
||||||
|
fooValidator.Validate(t)
|
||||||
|
barValidator.Validate(t)
|
||||||
|
|
||||||
|
This keeps the default validator's tag clean. Again, please refer to
|
||||||
|
godocs for a lot of more examples and different uses.
|
||||||
|
|
||||||
|
Pull requests policy
|
||||||
|
====================
|
||||||
|
|
||||||
|
tl;dr. Contributions are welcome.
|
||||||
|
|
||||||
|
The repository is organized in version branches. Pull requests to, say, the
|
||||||
|
`v2` branch that break API compatibility will not be accepted. It is okay to
|
||||||
|
break the API in master, *not in the branches*.
|
||||||
|
|
||||||
|
As for validation functions, the preference is to keep the main code simple
|
||||||
|
and add most new functions to the validator-contrib repository.
|
||||||
|
|
||||||
|
https://github.com/go-validator/validator-contrib
|
||||||
|
|
||||||
|
For improvements and/or fixes to the builtin validation functions, please
|
||||||
|
make sure the behaviour will not break existing functionality in the branches.
|
||||||
|
If you see a case where the functionality of the builtin will change
|
||||||
|
significantly, please send a pull request against `master`. We can discuss then
|
||||||
|
whether the changes should be incorporated in the version branches as well.
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
Copyright 2014 Roberto Teixeira <robteix@robteix.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
246
vendor/gopkg.in/validator.v2/builtins.go
generated
vendored
Normal file
246
vendor/gopkg.in/validator.v2/builtins.go
generated
vendored
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
// Package validator implements value validations
|
||||||
|
//
|
||||||
|
// Copyright 2014 Roberto Teixeira <robteix@robteix.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nonzero tests whether a variable value non-zero
|
||||||
|
// as defined by the golang spec.
|
||||||
|
func nonzero(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
valid := true
|
||||||
|
switch st.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
valid = len(st.String()) != 0
|
||||||
|
case reflect.Ptr, reflect.Interface:
|
||||||
|
valid = !st.IsNil()
|
||||||
|
case reflect.Slice, reflect.Map, reflect.Array:
|
||||||
|
valid = st.Len() != 0
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
valid = st.Int() != 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
valid = st.Uint() != 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
valid = st.Float() != 0
|
||||||
|
case reflect.Bool:
|
||||||
|
valid = st.Bool()
|
||||||
|
case reflect.Invalid:
|
||||||
|
valid = false // always invalid
|
||||||
|
case reflect.Struct:
|
||||||
|
valid = true // always valid since only nil pointers are empty
|
||||||
|
default:
|
||||||
|
return ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
return ErrZeroValue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// length tests whether a variable's length is equal to a given
|
||||||
|
// value. For strings it tests the number of characters whereas
|
||||||
|
// for maps and slices it tests the number of items.
|
||||||
|
func length(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
valid := true
|
||||||
|
switch st.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
valid = int64(len(st.String())) == p
|
||||||
|
case reflect.Slice, reflect.Map, reflect.Array:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
valid = int64(st.Len()) == p
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
valid = st.Int() == p
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
p, err := asUint(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
valid = st.Uint() == p
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
p, err := asFloat(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
valid = st.Float() == p
|
||||||
|
default:
|
||||||
|
return ErrUnsupported
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
return ErrLen
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// min tests whether a variable value is larger or equal to a given
|
||||||
|
// number. For number types, it's a simple lesser-than test; for
|
||||||
|
// strings it tests the number of characters whereas for maps
|
||||||
|
// and slices it tests the number of items.
|
||||||
|
func min(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
invalid := false
|
||||||
|
switch st.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = int64(len(st.String())) < p
|
||||||
|
case reflect.Slice, reflect.Map, reflect.Array:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = int64(st.Len()) < p
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = st.Int() < p
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
p, err := asUint(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = st.Uint() < p
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
p, err := asFloat(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = st.Float() < p
|
||||||
|
default:
|
||||||
|
return ErrUnsupported
|
||||||
|
}
|
||||||
|
if invalid {
|
||||||
|
return ErrMin
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// max tests whether a variable value is lesser than a given
|
||||||
|
// value. For numbers, it's a simple lesser-than test; for
|
||||||
|
// strings it tests the number of characters whereas for maps
|
||||||
|
// and slices it tests the number of items.
|
||||||
|
func max(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
var invalid bool
|
||||||
|
switch st.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = int64(len(st.String())) > p
|
||||||
|
case reflect.Slice, reflect.Map, reflect.Array:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = int64(st.Len()) > p
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
p, err := asInt(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = st.Int() > p
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
p, err := asUint(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = st.Uint() > p
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
p, err := asFloat(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
invalid = st.Float() > p
|
||||||
|
default:
|
||||||
|
return ErrUnsupported
|
||||||
|
}
|
||||||
|
if invalid {
|
||||||
|
return ErrMax
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// regex is the builtin validation function that checks
|
||||||
|
// whether the string variable matches a regular expression
|
||||||
|
func regex(v interface{}, param string) error {
|
||||||
|
s, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
return ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
re, err := regexp.Compile(param)
|
||||||
|
if err != nil {
|
||||||
|
return ErrBadParameter
|
||||||
|
}
|
||||||
|
|
||||||
|
if !re.MatchString(s) {
|
||||||
|
return ErrRegexp
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// asInt retuns the parameter as a int64
|
||||||
|
// or panics if it can't convert
|
||||||
|
func asInt(param string) (int64, error) {
|
||||||
|
i, err := strconv.ParseInt(param, 0, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, ErrBadParameter
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// asUint retuns the parameter as a uint64
|
||||||
|
// or panics if it can't convert
|
||||||
|
func asUint(param string) (uint64, error) {
|
||||||
|
i, err := strconv.ParseUint(param, 0, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, ErrBadParameter
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// asFloat retuns the parameter as a float64
|
||||||
|
// or panics if it can't convert
|
||||||
|
func asFloat(param string) (float64, error) {
|
||||||
|
i, err := strconv.ParseFloat(param, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0.0, ErrBadParameter
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
265
vendor/gopkg.in/validator.v2/doc.go
generated
vendored
Normal file
265
vendor/gopkg.in/validator.v2/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
// Package validator implements value validations
|
||||||
|
//
|
||||||
|
// Copyright 2014 Roberto Teixeira <robteix@robteix.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package validator implements value validations based on struct tags.
|
||||||
|
|
||||||
|
In code it is often necessary to validate that a given value is valid before
|
||||||
|
using it for something. A typical example might be something like this.
|
||||||
|
|
||||||
|
if age < 18 {
|
||||||
|
return error.New("age cannot be under 18")
|
||||||
|
}
|
||||||
|
|
||||||
|
This is a simple enough example, but it can get significantly more complex,
|
||||||
|
especially when dealing with structs.
|
||||||
|
|
||||||
|
l := len(strings.Trim(s.Username))
|
||||||
|
if l < 3 || l > 40 || !regexp.MatchString("^[a-zA-Z]$", s.Username) || s.Age < 18 || s.Password {
|
||||||
|
return errors.New("Invalid request")
|
||||||
|
}
|
||||||
|
|
||||||
|
You get the idea. Package validator allows one to define valid values as
|
||||||
|
struct tags when defining a new struct type.
|
||||||
|
|
||||||
|
type NewUserRequest struct {
|
||||||
|
Username string `validate:"min=3,max=40,regexp=^[a-zA-Z]*$"`
|
||||||
|
Name string `validate:"nonzero"`
|
||||||
|
Age int `validate:"min=18"`
|
||||||
|
Password string `validate:"min=8"`
|
||||||
|
}
|
||||||
|
|
||||||
|
Then validating a variable of type NewUserRequest becomes trivial.
|
||||||
|
|
||||||
|
nur := NewUserRequest{Username: "something", ...}
|
||||||
|
if errs := validator.Validate(nur); errs != nil {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
|
||||||
|
Builtin validator functions
|
||||||
|
|
||||||
|
Here is the list of validator functions builtin in the package.
|
||||||
|
|
||||||
|
len
|
||||||
|
For numeric numbers, len will simply make sure that the value is
|
||||||
|
equal to the parameter given. For strings, it checks that
|
||||||
|
the string length is exactly that number of characters. For slices,
|
||||||
|
arrays, and maps, validates the number of items. (Usage: len=10)
|
||||||
|
|
||||||
|
max
|
||||||
|
For numeric numbers, max will simply make sure that the value is
|
||||||
|
lesser or equal to the parameter given. For strings, it checks that
|
||||||
|
the string length is at most that number of characters. For slices,
|
||||||
|
arrays, and maps, validates the number of items. (Usage: max=10)
|
||||||
|
|
||||||
|
min
|
||||||
|
For numeric numbers, min will simply make sure that the value is
|
||||||
|
greater or equal to the parameter given. For strings, it checks that
|
||||||
|
the string length is at least that number of characters. For slices,
|
||||||
|
arrays, and maps, validates the number of items. (Usage: min=10)
|
||||||
|
|
||||||
|
nonzero
|
||||||
|
This validates that the value is not zero. The appropriate zero value
|
||||||
|
is given by the Go spec (e.g. for int it's 0, for string it's "", for
|
||||||
|
pointers is nil, etc.) Usage: nonzero
|
||||||
|
|
||||||
|
regexp
|
||||||
|
Only valid for string types, it will validate that the value matches
|
||||||
|
the regular expression provided as parameter. (Usage: regexp=^a.*b$)
|
||||||
|
|
||||||
|
|
||||||
|
Note that there are no tests to prevent conflicting validator parameters. For
|
||||||
|
instance, these fields will never be valid.
|
||||||
|
|
||||||
|
...
|
||||||
|
A int `validate:"max=0,min=1"`
|
||||||
|
B string `validate:"len=10,regexp=^$"
|
||||||
|
...
|
||||||
|
|
||||||
|
Custom validation functions
|
||||||
|
|
||||||
|
It is possible to define custom validation functions by using SetValidationFunc.
|
||||||
|
First, one needs to create a validation function.
|
||||||
|
|
||||||
|
// Very simple validation func
|
||||||
|
func notZZ(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
if st.Kind() != reflect.String {
|
||||||
|
return validate.ErrUnsupported
|
||||||
|
}
|
||||||
|
if st.String() == "ZZ" {
|
||||||
|
return errors.New("value cannot be ZZ")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Then one needs to add it to the list of validation funcs and give it a "tag" name.
|
||||||
|
|
||||||
|
validate.SetValidationFunc("notzz", notZZ)
|
||||||
|
|
||||||
|
Then it is possible to use the notzz validation tag. This will print
|
||||||
|
"Field A error: value cannot be ZZ"
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
A string `validate:"nonzero,notzz"`
|
||||||
|
}
|
||||||
|
t := T{"ZZ"}
|
||||||
|
if errs := validator.Validate(t); errs != nil {
|
||||||
|
fmt.Printf("Field A error: %s\n", errs["A"][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
To use parameters, it is very similar.
|
||||||
|
|
||||||
|
// Very simple validator with parameter
|
||||||
|
func notSomething(v interface{}, param string) error {
|
||||||
|
st := reflect.ValueOf(v)
|
||||||
|
if st.Kind() != reflect.String {
|
||||||
|
return validate.ErrUnsupported
|
||||||
|
}
|
||||||
|
if st.String() == param {
|
||||||
|
return errors.New("value cannot be " + param)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
And then the code below should print "Field A error: value cannot be ABC".
|
||||||
|
|
||||||
|
validator.SetValidationFunc("notsomething", notSomething)
|
||||||
|
type T struct {
|
||||||
|
A string `validate:"notsomething=ABC"`
|
||||||
|
}
|
||||||
|
t := T{"ABC"}
|
||||||
|
if errs := validator.Validate(t); errs != nil {
|
||||||
|
fmt.Printf("Field A error: %s\n", errs["A"][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
As well, it is possible to overwrite builtin validation functions.
|
||||||
|
|
||||||
|
validate.SetValidationFunc("min", myMinFunc)
|
||||||
|
|
||||||
|
And you can delete a validation function by setting it to nil.
|
||||||
|
|
||||||
|
validate.SetValidationFunc("notzz", nil)
|
||||||
|
validate.SetValidationFunc("nonzero", nil)
|
||||||
|
|
||||||
|
Using a non-existing validation func in a field tag will always return
|
||||||
|
false and with error validate.ErrUnknownTag.
|
||||||
|
|
||||||
|
Finally, package validator also provides a helper function that can be used
|
||||||
|
to validate simple variables/values.
|
||||||
|
|
||||||
|
// errs: nil
|
||||||
|
errs = validator.Valid(42, "min=10, max=50")
|
||||||
|
|
||||||
|
// errs: [validate.ErrZeroValue]
|
||||||
|
errs = validator.Valid(nil, "nonzero")
|
||||||
|
|
||||||
|
// errs: [validate.ErrMin,validate.ErrMax]
|
||||||
|
errs = validator.Valid("hi", "nonzero,min=3,max=2")
|
||||||
|
|
||||||
|
Custom tag name
|
||||||
|
|
||||||
|
In case there is a reason why one would not wish to use tag 'validate' (maybe due to
|
||||||
|
a conflict with a different package), it is possible to tell the package to use
|
||||||
|
a different tag.
|
||||||
|
|
||||||
|
validator.SetTag("valid")
|
||||||
|
|
||||||
|
Then.
|
||||||
|
|
||||||
|
Type T struct {
|
||||||
|
A int `valid:"min=8, max=10"`
|
||||||
|
B string `valid:"nonzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTag is permanent. The new tag name will be used until it is again changed
|
||||||
|
with a new call to SetTag. A way to temporarily use a different tag exists.
|
||||||
|
|
||||||
|
validator.WithTag("foo").Validate(t)
|
||||||
|
validator.WithTag("bar").Validate(t)
|
||||||
|
// But this will go back to using 'validate'
|
||||||
|
validator.Validate(t)
|
||||||
|
|
||||||
|
Multiple validators
|
||||||
|
|
||||||
|
You may often need to have a different set of validation
|
||||||
|
rules for different situations. In all the examples above,
|
||||||
|
we only used the default validator but you could create a
|
||||||
|
new one and set specific rules for it.
|
||||||
|
|
||||||
|
For instance, you might use the same struct to decode incoming JSON for a REST API
|
||||||
|
but your needs will change when you're using it to, say, create a new instance
|
||||||
|
in storage vs. when you need to change something.
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Username string `validate:"nonzero"`
|
||||||
|
Name string `validate:"nonzero"`
|
||||||
|
Age int `validate:"nonzero"`
|
||||||
|
Password string `validate:"nonzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe when creating a new user, you need to make sure all values in the struct are filled,
|
||||||
|
but then you use the same struct to handle incoming requests to, say, change the password,
|
||||||
|
in which case you only need the Username and the Password and don't care for the others.
|
||||||
|
You might use two different validators.
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Username string `creating:"nonzero" chgpw:"nonzero"`
|
||||||
|
Name string `creating:"nonzero"`
|
||||||
|
Age int `creating:"nonzero"`
|
||||||
|
Password string `creating:"nonzero" chgpw:"nonzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
creationValidator = validator.NewValidator()
|
||||||
|
chgPwValidator = validator.NewValidator()
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
creationValidator.SetTag("creating")
|
||||||
|
chgPwValidator.SetTag("chgpw")
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var u User
|
||||||
|
json.NewDecoder(r.Body).Decode(&user)
|
||||||
|
if errs := creationValidator.Validate(user); errs != nil {
|
||||||
|
// the request did not include all of the User
|
||||||
|
// struct fields, so send a http.StatusBadRequest
|
||||||
|
// back or something
|
||||||
|
}
|
||||||
|
// create the new user
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetNewUserPasswordHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var u User
|
||||||
|
json.NewDecoder(r.Body).Decode(&user)
|
||||||
|
if errs := chgPwValidator.Validate(user); errs != nil {
|
||||||
|
// the request did not Username and Password,
|
||||||
|
// so send a http.StatusBadRequest
|
||||||
|
// back or something
|
||||||
|
}
|
||||||
|
// save the new password
|
||||||
|
}
|
||||||
|
|
||||||
|
It is also possible to do all of that using only the default validator as long
|
||||||
|
as SetTag is always called before calling validator.Validate() or you chain the
|
||||||
|
with WithTag().
|
||||||
|
|
||||||
|
*/
|
||||||
|
package validator
|
145
vendor/gopkg.in/validator.v2/examplevalidate_test.go
generated
vendored
Normal file
145
vendor/gopkg.in/validator.v2/examplevalidate_test.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// Package validator implements value validations
|
||||||
|
//
|
||||||
|
// Copyright 2014 Roberto Teixeira <robteix@robteix.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package validator_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"gopkg.in/validator.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This example demonstrates a custom function to process template text.
|
||||||
|
// It installs the strings.Title function and uses it to
|
||||||
|
// Make Title Text Look Good In Our Template's Output.
|
||||||
|
func ExampleValidate() {
|
||||||
|
// First create a struct to be validated
|
||||||
|
// according to the validator tags.
|
||||||
|
type ValidateExample struct {
|
||||||
|
Name string `validate:"nonzero"`
|
||||||
|
Description string
|
||||||
|
Age int `validate:"min=18"`
|
||||||
|
Email string `validate:"regexp=^[0-9a-z]+@[0-9a-z]+(\\.[0-9a-z]+)+$"`
|
||||||
|
Address struct {
|
||||||
|
Street string `validate:"nonzero"`
|
||||||
|
City string `validate:"nonzero"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in some values
|
||||||
|
ve := ValidateExample{
|
||||||
|
Name: "Joe Doe", // valid as it's nonzero
|
||||||
|
Description: "", // valid no validation tag exists
|
||||||
|
Age: 17, // invalid as age is less than required 18
|
||||||
|
}
|
||||||
|
// invalid as Email won't match the regular expression
|
||||||
|
ve.Email = "@not.a.valid.email"
|
||||||
|
ve.Address.City = "Some City" // valid
|
||||||
|
ve.Address.Street = "" // invalid
|
||||||
|
|
||||||
|
err := validator.Validate(ve)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Println("Values are valid.")
|
||||||
|
} else {
|
||||||
|
errs := err.(validator.ErrorMap)
|
||||||
|
// See if Address was empty
|
||||||
|
if errs["Address.Street"][0] == validator.ErrZeroValue {
|
||||||
|
fmt.Println("Street cannot be empty.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through the list of fields and respective errors
|
||||||
|
fmt.Println("Invalid due to fields:")
|
||||||
|
|
||||||
|
// Here we have to sort the arrays to ensure map ordering does not
|
||||||
|
// fail our example, typically it's ok to just range through the err
|
||||||
|
// list when order is not important.
|
||||||
|
var errOuts []string
|
||||||
|
for f, e := range errs {
|
||||||
|
errOuts = append(errOuts, fmt.Sprintf("\t - %s (%v)\n", f, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Again this part is extraneous and you should not need this in real
|
||||||
|
// code.
|
||||||
|
sort.Strings(errOuts)
|
||||||
|
for _, str := range errOuts {
|
||||||
|
fmt.Print(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Street cannot be empty.
|
||||||
|
// Invalid due to fields:
|
||||||
|
// - Address.Street (zero value)
|
||||||
|
// - Age (less than min)
|
||||||
|
// - Email (regular expression mismatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example shows how to use the Valid helper
|
||||||
|
// function to validator any number of values
|
||||||
|
func ExampleValid() {
|
||||||
|
err := validator.Valid(42, "min=10,max=100,nonzero")
|
||||||
|
fmt.Printf("42: valid=%v, errs=%v\n", err == nil, err)
|
||||||
|
|
||||||
|
var ptr *int
|
||||||
|
if err := validator.Valid(ptr, "nonzero"); err != nil {
|
||||||
|
fmt.Println("ptr: Invalid nil pointer.")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validator.Valid("ABBA", "regexp=[ABC]*")
|
||||||
|
fmt.Printf("ABBA: valid=%v\n", err == nil)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 42: valid=true, errs=<nil>
|
||||||
|
// ptr: Invalid nil pointer.
|
||||||
|
// ABBA: valid=true
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example shows you how to change the tag name
|
||||||
|
func ExampleSetTag() {
|
||||||
|
type T struct {
|
||||||
|
A int `foo:"nonzero" bar:"min=10"`
|
||||||
|
}
|
||||||
|
t := T{5}
|
||||||
|
v := validator.NewValidator()
|
||||||
|
v.SetTag("foo")
|
||||||
|
err := v.Validate(t)
|
||||||
|
fmt.Printf("foo --> valid: %v, errs: %v\n", err == nil, err)
|
||||||
|
v.SetTag("bar")
|
||||||
|
err = v.Validate(t)
|
||||||
|
errs := err.(validator.ErrorMap)
|
||||||
|
fmt.Printf("bar --> valid: %v, errs: %v\n", err == nil, errs)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// foo --> valid: true, errs: <nil>
|
||||||
|
// bar --> valid: false, errs: A: less than min
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example shows you how to change the tag name
|
||||||
|
func ExampleWithTag() {
|
||||||
|
type T struct {
|
||||||
|
A int `foo:"nonzero" bar:"min=10"`
|
||||||
|
}
|
||||||
|
t := T{5}
|
||||||
|
err := validator.WithTag("foo").Validate(t)
|
||||||
|
fmt.Printf("foo --> valid: %v, errs: %v\n", err == nil, err)
|
||||||
|
err = validator.WithTag("bar").Validate(t)
|
||||||
|
fmt.Printf("bar --> valid: %v, errs: %v\n", err == nil, err)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// foo --> valid: true, errs: <nil>
|
||||||
|
// bar --> valid: false, errs: A: less than min
|
||||||
|
}
|
369
vendor/gopkg.in/validator.v2/validator.go
generated
vendored
Normal file
369
vendor/gopkg.in/validator.v2/validator.go
generated
vendored
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
// Package validator implements value validations
|
||||||
|
//
|
||||||
|
// Copyright 2014 Roberto Teixeira <robteix@robteix.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TextErr is an error that also implements the TextMarshaller interface for
|
||||||
|
// serializing out to various plain text encodings. Packages creating their
|
||||||
|
// own custom errors should use TextErr if they're intending to use serializing
|
||||||
|
// formats like json, msgpack etc.
|
||||||
|
type TextErr struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (t TextErr) Error() string {
|
||||||
|
return t.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the TextMarshaller
|
||||||
|
func (t TextErr) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(t.Err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrZeroValue is the error returned when variable has zero valud
|
||||||
|
// and nonzero was specified
|
||||||
|
ErrZeroValue = TextErr{errors.New("zero value")}
|
||||||
|
// ErrMin is the error returned when variable is less than mininum
|
||||||
|
// value specified
|
||||||
|
ErrMin = TextErr{errors.New("less than min")}
|
||||||
|
// ErrMax is the error returned when variable is more than
|
||||||
|
// maximum specified
|
||||||
|
ErrMax = TextErr{errors.New("greater than max")}
|
||||||
|
// ErrLen is the error returned when length is not equal to
|
||||||
|
// param specified
|
||||||
|
ErrLen = TextErr{errors.New("invalid length")}
|
||||||
|
// ErrRegexp is the error returned when the value does not
|
||||||
|
// match the provided regular expression parameter
|
||||||
|
ErrRegexp = TextErr{errors.New("regular expression mismatch")}
|
||||||
|
// ErrUnsupported is the error error returned when a validation rule
|
||||||
|
// is used with an unsupported variable type
|
||||||
|
ErrUnsupported = TextErr{errors.New("unsupported type")}
|
||||||
|
// ErrBadParameter is the error returned when an invalid parameter
|
||||||
|
// is provided to a validation rule (e.g. a string where an int was
|
||||||
|
// expected (max=foo,len=bar) or missing a parameter when one is required (len=))
|
||||||
|
ErrBadParameter = TextErr{errors.New("bad parameter")}
|
||||||
|
// ErrUnknownTag is the error returned when an unknown tag is found
|
||||||
|
ErrUnknownTag = TextErr{errors.New("unknown tag")}
|
||||||
|
// ErrInvalid is the error returned when variable is invalid
|
||||||
|
// (normally a nil pointer)
|
||||||
|
ErrInvalid = TextErr{errors.New("invalid value")}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorMap is a map which contains all errors from validating a struct.
|
||||||
|
type ErrorMap map[string]ErrorArray
|
||||||
|
|
||||||
|
// ErrorMap implements the Error interface so we can check error against nil.
|
||||||
|
// The returned error is if existent the first error which was added to the map.
|
||||||
|
func (err ErrorMap) Error() string {
|
||||||
|
for k, errs := range err {
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Sprintf("%s: %s", k, errs.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorArray is a slice of errors returned by the Validate function.
|
||||||
|
type ErrorArray []error
|
||||||
|
|
||||||
|
// ErrorArray implements the Error interface and returns the first error as
|
||||||
|
// string if existent.
|
||||||
|
func (err ErrorArray) Error() string {
|
||||||
|
if len(err) > 0 {
|
||||||
|
return err[0].Error()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidationFunc is a function that receives the value of a
|
||||||
|
// field and a parameter used for the respective validation tag.
|
||||||
|
type ValidationFunc func(v interface{}, param string) error
|
||||||
|
|
||||||
|
// Validator implements a validator
|
||||||
|
type Validator struct {
|
||||||
|
// Tag name being used.
|
||||||
|
tagName string
|
||||||
|
// validationFuncs is a map of ValidationFuncs indexed
|
||||||
|
// by their name.
|
||||||
|
validationFuncs map[string]ValidationFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper validator so users can use the
|
||||||
|
// functions directly from the package
|
||||||
|
var defaultValidator = NewValidator()
|
||||||
|
|
||||||
|
// NewValidator creates a new Validator
|
||||||
|
func NewValidator() *Validator {
|
||||||
|
return &Validator{
|
||||||
|
tagName: "validate",
|
||||||
|
validationFuncs: map[string]ValidationFunc{
|
||||||
|
"nonzero": nonzero,
|
||||||
|
"len": length,
|
||||||
|
"min": min,
|
||||||
|
"max": max,
|
||||||
|
"regexp": regex,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTag allows you to change the tag name used in structs
|
||||||
|
func SetTag(tag string) {
|
||||||
|
defaultValidator.SetTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTag allows you to change the tag name used in structs
|
||||||
|
func (mv *Validator) SetTag(tag string) {
|
||||||
|
mv.tagName = tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTag creates a new Validator with the new tag name. It is
|
||||||
|
// useful to chain-call with Validate so we don't change the tag
|
||||||
|
// name permanently: validator.WithTag("foo").Validate(t)
|
||||||
|
func WithTag(tag string) *Validator {
|
||||||
|
return defaultValidator.WithTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTag creates a new Validator with the new tag name. It is
|
||||||
|
// useful to chain-call with Validate so we don't change the tag
|
||||||
|
// name permanently: validator.WithTag("foo").Validate(t)
|
||||||
|
func (mv *Validator) WithTag(tag string) *Validator {
|
||||||
|
v := mv.copy()
|
||||||
|
v.SetTag(tag)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a validator
|
||||||
|
func (mv *Validator) copy() *Validator {
|
||||||
|
newFuncs := map[string]ValidationFunc{}
|
||||||
|
for k, f := range mv.validationFuncs {
|
||||||
|
newFuncs[k] = f
|
||||||
|
}
|
||||||
|
return &Validator{
|
||||||
|
tagName: mv.tagName,
|
||||||
|
validationFuncs: newFuncs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValidationFunc sets the function to be used for a given
|
||||||
|
// validation constraint. Calling this function with nil vf
|
||||||
|
// is the same as removing the constraint function from the list.
|
||||||
|
func SetValidationFunc(name string, vf ValidationFunc) error {
|
||||||
|
return defaultValidator.SetValidationFunc(name, vf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValidationFunc sets the function to be used for a given
|
||||||
|
// validation constraint. Calling this function with nil vf
|
||||||
|
// is the same as removing the constraint function from the list.
|
||||||
|
func (mv *Validator) SetValidationFunc(name string, vf ValidationFunc) error {
|
||||||
|
if name == "" {
|
||||||
|
return errors.New("name cannot be empty")
|
||||||
|
}
|
||||||
|
if vf == nil {
|
||||||
|
delete(mv.validationFuncs, name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
mv.validationFuncs[name] = vf
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the fields of a struct based
|
||||||
|
// on 'validator' tags and returns errors found indexed
|
||||||
|
// by the field name.
|
||||||
|
func Validate(v interface{}) error {
|
||||||
|
return defaultValidator.Validate(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the fields of a struct based
|
||||||
|
// on 'validator' tags and returns errors found indexed
|
||||||
|
// by the field name.
|
||||||
|
func (mv *Validator) Validate(v interface{}) error {
|
||||||
|
sv := reflect.ValueOf(v)
|
||||||
|
st := reflect.TypeOf(v)
|
||||||
|
if sv.Kind() == reflect.Ptr && !sv.IsNil() {
|
||||||
|
return mv.Validate(sv.Elem().Interface())
|
||||||
|
}
|
||||||
|
if sv.Kind() != reflect.Struct && sv.Kind() != reflect.Interface {
|
||||||
|
return ErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
nfields := sv.NumField()
|
||||||
|
m := make(ErrorMap)
|
||||||
|
for i := 0; i < nfields; i++ {
|
||||||
|
fname := st.Field(i).Name
|
||||||
|
if !unicode.IsUpper(rune(fname[0])) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f := sv.Field(i)
|
||||||
|
// deal with pointers
|
||||||
|
for f.Kind() == reflect.Ptr && !f.IsNil() {
|
||||||
|
f = f.Elem()
|
||||||
|
}
|
||||||
|
tag := st.Field(i).Tag.Get(mv.tagName)
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var errs ErrorArray
|
||||||
|
|
||||||
|
if tag != "" {
|
||||||
|
err := mv.Valid(f.Interface(), tag)
|
||||||
|
if errors, ok := err.(ErrorArray); ok {
|
||||||
|
errs = errors
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
errs = ErrorArray{err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mv.deepValidateCollection(f, fname, m) // no-op if field is not a struct, interface, array, slice or map
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
m[st.Field(i).Name] = errs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m) > 0 {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mv *Validator) deepValidateCollection(f reflect.Value, fname string, m ErrorMap) {
|
||||||
|
switch f.Kind() {
|
||||||
|
case reflect.Struct, reflect.Interface, reflect.Ptr:
|
||||||
|
e := mv.Validate(f.Interface())
|
||||||
|
if e, ok := e.(ErrorMap); ok && len(e) > 0 {
|
||||||
|
for j, k := range e {
|
||||||
|
m[fname+"."+j] = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
for i := 0; i < f.Len(); i++ {
|
||||||
|
mv.deepValidateCollection(f.Index(i), fmt.Sprintf("%s[%d]", fname, i), m)
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
for _, key := range f.MapKeys() {
|
||||||
|
mv.deepValidateCollection(key, fmt.Sprintf("%s[%+v](key)", fname, key.Interface()), m) // validate the map key
|
||||||
|
value := f.MapIndex(key)
|
||||||
|
mv.deepValidateCollection(value, fmt.Sprintf("%s[%+v](value)", fname, key.Interface()), m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid validates a value based on the provided
|
||||||
|
// tags and returns errors found or nil.
|
||||||
|
func Valid(val interface{}, tags string) error {
|
||||||
|
return defaultValidator.Valid(val, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid validates a value based on the provided
|
||||||
|
// tags and returns errors found or nil.
|
||||||
|
func (mv *Validator) Valid(val interface{}, tags string) error {
|
||||||
|
if tags == "-" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
if v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||||
|
return mv.Valid(v.Elem().Interface(), tags)
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Invalid:
|
||||||
|
err = mv.validateVar(nil, tags)
|
||||||
|
default:
|
||||||
|
err = mv.validateVar(val, tags)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateVar validates one single variable
|
||||||
|
func (mv *Validator) validateVar(v interface{}, tag string) error {
|
||||||
|
tags, err := mv.parseTags(tag)
|
||||||
|
if err != nil {
|
||||||
|
// unknown tag found, give up.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
errs := make(ErrorArray, 0, len(tags))
|
||||||
|
for _, t := range tags {
|
||||||
|
if err := t.Fn(v, t.Param); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag represents one of the tag items
|
||||||
|
type tag struct {
|
||||||
|
Name string // name of the tag
|
||||||
|
Fn ValidationFunc // validation function to call
|
||||||
|
Param string // parameter to send to the validation function
|
||||||
|
}
|
||||||
|
|
||||||
|
// separate by no escaped commas
|
||||||
|
var sepPattern *regexp.Regexp = regexp.MustCompile(`((?:^|[^\\])(?:\\\\)*),`)
|
||||||
|
|
||||||
|
func splitUnescapedComma(str string) []string {
|
||||||
|
ret := []string{}
|
||||||
|
indexes := sepPattern.FindAllStringIndex(str, -1)
|
||||||
|
last := 0
|
||||||
|
for _, is := range indexes {
|
||||||
|
ret = append(ret, str[last:is[1]-1])
|
||||||
|
last = is[1]
|
||||||
|
}
|
||||||
|
ret = append(ret, str[last:])
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseTags parses all individual tags found within a struct tag.
|
||||||
|
func (mv *Validator) parseTags(t string) ([]tag, error) {
|
||||||
|
tl := splitUnescapedComma(t)
|
||||||
|
tags := make([]tag, 0, len(tl))
|
||||||
|
for _, i := range tl {
|
||||||
|
i = strings.Replace(i, `\,`, ",", -1)
|
||||||
|
tg := tag{}
|
||||||
|
v := strings.SplitN(i, "=", 2)
|
||||||
|
tg.Name = strings.Trim(v[0], " ")
|
||||||
|
if tg.Name == "" {
|
||||||
|
return []tag{}, ErrUnknownTag
|
||||||
|
}
|
||||||
|
if len(v) > 1 {
|
||||||
|
tg.Param = strings.Trim(v[1], " ")
|
||||||
|
}
|
||||||
|
var found bool
|
||||||
|
if tg.Fn, found = mv.validationFuncs[tg.Name]; !found {
|
||||||
|
return []tag{}, ErrUnknownTag
|
||||||
|
}
|
||||||
|
tags = append(tags, tg)
|
||||||
|
|
||||||
|
}
|
||||||
|
return tags, nil
|
||||||
|
}
|
517
vendor/gopkg.in/validator.v2/validator_test.go
generated
vendored
Normal file
517
vendor/gopkg.in/validator.v2/validator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,517 @@
|
||||||
|
// Package validator implements value validations
|
||||||
|
//
|
||||||
|
// Copyright 2014 Roberto Teixeira <robteix@robteix.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package validator_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
"gopkg.in/validator.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test(t *testing.T) {
|
||||||
|
TestingT(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MySuite struct{}
|
||||||
|
|
||||||
|
var _ = Suite(&MySuite{})
|
||||||
|
|
||||||
|
type Simple struct {
|
||||||
|
A int `validate:"min=10"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type I interface {
|
||||||
|
Foo() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Impl struct {
|
||||||
|
F string `validate:"len=3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Impl) Foo() string {
|
||||||
|
return this.F
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestStruct struct {
|
||||||
|
A int `validate:"nonzero"`
|
||||||
|
B string `validate:"len=8,min=6,max=4"`
|
||||||
|
Sub struct {
|
||||||
|
A int `validate:"nonzero"`
|
||||||
|
B string
|
||||||
|
C float64 `validate:"nonzero,min=1"`
|
||||||
|
D *string `validate:"nonzero"`
|
||||||
|
}
|
||||||
|
D *Simple `validate:"nonzero"`
|
||||||
|
E I `validate:nonzero`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidate(c *C) {
|
||||||
|
t := TestStruct{
|
||||||
|
A: 0,
|
||||||
|
B: "12345",
|
||||||
|
}
|
||||||
|
t.Sub.A = 1
|
||||||
|
t.Sub.B = ""
|
||||||
|
t.Sub.C = 0.0
|
||||||
|
t.D = &Simple{10}
|
||||||
|
t.E = &Impl{"hello"}
|
||||||
|
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrZeroValue)
|
||||||
|
c.Assert(errs["B"], HasError, validator.ErrLen)
|
||||||
|
c.Assert(errs["B"], HasError, validator.ErrMin)
|
||||||
|
c.Assert(errs["B"], HasError, validator.ErrMax)
|
||||||
|
c.Assert(errs["Sub.A"], HasLen, 0)
|
||||||
|
c.Assert(errs["Sub.B"], HasLen, 0)
|
||||||
|
c.Assert(errs["Sub.C"], HasLen, 2)
|
||||||
|
c.Assert(errs["Sub.D"], HasError, validator.ErrZeroValue)
|
||||||
|
c.Assert(errs["E.F"], HasError, validator.ErrLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidSlice(c *C) {
|
||||||
|
s := make([]int, 0, 10)
|
||||||
|
err := validator.Valid(s, "nonzero")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrZeroValue)
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
s = append(s, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validator.Valid(s, "min=11,max=5,len=9,nonzero")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok = err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMin)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMax)
|
||||||
|
c.Assert(errs, HasError, validator.ErrLen)
|
||||||
|
c.Assert(errs, Not(HasError), validator.ErrZeroValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidMap(c *C) {
|
||||||
|
m := make(map[string]string)
|
||||||
|
err := validator.Valid(m, "nonzero")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrZeroValue)
|
||||||
|
|
||||||
|
err = validator.Valid(m, "min=1")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok = err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMin)
|
||||||
|
|
||||||
|
m = map[string]string{"A": "a", "B": "a"}
|
||||||
|
err = validator.Valid(m, "max=1")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok = err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMax)
|
||||||
|
|
||||||
|
err = validator.Valid(m, "min=2, max=5")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
m = map[string]string{
|
||||||
|
"1": "a",
|
||||||
|
"2": "b",
|
||||||
|
"3": "c",
|
||||||
|
"4": "d",
|
||||||
|
"5": "e",
|
||||||
|
}
|
||||||
|
err = validator.Valid(m, "len=4,min=6,max=1,nonzero")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok = err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrLen)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMin)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMax)
|
||||||
|
c.Assert(errs, Not(HasError), validator.ErrZeroValue)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidFloat(c *C) {
|
||||||
|
err := validator.Valid(12.34, "nonzero")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
err = validator.Valid(0.0, "nonzero")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrZeroValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidInt(c *C) {
|
||||||
|
i := 123
|
||||||
|
err := validator.Valid(i, "nonzero")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
err = validator.Valid(i, "min=1")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
err = validator.Valid(i, "min=124, max=122")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMin)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMax)
|
||||||
|
|
||||||
|
err = validator.Valid(i, "max=10")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok = err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrMax)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidString(c *C) {
|
||||||
|
s := "test1234"
|
||||||
|
err := validator.Valid(s, "len=8")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
err = validator.Valid(s, "len=0")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasError, validator.ErrLen)
|
||||||
|
|
||||||
|
err = validator.Valid(s, "regexp=^[tes]{4}.*")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
err = validator.Valid(s, "regexp=^.*[0-9]{5}$")
|
||||||
|
c.Assert(errs, NotNil)
|
||||||
|
|
||||||
|
err = validator.Valid("", "nonzero,len=3,max=1")
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok = err.(validator.ErrorArray)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasLen, 2)
|
||||||
|
c.Assert(errs, HasError, validator.ErrZeroValue)
|
||||||
|
c.Assert(errs, HasError, validator.ErrLen)
|
||||||
|
c.Assert(errs, Not(HasError), validator.ErrMax)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidateStructVar(c *C) {
|
||||||
|
// just verifies that a the given val is a struct
|
||||||
|
validator.SetValidationFunc("struct", func(val interface{}, _ string) error {
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
if v.Kind() == reflect.Struct {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return validator.ErrUnsupported
|
||||||
|
})
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
A int
|
||||||
|
}
|
||||||
|
err := validator.Valid(test{}, "struct")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
type test2 struct {
|
||||||
|
B int
|
||||||
|
}
|
||||||
|
type test1 struct {
|
||||||
|
A test2 `validate:"struct"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validator.Validate(test1{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
type test4 struct {
|
||||||
|
B int `validate:"foo"`
|
||||||
|
}
|
||||||
|
type test3 struct {
|
||||||
|
A test4
|
||||||
|
}
|
||||||
|
err = validator.Validate(test3{})
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["A.B"], HasError, validator.ErrUnknownTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidatePointerVar(c *C) {
|
||||||
|
// just verifies that a the given val is a struct
|
||||||
|
validator.SetValidationFunc("struct", func(val interface{}, _ string) error {
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
if v.Kind() == reflect.Struct {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return validator.ErrUnsupported
|
||||||
|
})
|
||||||
|
validator.SetValidationFunc("nil", func(val interface{}, _ string) error {
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
if v.IsNil() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return validator.ErrUnsupported
|
||||||
|
})
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
A int
|
||||||
|
}
|
||||||
|
err := validator.Valid(&test{}, "struct")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
type test2 struct {
|
||||||
|
B int
|
||||||
|
}
|
||||||
|
type test1 struct {
|
||||||
|
A *test2 `validate:"struct"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validator.Validate(&test1{&test2{}})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
type test4 struct {
|
||||||
|
B int `validate:"foo"`
|
||||||
|
}
|
||||||
|
type test3 struct {
|
||||||
|
A test4
|
||||||
|
}
|
||||||
|
err = validator.Validate(&test3{})
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["A.B"], HasError, validator.ErrUnknownTag)
|
||||||
|
|
||||||
|
err = validator.Valid((*test)(nil), "nil")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
type test5 struct {
|
||||||
|
A *test2 `validate:"nil"`
|
||||||
|
}
|
||||||
|
err = validator.Validate(&test5{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
type test6 struct {
|
||||||
|
A *test2 `validate:"nonzero"`
|
||||||
|
}
|
||||||
|
err = validator.Validate(&test6{})
|
||||||
|
errs, ok = err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrZeroValue)
|
||||||
|
|
||||||
|
err = validator.Validate(&test6{&test2{}})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidateOmittedStructVar(c *C) {
|
||||||
|
type test2 struct {
|
||||||
|
B int `validate:"min=1"`
|
||||||
|
}
|
||||||
|
type test1 struct {
|
||||||
|
A test2 `validate:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
t := test1{}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
errs := validator.Valid(test2{}, "-")
|
||||||
|
c.Assert(errs, IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestUnknownTag(c *C) {
|
||||||
|
type test struct {
|
||||||
|
A int `validate:"foo"`
|
||||||
|
}
|
||||||
|
t := test{}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasLen, 1)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrUnknownTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidateStructWithSlice(c *C) {
|
||||||
|
type test2 struct {
|
||||||
|
Num int `validate:"max=2"`
|
||||||
|
String string `validate:"nonzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
Slices []test2 `validate:"len=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
t := test{
|
||||||
|
Slices: []test2{{
|
||||||
|
Num: 6,
|
||||||
|
String: "foo",
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["Slices[0].Num"], HasError, validator.ErrMax)
|
||||||
|
c.Assert(errs["Slices[0].String"], IsNil) // sanity check
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidateStructWithNestedSlice(c *C) {
|
||||||
|
type test2 struct {
|
||||||
|
Num int `validate:"max=2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
Slices [][]test2
|
||||||
|
}
|
||||||
|
|
||||||
|
t := test{
|
||||||
|
Slices: [][]test2{{{Num: 6}}},
|
||||||
|
}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["Slices[0][0].Num"], HasError, validator.ErrMax)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestValidateStructWithMap(c *C) {
|
||||||
|
type test2 struct {
|
||||||
|
Num int `validate:"max=2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
Map map[string]test2
|
||||||
|
StructKeyMap map[test2]test2
|
||||||
|
}
|
||||||
|
|
||||||
|
t := test{
|
||||||
|
Map: map[string]test2{
|
||||||
|
"hello": {Num: 6},
|
||||||
|
},
|
||||||
|
StructKeyMap: map[test2]test2{
|
||||||
|
{Num: 3}: {Num: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
|
||||||
|
c.Assert(errs["Map[hello](value).Num"], HasError, validator.ErrMax)
|
||||||
|
c.Assert(errs["StructKeyMap[{Num:3}](key).Num"], HasError, validator.ErrMax)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestUnsupported(c *C) {
|
||||||
|
type test struct {
|
||||||
|
A int `validate:"regexp=a.*b"`
|
||||||
|
B float64 `validate:"regexp=.*"`
|
||||||
|
}
|
||||||
|
t := test{}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasLen, 2)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrUnsupported)
|
||||||
|
c.Assert(errs["B"], HasError, validator.ErrUnsupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestBadParameter(c *C) {
|
||||||
|
type test struct {
|
||||||
|
A string `validate:"min="`
|
||||||
|
B string `validate:"len=="`
|
||||||
|
C string `validate:"max=foo"`
|
||||||
|
}
|
||||||
|
t := test{}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasLen, 3)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrBadParameter)
|
||||||
|
c.Assert(errs["B"], HasError, validator.ErrBadParameter)
|
||||||
|
c.Assert(errs["C"], HasError, validator.ErrBadParameter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestCopy(c *C) {
|
||||||
|
v := validator.NewValidator()
|
||||||
|
// WithTag calls copy, so we just copy the validator with the same tag
|
||||||
|
v2 := v.WithTag("validate")
|
||||||
|
// now we add a custom func only to the second one, it shouldn't get added
|
||||||
|
// to the first
|
||||||
|
v2.SetValidationFunc("custom", func(_ interface{}, _ string) error { return nil })
|
||||||
|
type test struct {
|
||||||
|
A string `validate:"custom"`
|
||||||
|
}
|
||||||
|
err := v2.Validate(test{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
err = v.Validate(test{})
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs, HasLen, 1)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrUnknownTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MySuite) TestTagEscape(c *C) {
|
||||||
|
type test struct {
|
||||||
|
A string `validate:"min=0,regexp=^a{3\\,10}"`
|
||||||
|
}
|
||||||
|
t := test{"aaaa"}
|
||||||
|
err := validator.Validate(t)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
|
t2 := test{"aa"}
|
||||||
|
err = validator.Validate(t2)
|
||||||
|
c.Assert(err, NotNil)
|
||||||
|
errs, ok := err.(validator.ErrorMap)
|
||||||
|
c.Assert(ok, Equals, true)
|
||||||
|
c.Assert(errs["A"], HasError, validator.ErrRegexp)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hasErrorChecker struct {
|
||||||
|
*CheckerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *hasErrorChecker) Check(params []interface{}, names []string) (bool, string) {
|
||||||
|
var (
|
||||||
|
ok bool
|
||||||
|
slice []error
|
||||||
|
value error
|
||||||
|
)
|
||||||
|
slice, ok = params[0].(validator.ErrorArray)
|
||||||
|
if !ok {
|
||||||
|
return false, "First parameter is not an Errorarray"
|
||||||
|
}
|
||||||
|
value, ok = params[1].(error)
|
||||||
|
if !ok {
|
||||||
|
return false, "Second parameter is not an error"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range slice {
|
||||||
|
if v == value {
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *hasErrorChecker) Info() *CheckerInfo {
|
||||||
|
return c.CheckerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
var HasError = &hasErrorChecker{&CheckerInfo{Name: "HasError", Params: []string{"HasError", "expected to contain"}}}
|
206
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
206
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
|
@ -1,13 +1,201 @@
|
||||||
Copyright 2011-2016 Canonical Ltd.
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
2
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
2
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
|
@ -48,6 +48,8 @@ The yaml package is licensed under the Apache License 2.0. Please see the LICENS
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
Some more examples can be found in the "examples" folder.
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
10
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
10
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
|
@ -120,7 +120,6 @@ func (p *parser) parse() *node {
|
||||||
default:
|
default:
|
||||||
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
|
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) node(kind int) *node {
|
func (p *parser) node(kind int) *node {
|
||||||
|
@ -191,6 +190,7 @@ type decoder struct {
|
||||||
aliases map[string]bool
|
aliases map[string]bool
|
||||||
mapType reflect.Type
|
mapType reflect.Type
|
||||||
terrors []string
|
terrors []string
|
||||||
|
strict bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -200,8 +200,8 @@ var (
|
||||||
ifaceType = defaultMapType.Elem()
|
ifaceType = defaultMapType.Elem()
|
||||||
)
|
)
|
||||||
|
|
||||||
func newDecoder() *decoder {
|
func newDecoder(strict bool) *decoder {
|
||||||
d := &decoder{mapType: defaultMapType}
|
d := &decoder{mapType: defaultMapType, strict: strict}
|
||||||
d.aliases = make(map[string]bool)
|
d.aliases = make(map[string]bool)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
|
||||||
//
|
//
|
||||||
// If n holds a null value, prepare returns before doing anything.
|
// If n holds a null value, prepare returns before doing anything.
|
||||||
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
||||||
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "") {
|
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "" && n.implicit) {
|
||||||
return out, false, false
|
return out, false, false
|
||||||
}
|
}
|
||||||
again := true
|
again := true
|
||||||
|
@ -640,6 +640,8 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
|
||||||
value := reflect.New(elemType).Elem()
|
value := reflect.New(elemType).Elem()
|
||||||
d.unmarshal(n.children[i+1], value)
|
d.unmarshal(n.children[i+1], value)
|
||||||
inlineMap.SetMapIndex(name, value)
|
inlineMap.SetMapIndex(name, value)
|
||||||
|
} else if d.strict {
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", n.line+1, name.String(), out.Type()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
33
vendor/gopkg.in/yaml.v2/decode_test.go
generated
vendored
33
vendor/gopkg.in/yaml.v2/decode_test.go
generated
vendored
|
@ -405,6 +405,12 @@ var unmarshalTests = []struct {
|
||||||
map[string]interface{}{"v": 1},
|
map[string]interface{}{"v": 1},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Non-specific tag (Issue #75)
|
||||||
|
{
|
||||||
|
"v: ! test",
|
||||||
|
map[string]interface{}{"v": "test"},
|
||||||
|
},
|
||||||
|
|
||||||
// Anchors and aliases.
|
// Anchors and aliases.
|
||||||
{
|
{
|
||||||
"a: &x 1\nb: &y 2\nc: *x\nd: *y\n",
|
"a: &x 1\nb: &y 2\nc: *x\nd: *y\n",
|
||||||
|
@ -551,7 +557,7 @@ var unmarshalTests = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"a: 2015-02-24T18:19:39Z\n",
|
"a: 2015-02-24T18:19:39Z\n",
|
||||||
map[string]time.Time{"a": time.Unix(1424801979, 0)},
|
map[string]time.Time{"a": time.Unix(1424801979, 0).In(time.UTC)},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Encode empty lists as zero-length slices.
|
// Encode empty lists as zero-length slices.
|
||||||
|
@ -581,6 +587,15 @@ var unmarshalTests = []struct {
|
||||||
"\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \xd8=\xdf\xd4\x00\n",
|
"\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \xd8=\xdf\xd4\x00\n",
|
||||||
M{"ñoño": "very yes 🟔"},
|
M{"ñoño": "very yes 🟔"},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// YAML Float regex shouldn't match this
|
||||||
|
{
|
||||||
|
"a: 123456e1\n",
|
||||||
|
M{"a": "123456e1"},
|
||||||
|
}, {
|
||||||
|
"a: 123456E1\n",
|
||||||
|
M{"a": "123456E1"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type M map[interface{}]interface{}
|
type M map[interface{}]interface{}
|
||||||
|
@ -595,7 +610,8 @@ type inlineC struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *S) TestUnmarshal(c *C) {
|
func (s *S) TestUnmarshal(c *C) {
|
||||||
for _, item := range unmarshalTests {
|
for i, item := range unmarshalTests {
|
||||||
|
c.Logf("test %d: %q", i, item.data)
|
||||||
t := reflect.ValueOf(item.value).Type()
|
t := reflect.ValueOf(item.value).Type()
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
|
@ -639,6 +655,7 @@ var unmarshalErrorTests = []struct {
|
||||||
{"a: !!binary ==", "yaml: !!binary value contains invalid base64 data"},
|
{"a: !!binary ==", "yaml: !!binary value contains invalid base64 data"},
|
||||||
{"{[.]}", `yaml: invalid map key: \[\]interface \{\}\{"\."\}`},
|
{"{[.]}", `yaml: invalid map key: \[\]interface \{\}\{"\."\}`},
|
||||||
{"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`},
|
{"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`},
|
||||||
|
{"%TAG !%79! tag:yaml.org,2002:\n---\nv: !%79!int '1'", "yaml: did not find expected whitespace"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *S) TestUnmarshalErrors(c *C) {
|
func (s *S) TestUnmarshalErrors(c *C) {
|
||||||
|
@ -660,6 +677,7 @@ var unmarshalerTests = []struct {
|
||||||
{`_: BAR!`, "!!str", "BAR!"},
|
{`_: BAR!`, "!!str", "BAR!"},
|
||||||
{`_: "BAR!"`, "!!str", "BAR!"},
|
{`_: "BAR!"`, "!!str", "BAR!"},
|
||||||
{"_: !!foo 'BAR!'", "!!foo", "BAR!"},
|
{"_: !!foo 'BAR!'", "!!foo", "BAR!"},
|
||||||
|
{`_: ""`, "!!str", ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
var unmarshalerResult = map[int]error{}
|
var unmarshalerResult = map[int]error{}
|
||||||
|
@ -958,6 +976,17 @@ func (s *S) TestUnmarshalSliceOnPreset(c *C) {
|
||||||
c.Assert(v.A, DeepEquals, []int{2})
|
c.Assert(v.A, DeepEquals, []int{2})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalStrict(c *C) {
|
||||||
|
v := struct{ A, B int }{}
|
||||||
|
|
||||||
|
err := yaml.UnmarshalStrict([]byte("a: 1\nb: 2"), &v)
|
||||||
|
c.Check(err, IsNil)
|
||||||
|
err = yaml.Unmarshal([]byte("a: 1\nb: 2\nc: 3"), &v)
|
||||||
|
c.Check(err, IsNil)
|
||||||
|
err = yaml.UnmarshalStrict([]byte("a: 1\nb: 2\nc: 3"), &v)
|
||||||
|
c.Check(err, ErrorMatches, "yaml: unmarshal errors:\n line 1: field c not found in struct struct { A int; B int }")
|
||||||
|
}
|
||||||
|
|
||||||
//var data []byte
|
//var data []byte
|
||||||
//func init() {
|
//func init() {
|
||||||
// var err error
|
// var err error
|
||||||
|
|
9
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
9
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
|
@ -666,7 +666,6 @@ func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
|
||||||
return yaml_emitter_set_emitter_error(emitter,
|
return yaml_emitter_set_emitter_error(emitter,
|
||||||
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
|
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expect ALIAS.
|
// Expect ALIAS.
|
||||||
|
@ -995,7 +994,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
||||||
break_space = false
|
break_space = false
|
||||||
space_break = false
|
space_break = false
|
||||||
|
|
||||||
preceeded_by_whitespace = false
|
preceded_by_whitespace = false
|
||||||
followed_by_whitespace = false
|
followed_by_whitespace = false
|
||||||
previous_space = false
|
previous_space = false
|
||||||
previous_break = false
|
previous_break = false
|
||||||
|
@ -1017,7 +1016,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
||||||
flow_indicators = true
|
flow_indicators = true
|
||||||
}
|
}
|
||||||
|
|
||||||
preceeded_by_whitespace = true
|
preceded_by_whitespace = true
|
||||||
for i, w := 0, 0; i < len(value); i += w {
|
for i, w := 0, 0; i < len(value); i += w {
|
||||||
w = width(value[i])
|
w = width(value[i])
|
||||||
followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
|
followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w)
|
||||||
|
@ -1048,7 +1047,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
||||||
block_indicators = true
|
block_indicators = true
|
||||||
}
|
}
|
||||||
case '#':
|
case '#':
|
||||||
if preceeded_by_whitespace {
|
if preceded_by_whitespace {
|
||||||
flow_indicators = true
|
flow_indicators = true
|
||||||
block_indicators = true
|
block_indicators = true
|
||||||
}
|
}
|
||||||
|
@ -1089,7 +1088,7 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
|
// [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition.
|
||||||
preceeded_by_whitespace = is_blankz(value, i)
|
preceded_by_whitespace = is_blankz(value, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
emitter.scalar_data.multiline = line_breaks
|
emitter.scalar_data.multiline = line_breaks
|
||||||
|
|
41
vendor/gopkg.in/yaml.v2/example_embedded_test.go
generated
vendored
Normal file
41
vendor/gopkg.in/yaml.v2/example_embedded_test.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An example showing how to unmarshal embedded
|
||||||
|
// structs from YAML.
|
||||||
|
|
||||||
|
type StructA struct {
|
||||||
|
A string `yaml:"a"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructB struct {
|
||||||
|
// Embedded structs are not treated as embedded in YAML by default. To do that,
|
||||||
|
// add the ",inline" annotation below
|
||||||
|
StructA `yaml:",inline"`
|
||||||
|
B string `yaml:"b"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = `
|
||||||
|
a: a string from struct A
|
||||||
|
b: a string from struct B
|
||||||
|
`
|
||||||
|
|
||||||
|
func ExampleUnmarshal_embedded() {
|
||||||
|
var b StructB
|
||||||
|
|
||||||
|
err := yaml.Unmarshal([]byte(data), &b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("cannot unmarshal data: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(b.A)
|
||||||
|
fmt.Println(b.B)
|
||||||
|
// Output:
|
||||||
|
// a string from struct A
|
||||||
|
// a string from struct B
|
||||||
|
}
|
1
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
1
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
|
@ -166,7 +166,6 @@ func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool
|
||||||
default:
|
default:
|
||||||
panic("invalid parser state")
|
panic("invalid parser state")
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the production:
|
// Parse the production:
|
||||||
|
|
5
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
5
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
|
@ -3,6 +3,7 @@ package yaml
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"math"
|
"math"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -80,6 +81,8 @@ func resolvableTag(tag string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
|
||||||
|
|
||||||
func resolve(tag string, in string) (rtag string, out interface{}) {
|
func resolve(tag string, in string) (rtag string, out interface{}) {
|
||||||
if !resolvableTag(tag) {
|
if !resolvableTag(tag) {
|
||||||
return tag, in
|
return tag, in
|
||||||
|
@ -135,10 +138,12 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return yaml_INT_TAG, uintv
|
return yaml_INT_TAG, uintv
|
||||||
}
|
}
|
||||||
|
if yamlStyleFloat.MatchString(plain) {
|
||||||
floatv, err := strconv.ParseFloat(plain, 64)
|
floatv, err := strconv.ParseFloat(plain, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return yaml_FLOAT_TAG, floatv
|
return yaml_FLOAT_TAG, floatv
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if strings.HasPrefix(plain, "0b") {
|
if strings.HasPrefix(plain, "0b") {
|
||||||
intv, err := strconv.ParseInt(plain[2:], 2, 64)
|
intv, err := strconv.ParseInt(plain[2:], 2, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
11
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
11
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
|
@ -9,7 +9,7 @@ import (
|
||||||
// ************
|
// ************
|
||||||
//
|
//
|
||||||
// The following notes assume that you are familiar with the YAML specification
|
// The following notes assume that you are familiar with the YAML specification
|
||||||
// (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in
|
// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in
|
||||||
// some cases we are less restrictive that it requires.
|
// some cases we are less restrictive that it requires.
|
||||||
//
|
//
|
||||||
// The process of transforming a YAML stream into a sequence of events is
|
// The process of transforming a YAML stream into a sequence of events is
|
||||||
|
@ -611,7 +611,7 @@ func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, co
|
||||||
if directive {
|
if directive {
|
||||||
context = "while parsing a %TAG directive"
|
context = "while parsing a %TAG directive"
|
||||||
}
|
}
|
||||||
return yaml_parser_set_scanner_error(parser, context, context_mark, "did not find URI escaped octet")
|
return yaml_parser_set_scanner_error(parser, context, context_mark, problem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func trace(args ...interface{}) func() {
|
func trace(args ...interface{}) func() {
|
||||||
|
@ -1944,7 +1944,7 @@ func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_ma
|
||||||
} else {
|
} else {
|
||||||
// It's either the '!' tag or not really a tag handle. If it's a %TAG
|
// It's either the '!' tag or not really a tag handle. If it's a %TAG
|
||||||
// directive, it's an error. If it's a tag token, it must be a part of URI.
|
// directive, it's an error. If it's a tag token, it must be a part of URI.
|
||||||
if directive && !(s[0] == '!' && s[1] == 0) {
|
if directive && string(s) != "!" {
|
||||||
yaml_parser_set_scanner_tag_error(parser, directive,
|
yaml_parser_set_scanner_tag_error(parser, directive,
|
||||||
start_mark, "did not find expected '!'")
|
start_mark, "did not find expected '!'")
|
||||||
return false
|
return false
|
||||||
|
@ -1959,6 +1959,7 @@ func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_ma
|
||||||
func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
|
func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool {
|
||||||
//size_t length = head ? strlen((char *)head) : 0
|
//size_t length = head ? strlen((char *)head) : 0
|
||||||
var s []byte
|
var s []byte
|
||||||
|
hasTag := len(head) > 0
|
||||||
|
|
||||||
// Copy the head if needed.
|
// Copy the head if needed.
|
||||||
//
|
//
|
||||||
|
@ -2000,10 +2001,10 @@ func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte
|
||||||
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
hasTag = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the tag is non-empty.
|
if !hasTag {
|
||||||
if len(s) == 0 {
|
|
||||||
yaml_parser_set_scanner_tag_error(parser, directive,
|
yaml_parser_set_scanner_tag_error(parser, directive,
|
||||||
start_mark, "did not find expected tag URI")
|
start_mark, "did not find expected tag URI")
|
||||||
return false
|
return false
|
||||||
|
|
13
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
13
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
|
@ -77,8 +77,19 @@ type Marshaler interface {
|
||||||
// supported tag options.
|
// supported tag options.
|
||||||
//
|
//
|
||||||
func Unmarshal(in []byte, out interface{}) (err error) {
|
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||||
|
return unmarshal(in, out, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalStrict is like Unmarshal except that any fields that are found
|
||||||
|
// in the data that do not have corresponding struct members will result in
|
||||||
|
// an error.
|
||||||
|
func UnmarshalStrict(in []byte, out interface{}) (err error) {
|
||||||
|
return unmarshal(in, out, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||||
defer handleErr(&err)
|
defer handleErr(&err)
|
||||||
d := newDecoder()
|
d := newDecoder(strict)
|
||||||
p := newParser(in)
|
p := newParser(in)
|
||||||
defer p.destroy()
|
defer p.destroy()
|
||||||
node := p.parse()
|
node := p.parse()
|
||||||
|
|
2
vendor/gopkg.in/yaml.v2/yamlh.go
generated
vendored
2
vendor/gopkg.in/yaml.v2/yamlh.go
generated
vendored
|
@ -508,7 +508,7 @@ type yaml_parser_t struct {
|
||||||
|
|
||||||
problem string // Error description.
|
problem string // Error description.
|
||||||
|
|
||||||
// The byte about which the problem occured.
|
// The byte about which the problem occurred.
|
||||||
problem_offset int
|
problem_offset int
|
||||||
problem_value int
|
problem_value int
|
||||||
problem_mark yaml_mark_t
|
problem_mark yaml_mark_t
|
||||||
|
|
Loading…
Reference in a new issue