diff options
90 files changed, 8876 insertions, 289 deletions
@@ -26,6 +26,12 @@ version = "v0.16.0" [[projects]] + branch = "v2" + name = "github.com/pborman/getopt" + packages = ["v2"] + revision = "0fd4e972e7f7285fbae5863470524ece4ae99d78" + +[[projects]] name = "github.com/pmezard/go-difflib" packages = ["difflib"] revision = "792786c7400a136282c1664665ae0a8db921c6c2" @@ -38,10 +44,16 @@ version = "v1.1.4" [[projects]] + name = "github.com/utahta/go-openuri" + packages = ["."] + revision = "e3e1c475535dd7256d67286b1c8c223721aafa05" + version = "v0.1.0" + +[[projects]] name = "gopkg.in/go-playground/validator.v9" packages = ["."] - revision = "61caf9d3038e1af346dbf5c2e16f6678e1548364" - version = "v9.9.0" + revision = "1b8c8e19cd250435025214492d9a08411d760fdd" + version = "v9.12.0" [[projects]] branch = "v2" @@ -52,6 +64,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "a207dfcd5255a9f7ed6e08d3982f8f3075d29d45b7d0bb7ad31709e04755a649" + inputs-digest = "8cdb40365412638a73ba10e3c82296098a85b4df74a25186aec4bd7b3a8c50e4" solver-name = "gps-cdcl" solver-version = 1 @@ -11,8 +11,16 @@ [[constraint]] name = "gopkg.in/go-playground/validator.v9" - version = "9.9.0" + version = "9.12.0" [[constraint]] branch = "v2" name = "gopkg.in/yaml.v2" + +[[constraint]] + name = "github.com/utahta/go-openuri" + version = "0.1.0" + +[[constraint]] + branch = "v2" + name = "github.com/pborman/getopt" diff --git a/config/common.go b/config/common.go index a597a82..4cc300d 100644 --- a/config/common.go +++ b/config/common.go @@ -9,12 +9,12 @@ import ( // type CommonConfig struct { Base string `yaml:"base" validate:"omitempty,baseimage"` // name/path to base image - Apt AptConfig `yaml:"apt"` // APT related configuration - Node NodeConfig `yaml:"node"` // Node related configuration - Python PythonConfig `yaml:"python"` // Python related configuration - Lives LivesConfig `yaml:"lives"` // application owner/dir configuration - Runs RunsConfig `yaml:"runs"` // runtime environment configuration - SharedVolume Flag `yaml:"sharedvolume"` // define a volume for application + Apt AptConfig `yaml:"apt"` // APT related + Node NodeConfig `yaml:"node"` // Node related + Python PythonConfig `yaml:"python"` // Python related + Lives LivesConfig `yaml:"lives"` // application owner/dir + Runs RunsConfig `yaml:"runs"` // runtime environment + SharedVolume Flag `yaml:"sharedvolume"` // use volume for app EntryPoint []string `yaml:"entrypoint"` // entry-point executable } diff --git a/config/policy.go b/config/policy.go new file mode 100644 index 0000000..25fe02a --- /dev/null +++ b/config/policy.go @@ -0,0 +1,141 @@ +package config + +import ( + "errors" + "fmt" + "io/ioutil" + "reflect" + "strings" + + "github.com/utahta/go-openuri" + "gopkg.in/yaml.v2" +) + +// Policy validates a number of rules against a given configuration. +// +type Policy struct { + Enforcements []Enforcement `yaml:"enforcements"` +} + +// Validate checks the given config against all policy enforcements. +// +func (pol Policy) Validate(config Config) error { + validate := NewValidator() + + for _, enforcement := range pol.Enforcements { + cfg, err := ResolveYAMLPath(enforcement.Path, config) + + if err != nil { + // If the path resolved nothing, there's nothing to enforce + continue + } + + // Flags are a special case in which the True field should be compared + // against the validator, not the struct itself. + if flag, ok := cfg.(Flag); ok { + cfg = flag.True + } + + err = validate.Var(cfg, enforcement.Rule) + + if err != nil { + return fmt.Errorf( + `value for "%s" violates policy rule "%s"`, + enforcement.Path, enforcement.Rule, + ) + } + } + + return nil +} + +// Enforcement represents a policy rule and config path on which to apply it. +// +type Enforcement struct { + Path string `yaml:"path"` + Rule string `yaml:"rule"` +} + +// ReadPolicy unmarshals the given YAML bytes into a new Policy struct. +// +func ReadPolicy(data []byte) (*Policy, error) { + var policy Policy + + err := yaml.Unmarshal(data, &policy) + + if err != nil { + return nil, err + } + + return &policy, err +} + +// ReadPolicyFromURI fetches the policy file from the given URL or file path +// and loads its contents with ReadPolicy. +// +func ReadPolicyFromURI(uri string) (*Policy, error) { + io, err := openuri.Open(uri) + + if err != nil { + return nil, err + } + + defer io.Close() + + data, err := ioutil.ReadAll(io) + + if err != nil { + return nil, err + } + + return ReadPolicy(data) +} + +// ResolveYAMLPath returns the config value found at the given YAML-ish +// namespace/path (e.g. "variants.production.runs.as"). +// +func ResolveYAMLPath(path string, cfg interface{}) (interface{}, error) { + parts := strings.SplitN(path, ".", 2) + name := parts[0] + + v := reflect.ValueOf(cfg) + t := v.Type() + + var subcfg interface{} + + switch t.Kind() { + case reflect.Struct: + for i := 0; i < t.NumField(); i++ { + if t.Field(i).Anonymous { + if subsubcfg, err := ResolveYAMLPath(path, v.Field(i).Interface()); err == nil { + return subsubcfg, nil + } + } + + if name == resolveYAMLTagName(t.Field(i)) { + subcfg = v.Field(i).Interface() + break + } + } + + case reflect.Map: + if t.Key().Kind() == reflect.String { + for _, key := range v.MapKeys() { + if key.Interface().(string) == name { + subcfg = v.MapIndex(key).Interface() + break + } + } + } + } + + if subcfg == nil { + return nil, errors.New("invalid path") + } + + if len(parts) > 1 { + return ResolveYAMLPath(parts[1], subcfg) + } + + return subcfg, nil +} diff --git a/config/policy_test.go b/config/policy_test.go new file mode 100644 index 0000000..2d7a3a7 --- /dev/null +++ b/config/policy_test.go @@ -0,0 +1,117 @@ +package config_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "phabricator.wikimedia.org/source/blubber/config" +) + +func TestPolicyRead(t *testing.T) { + policy, err := config.ReadPolicy([]byte(`--- + enforcements: + - path: variants.production.runs.as + rule: ne=root + - path: base + rule: oneof=debian:jessie debian:stretch`)) + + if assert.NoError(t, err) { + if assert.Len(t, policy.Enforcements, 2) { + assert.Equal(t, "variants.production.runs.as", policy.Enforcements[0].Path) + assert.Equal(t, "ne=root", policy.Enforcements[0].Rule) + + assert.Equal(t, "base", policy.Enforcements[1].Path) + assert.Equal(t, "oneof=debian:jessie debian:stretch", policy.Enforcements[1].Rule) + } + } +} + +func TestPolicyValidate(t *testing.T) { + cfg := config.Config{ + CommonConfig: config.CommonConfig{ + Base: "foo:tag", + }, + Variants: map[string]config.VariantConfig{ + "foo": config.VariantConfig{ + CommonConfig: config.CommonConfig{ + Runs: config.RunsConfig{ + UserConfig: config.UserConfig{ + As: "root", + }, + }, + }, + }, + }, + } + + policy := config.Policy{ + Enforcements: []config.Enforcement{ + {Path: "variants.foo.runs.as", Rule: "ne=root"}, + }, + } + + assert.EqualError(t, + policy.Validate(cfg), + `value for "variants.foo.runs.as" violates policy rule "ne=root"`, + ) + + policy = config.Policy{ + Enforcements: []config.Enforcement{ + {Path: "base", Rule: "oneof=debian:jessie debian:stretch"}, + }, + } + + assert.EqualError(t, + policy.Validate(cfg), + `value for "base" violates policy rule "oneof=debian:jessie debian:stretch"`, + ) +} + +func TestEnforcementOnFlag(t *testing.T) { + cfg := config.Config{ + Variants: map[string]config.VariantConfig{ + "production": config.VariantConfig{ + CommonConfig: config.CommonConfig{ + Node: config.NodeConfig{ + Dependencies: config.Flag{True: true}, + }, + }, + }, + }, + } + + policy := config.Policy{ + Enforcements: []config.Enforcement{ + {Path: "variants.production.node.dependencies", Rule: "isfalse"}, + }, + } + + assert.Error(t, + policy.Validate(cfg), + `value for "variants.production.node.dependencies" violates policy rule "isfalse"`, + ) + +} + +func TestResolveYAMLPath(t *testing.T) { + cfg := config.Config{ + Variants: map[string]config.VariantConfig{ + "foo": config.VariantConfig{ + CommonConfig: config.CommonConfig{ + Runs: config.RunsConfig{ + UserConfig: config.UserConfig{ + As: "root", + }, + }, + }, + }, + }, + } + + val, err := config.ResolveYAMLPath("variants.foo.runs.as", cfg) + + if assert.NoError(t, err) { + assert.Equal(t, "root", val) + } +} diff --git a/config/validation.go b/config/validation.go index 652a3c8..3359211 100644 --- a/config/validation.go +++ b/config/validation.go @@ -52,6 +52,8 @@ var ( "baseimage": isBaseImage, "debianpackage": isDebianPackage, "envvars": isEnvironmentVariables, + "isfalse": isFalse, + "istrue": isTrue, "variantref": isVariantReference, "variants": hasVariantNames, } @@ -61,11 +63,10 @@ type ctxKey uint8 const rootCfgCtx ctxKey = iota -// Validate runs all validations defined for config fields against the given -// Config value. If the returned error is not nil, it will contain a -// user-friendly message describing all invalid field values. +// NewValidator returns a validator instance for which our custom aliases and +// functions are registered. // -func Validate(config Config) error { +func NewValidator() *validator.Validate { validate := validator.New() validate.RegisterTagNameFunc(resolveYAMLTagName) @@ -78,6 +79,16 @@ func Validate(config Config) error { validate.RegisterValidationCtx(name, f) } + return validate +} + +// Validate runs all validations defined for config fields against the given +// Config value. If the returned error is not nil, it will contain a +// user-friendly message describing all invalid field values. +// +func Validate(config Config) error { + validate := NewValidator() + ctx := context.WithValue(context.Background(), rootCfgCtx, config) return validate.StructCtx(ctx, config) @@ -169,6 +180,18 @@ func isEnvironmentVariables(_ context.Context, fl validator.FieldLevel) bool { return true } +func isFalse(_ context.Context, fl validator.FieldLevel) bool { + val, ok := fl.Field().Interface().(bool) + + return ok && val == false +} + +func isTrue(_ context.Context, fl validator.FieldLevel) bool { + val, ok := fl.Field().Interface().(bool) + + return ok && val == true +} + func isVariantReference(ctx context.Context, fl validator.FieldLevel) bool { cfg := ctx.Value(rootCfgCtx).(Config) ref := fl.Field().String() @@ -7,35 +7,73 @@ import ( "log" "os" + "github.com/pborman/getopt/v2" + "phabricator.wikimedia.org/source/blubber/config" "phabricator.wikimedia.org/source/blubber/docker" "phabricator.wikimedia.org/source/blubber/meta" ) +const parameters = "config.yaml variant" + +var ( + showHelp *bool = getopt.BoolLong("help", 'h', "show help/usage") + showVersion *bool = getopt.BoolLong("version", 'v', "show version information") + policyURI *string = getopt.StringLong("policy", 'p', "", "policy file URI", "uri") +) + func main() { - if len(os.Args) > 1 && os.Args[1] == "--version" { + getopt.SetParameters(parameters) + getopt.Parse() + + if *showHelp { + getopt.Usage() + os.Exit(1) + } + + if *showVersion { fmt.Println(meta.FullVersion()) os.Exit(0) } - if len(os.Args) < 3 { - fmt.Println("Usage: blubber config.yaml variant") + args := getopt.Args() + + if len(args) < 2 { + getopt.Usage() os.Exit(1) } - cfg, err := config.ReadConfigFile(os.Args[1]) + cfgPath, variant := args[0], args[1] + + cfg, err := config.ReadConfigFile(cfgPath) if err != nil { if config.IsValidationError(err) { - log.Printf("Your config is invalid:\n%v", config.HumanizeValidationError(err)) + log.Printf("%s is invalid:\n%v", cfgPath, config.HumanizeValidationError(err)) os.Exit(4) } else { - log.Printf("Error reading config: %v\n", err) + log.Printf("Error reading %s: %v\n", cfgPath, err) os.Exit(2) } } - dockerFile, err := docker.Compile(cfg, os.Args[2]) + if *policyURI != "" { + policy, err := config.ReadPolicyFromURI(*policyURI) + + if err != nil { + log.Printf("Error loading policy from %s: %v\n", *policyURI, err) + os.Exit(5) + } + + err = policy.Validate(*cfg) + + if err != nil { + log.Printf("Configuration fails policy check against:\npolicy: %s\nviolation: %v\n", *policyURI, err) + os.Exit(6) + } + } + + dockerFile, err := docker.Compile(cfg, variant) if err != nil { log.Printf("Error compiling config: %v\n", err) diff --git a/policy.example.yaml b/policy.example.yaml new file mode 100644 index 0000000..2ca553b --- /dev/null +++ b/policy.example.yaml @@ -0,0 +1,5 @@ +enforcements: + - path: variants.production.base + rule: oneof=debian:jessie debian:jessie-slim + - path: variants.production.node.dependencies + rule: istrue diff --git a/vendor/github.com/pborman/getopt/AUTHORS b/vendor/github.com/pborman/getopt/AUTHORS new file mode 100644 index 0000000..2d70b04 --- /dev/null +++ b/vendor/github.com/pborman/getopt/AUTHORS @@ -0,0 +1 @@ +Paul Borman <paul@borman.com> diff --git a/vendor/github.com/pborman/getopt/CONTRIBUTING.md b/vendor/github.com/pborman/getopt/CONTRIBUTING.md new file mode 100644 index 0000000..04fdf09 --- /dev/null +++ b/vendor/github.com/pborman/getopt/CONTRIBUTING.md @@ -0,0 +1,10 @@ +# How to contribute + +We definitely welcome patches and contribution to this project! + +### Legal requirements + +In order to protect both you and ourselves, you will need to sign the +[Contributor License Agreement](https://cla.developers.google.com/clas). + +You may have already signed it for other Google projects. diff --git a/vendor/github.com/pborman/getopt/LICENSE b/vendor/github.com/pborman/getopt/LICENSE new file mode 100644 index 0000000..a8181ec --- /dev/null +++ b/vendor/github.com/pborman/getopt/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2017 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google, nor the names of other +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pborman/getopt/README.md b/vendor/github.com/pborman/getopt/README.md new file mode 100644 index 0000000..2e1cf72 --- /dev/null +++ b/vendor/github.com/pborman/getopt/README.md @@ -0,0 +1,226 @@ +# getopt + +Package getopt provides traditional getopt processing for implementing +commands that use traditional command lines. The standard Go flag package +cannot be used to write a program that parses flags the way ls or ssh does, +for example. There are two versions, v1 and v2, both named getopt, that +use the following import paths: + +``` + "github.com/pborman/getopt" // version 1 + "github.com/pborman/getopt/v2" // version 2 +``` + +This README describes version 2 of the package, which has a simplified API. + +## Usage + +Getopt supports functionality found in both the standard BSD getopt as well +as (one of the many versions of) the GNU getopt_long. Being a Go package, +this package makes common usage easy, but still enables more controlled usage +if needed. + +Typical usage: + +``` + Declare flags and have getopt return pointers to the values. + helpFlag := getopt.Bool('?', "display help") + cmdFlag := getopt.StringLong("command", 'c', "default", "the command) + + Declare flags against existing variables. + var { + fileName = "/the/default/path" + timeout = time.Second * 5 + verbose bool + } + func init() { + getopt.Flag(&verbose, 'v', "be verbose") + getopt.FlagLong(&fileName, "path", 0, "the path") + getopt.FlagLong(&timeout, "timeout", 't', "some timeout") + } + + func main() { + Parse the program arguments + getopt.Parse() + Get the remaining positional parameters + args := getopt.Args() + ... +``` + +If you don't want the program to exit on error, use getopt.Getopt: + +``` + err := getopt.Getopt(nil) + if err != nil { + code to handle error + fmt.Fprintln(os.Stderr, err) + } +``` + +## Flag Syntax + +Support is provided for both short (-f) and long (--flag) options. A single +option may have both a short and a long name. Each option may be a flag or a +value. A value takes an argument. + +Declaring no long names causes this package to process arguments like the +traditional BSD getopt. + +Short flags may be combined into a single parameter. For example, "-a -b -c" +may also be expressed "-abc". Long flags must stand on their own "--alpha +--beta" + +Values require an argument. For short options the argument may either be +immediately following the short name or as the next argument. Only one short +value may be combined with short flags in a single argument; the short value +must be after all short flags. For example, if f is a flag and v is a value, +then: + +``` + -vvalue (sets v to "value") + -v value (sets v to "value") + -fvvalue (sets f, and sets v to "value") + -fv value (sets f, and sets v to "value") + -vf value (set v to "f" and value is the first parameter) +``` + +For the long value option val: + +``` + --val value (sets val to "value") + --val=value (sets val to "value") + --valvalue (invalid option "valvalue") +``` + +Values with an optional value only set the value if the value is part of the +same argument. In any event, the option count is increased and the option is +marked as seen. + +``` + -v -f (sets v and f as being seen) + -vvalue -f (sets v to "value" and sets f) + --val -f (sets v and f as being seen) + --val=value -f (sets v to "value" and sets f) +``` + +There is no convience function defined for making the value optional. The +SetOptional method must be called on the actual Option. + +``` + v := String("val", 'v', "", "the optional v") + Lookup("v").SetOptional() + + var s string + FlagLong(&s, "val", 'v', "the optional v).SetOptional() +``` + +Parsing continues until the first non-option or "--" is encountered. + +The short name "-" can be used, but it either is specified as "-" or as part +of a group of options, for example "-f-". If there are no long options +specified then "--f" could also be used. If "-" is not declared as an option +then the single "-" will also terminate the option processing but unlike +"--", the "-" will be part of the remaining arguments. + +## Advanced Usage + +Normally the parsing is performed by calling the Parse function. If it is +important to see the order of the options then the Getopt function should be +used. The standard Parse function does the equivalent of: + +``` +func Parse() { + if err := getopt.Getopt(os.Args, nil); err != nil { + fmt.Fprintln(os.Stderr, err) + s.usage() + os.Exit(1) + } +} +``` + +When calling Getopt it is the responsibility of the caller to print any +errors. + +Normally the default option set, CommandLine, is used. Other option sets may +be created with New. + +After parsing, the sets Args will contain the non-option arguments. If an +error is encountered then Args will begin with argument that caused the +error. + +It is valid to call a set's Parse a second time to amend the current set of +flags or values. As an example: + +``` + var a = getopt.Bool('a', "", "The a flag") + var b = getopt.Bool('b', "", "The a flag") + var cmd = "" + + var opts = getopt.CommandLine + + opts.Parse(os.Args) + if opts.NArgs() > 0 { + cmd = opts.Arg(0) + opts.Parse(opts.Args()) + } +``` + +If called with set to { "prog", "-a", "cmd", "-b", "arg" } then both and and +b would be set, cmd would be set to "cmd", and opts.Args() would return { +"arg" }. + +Unless an option type explicitly prohibits it, an option may appear more than +once in the arguments. The last value provided to the option is the value. + +## Builtin Types + +The Flag and FlagLong functions support most standard Go types. For the +list, see the description of FlagLong below for a list of supported types. + +There are also helper routines to allow single line flag declarations. These +types are: Bool, Counter, Duration, Enum, Int16, Int32, Int64, Int, List, +Signed, String, Uint16, Uint32, Uint64, Uint, and Unsigned. + +Each comes in a short and long flavor, e.g., Bool and BoolLong and include +functions to set the flags on the standard command line or for a specific Set +of flags. + +Except for the Counter, Enum, Signed and Unsigned types, all of these types +can be declared using Flag and FlagLong by passing in a pointer to the +appropriate type. + +## Declaring New Flag Types + +A pointer to any type that implements the Value interface may be passed to +Flag or FlagLong. + +## VALUEHELP + +All non-flag options are created with a "valuehelp" as the last parameter. +Valuehelp should be 0, 1, or 2 strings. The first string, if provided, is +the usage message for the option. If the second string, if provided, is the +name to use for the value when displaying the usage. If not provided the +term "value" is assumed. + +The usage message for the option created with + +``` + StringLong("option", 'o', "defval", "a string of letters") +``` + +is + +``` + -o, -option=value +``` +while the usage message for the option created with + +``` + StringLong("option", 'o', "defval", "a string of letters", "string") +``` + +is + +``` + -o, -option=string +``` diff --git a/vendor/github.com/pborman/getopt/bool.go b/vendor/github.com/pborman/getopt/bool.go new file mode 100644 index 0000000..37ce019 --- /dev/null +++ b/vendor/github.com/pborman/getopt/bool.go @@ -0,0 +1,74 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" +) + +type boolValue bool + +func (b *boolValue) Set(value string, opt Option) error { + switch strings.ToLower(value) { + case "", "1", "true", "on", "t": + *b = true + case "0", "false", "off", "f": + *b = false + default: + return fmt.Errorf("invalid value for bool %s: %q", opt.Name(), value) + } + return nil +} + +func (b *boolValue) String() string { + if *b { + return "true" + } + return "false" +} + +// Bool creates a flag option that is a bool. Bools normally do not take a +// value however one can be assigned by using the long form of the option: +// +// --option=true +// --o=false +// +// Its value is case insenstive and one of true, false, t, f, on, off, t and 0. +func Bool(name rune, helpvalue ...string) *bool { + return CommandLine.Bool(name, helpvalue...) +} + +func (s *Set) Bool(name rune, helpvalue ...string) *bool { + var p bool + s.BoolVarLong(&p, "", name, helpvalue...) + return &p +} + +func BoolLong(name string, short rune, helpvalue ...string) *bool { + return CommandLine.BoolLong(name, short, helpvalue...) +} + +func (s *Set) BoolLong(name string, short rune, helpvalue ...string) *bool { + var p bool + s.BoolVarLong(&p, name, short, helpvalue...) + return &p +} + +func BoolVar(p *bool, name rune, helpvalue ...string) Option { + return CommandLine.BoolVar(p, name, helpvalue...) +} + +func (s *Set) BoolVar(p *bool, name rune, helpvalue ...string) Option { + return s.BoolVarLong(p, "", name, helpvalue...) +} + +func BoolVarLong(p *bool, name string, short rune, helpvalue ...string) Option { + return CommandLine.BoolVarLong(p, name, short, helpvalue...) +} + +func (s *Set) BoolVarLong(p *bool, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*boolValue)(p), name, short, helpvalue...).SetFlag() +} diff --git a/vendor/github.com/pborman/getopt/bool_test.go b/vendor/github.com/pborman/getopt/bool_test.go new file mode 100644 index 0000000..b112161 --- /dev/null +++ b/vendor/github.com/pborman/getopt/bool_test.go @@ -0,0 +1,106 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var boolTests = []struct { + where string + in []string + f bool + fc int + opt bool + optc int + err string +}{ + { + loc(), + []string{}, + false, 0, + false, 0, + "", + }, + { + loc(), + []string{"test", "-f", "--opt"}, + true, 1, + true, 1, + "", + }, + { + loc(), + []string{"test", "--f", "--opt"}, + true, 1, + true, 1, + "", + }, + { + loc(), + []string{"test", "-ff", "-f", "--opt", "--opt"}, + true, 3, + true, 2, + "", + }, + { + loc(), + []string{"test", "--opt", "--opt=false"}, + false, 0, + false, 2, + "", + }, + { + loc(), + []string{"test", "-f", "false"}, + true, 1, + false, 0, + "", + }, + { + loc(), + []string{"test", "-f=false"}, + true, 1, + false, 0, + "test: unknown option: -=\n", + }, + { + loc(), + []string{"test", "-f", "false"}, + true, 1, + false, 0, + "", + }, +} + +func TestBool(t *testing.T) { + for x, tt := range boolTests { + reset() + f := Bool('f') + opt := BoolLong("opt", 0) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *f, tt.f; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.opt; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := GetCount('f'), tt.fc; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := GetCount("opt"), tt.optc; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/breakup_test.go b/vendor/github.com/pborman/getopt/breakup_test.go new file mode 100644 index 0000000..c0ac148 --- /dev/null +++ b/vendor/github.com/pborman/getopt/breakup_test.go @@ -0,0 +1,34 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "testing" +) + +var breakupTests = []struct { + in string + max int + out []string +}{ + {"", 8, []string{}}, + {"a fox", 8, []string{"a fox"}}, + {"a foxhound is sly", 2, []string{"a", "foxhound", "is", "sly"}}, + {"a foxhound is sly", 5, []string{"a", "foxhound", "is", "sly"}}, + {"a foxhound is sly", 6, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 7, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 8, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 9, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 10, []string{"a foxhound", "is sly"}}, +} + +func TestBreakup(t *testing.T) { + for x, tt := range breakupTests { + out := breakup(tt.in, tt.max) + if badSlice(out, tt.out) { + t.Errorf("#%d: got %v, want %v", x, out, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/counter.go b/vendor/github.com/pborman/getopt/counter.go new file mode 100644 index 0000000..8b11ec1 --- /dev/null +++ b/vendor/github.com/pborman/getopt/counter.go @@ -0,0 +1,81 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type counterValue int + +func (b *counterValue) Set(value string, opt Option) error { + if value == "" { + *b++ + } else { + v, err := strconv.ParseInt(value, 0, strconv.IntSize) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *b = counterValue(v) + } + return nil +} + +func (b *counterValue) String() string { + return strconv.Itoa(int(*b)) +} + +// Counter creates a counting flag stored as an int. Each time the option +// is seen while parsing the value is incremented. The value of the counter +// may be explicitly set by using the long form: +// +// --counter=5 +// --c=5 +// +// Further instances of the option will increment from the set value. +func Counter(name rune, helpvalue ...string) *int { + return CommandLine.Counter(name, helpvalue...) +} + +func (s *Set) Counter(name rune, helpvalue ...string) *int { + var p int + s.CounterVarLong(&p, "", name, helpvalue...) + return &p +} + +func CounterLong(name string, short rune, helpvalue ...string) *int { + return CommandLine.CounterLong(name, short, helpvalue...) +} + +func (s *Set) CounterLong(name string, short rune, helpvalue ...string) *int { + var p int + s.CounterVarLong(&p, name, short, helpvalue...) + return &p +} + +func CounterVar(p *int, name rune, helpvalue ...string) Option { + return CommandLine.CounterVar(p, name, helpvalue...) +} + +func (s *Set) CounterVar(p *int, name rune, helpvalue ...string) Option { + return s.CounterVarLong(p, "", name, helpvalue...) +} + +func CounterVarLong(p *int, name string, short rune, helpvalue ...string) Option { + return CommandLine.CounterVarLong(p, name, short, helpvalue...) +} + +func (s *Set) CounterVarLong(p *int, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*counterValue)(p), name, short, helpvalue...).SetFlag() +} diff --git a/vendor/github.com/pborman/getopt/counter_test.go b/vendor/github.com/pborman/getopt/counter_test.go new file mode 100644 index 0000000..4b4e0cb --- /dev/null +++ b/vendor/github.com/pborman/getopt/counter_test.go @@ -0,0 +1,91 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var counterTests = []struct { + where string + in []string + c int + cnt int + err string +}{ + { + loc(), + []string{}, + 0, + 0, + "", + }, + { + loc(), + []string{"test", "-c", "--cnt"}, + 1, + 1, + "", + }, + { + loc(), + []string{"test", "-cc", "-c", "--cnt", "--cnt"}, + 3, + 2, + "", + }, + { + loc(), + []string{"test", "--c=17", "--cnt=42"}, + 17, + 42, + "", + }, + { + loc(), + []string{"test", "--cnt=false"}, + 0, 0, + "test: not a valid number: false\n", + }, +} + +func TestCounter(t *testing.T) { + for x, tt := range counterTests { + reset() + c := Counter('c') + cnt := CounterLong("cnt", 0) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *c, tt.c; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *cnt, tt.cnt; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } + + reset() + c := 5 + opt := CounterVar(&c, 'c') + parse([]string{"test", "-c"}) + if c != 6 { + t.Errorf("got %d, want 6", c) + } + if opt.Count() != 1 { + t.Errorf("got %d, want 1", c) + } + Reset() + if c != 5 { + t.Errorf("got %d, want 5", c) + } +} diff --git a/vendor/github.com/pborman/getopt/duration.go b/vendor/github.com/pborman/getopt/duration.go new file mode 100644 index 0000000..9061113 --- /dev/null +++ b/vendor/github.com/pborman/getopt/duration.go @@ -0,0 +1,56 @@ +// Copyright 2015 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "time" + +type durationValue time.Duration + +func (d *durationValue) Set(value string, opt Option) error { + v, err := time.ParseDuration(value) + if err != nil { + return err + } + *d = durationValue(v) + return nil +} + +func (d *durationValue) String() string { + return time.Duration(*d).String() +} + +// Duration creates an option that parses its value as a time.Duration. +func Duration(name rune, value time.Duration, helpvalue ...string) *time.Duration { + return CommandLine.Duration(name, value, helpvalue...) +} + +func (s *Set) Duration(name rune, value time.Duration, helpvalue ...string) *time.Duration { + return s.DurationLong("", name, value, helpvalue...) +} + +func DurationLong(name string, short rune, value time.Duration, helpvalue ...string) *time.Duration { + return CommandLine.DurationLong(name, short, value, helpvalue...) +} + +func (s *Set) DurationLong(name string, short rune, value time.Duration, helpvalue ...string) *time.Duration { + s.DurationVarLong(&value, name, short, helpvalue...) + return &value +} + +func DurationVar(p *time.Duration, name rune, helpvalue ...string) Option { + return CommandLine.DurationVar(p, name, helpvalue...) +} + +func (s *Set) DurationVar(p *time.Duration, name rune, helpvalue ...string) Option { + return s.DurationVarLong(p, "", name, helpvalue...) +} + +func DurationVarLong(p *time.Duration, name string, short rune, helpvalue ...string) Option { + return CommandLine.DurationVarLong(p, name, short, helpvalue...) +} + +func (s *Set) DurationVarLong(p *time.Duration, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*durationValue)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/duration_test.go b/vendor/github.com/pborman/getopt/duration_test.go new file mode 100644 index 0000000..fc4ded7 --- /dev/null +++ b/vendor/github.com/pborman/getopt/duration_test.go @@ -0,0 +1,73 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" + "time" +) + +var durationTests = []struct { + where string + in []string + d time.Duration + dur time.Duration + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-d", "1s", "--duration", "2s"}, + time.Second, 2 * time.Second, + "", + }, + { + loc(), + []string{"test", "-d1s", "-d2s"}, + 2 * time.Second, 42, + "", + }, + { + loc(), + []string{"test", "-d1"}, + 17, 42, + "test: time: missing unit in duration 1\n", + }, + { + loc(), + []string{"test", "--duration", "foo"}, + 17, 42, + "test: time: invalid duration foo\n", + }, +} + +func TestDuration(t *testing.T) { + for x, tt := range durationTests { + reset() + d := Duration('d', 17) + opt := DurationLong("duration", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *d, tt.d; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.dur; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/enum.go b/vendor/github.com/pborman/getopt/enum.go new file mode 100644 index 0000000..ee4cf95 --- /dev/null +++ b/vendor/github.com/pborman/getopt/enum.go @@ -0,0 +1,73 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "errors" + +type enumValue string + +var enumValues = make(map[*enumValue]map[string]struct{}) + +func (s *enumValue) Set(value string, opt Option) error { + es, ok := enumValues[s] + if !ok || es == nil { + return errors.New("this option has no values") + } + if _, ok := es[value]; !ok { + return errors.New("invalid value: " + value) + } + *s = enumValue(value) + return nil +} + +func (s *enumValue) String() string { + return string(*s) +} + +// Enum creates an option that can only be set to one of the enumerated strings +// passed in values. Passing nil or an empty slice results in an option that +// will always fail. +func Enum(name rune, values []string, helpvalue ...string) *string { + return CommandLine.Enum(name, values, helpvalue...) +} + +func (s *Set) Enum(name rune, values []string, helpvalue ...string) *string { + var p string + s.EnumVarLong(&p, "", name, values, helpvalue...) + return &p +} + +func EnumLong(name string, short rune, values []string, helpvalue ...string) *string { + return CommandLine.EnumLong(name, short, values, helpvalue...) +} + +func (s *Set) EnumLong(name string, short rune, values []string, helpvalue ...string) *string { + var p string + s.EnumVarLong(&p, name, short, values, helpvalue...) + return &p +} + +// EnumVar creates an enum option that defaults to the starting value of *p. +// If *p is not found in values then a reset of this option will fail. +func EnumVar(p *string, name rune, values []string, helpvalue ...string) Option { + return CommandLine.EnumVar(p, name, values, helpvalue...) +} + +func (s *Set) EnumVar(p *string, name rune, values []string, helpvalue ...string) Option { + return s.EnumVarLong(p, "", name, values, helpvalue...) +} + +func EnumVarLong(p *string, name string, short rune, values []string, helpvalue ...string) Option { + return CommandLine.EnumVarLong(p, name, short, values, helpvalue...) +} + +func (s *Set) EnumVarLong(p *string, name string, short rune, values []string, helpvalue ...string) Option { + m := make(map[string]struct{}) + for _, v := range values { + m[v] = struct{}{} + } + enumValues[(*enumValue)(p)] = m + return s.VarLong((*enumValue)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/enum_test.go b/vendor/github.com/pborman/getopt/enum_test.go new file mode 100644 index 0000000..3c04ee8 --- /dev/null +++ b/vendor/github.com/pborman/getopt/enum_test.go @@ -0,0 +1,66 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var enumTests = []struct { + where string + in []string + values []string + out string + err string +}{ + { + loc(), + nil, + []string{}, + "", + "", + }, + { + loc(), + []string{"test", "-e", "val1"}, + []string{"val1", "val2"}, + "val1", + "", + }, + { + loc(), + []string{"test", "-e", "val1", "-e", "val2"}, + []string{"val1", "val2"}, + "val2", + "", + }, + { + loc(), + []string{"test", "-e", "val3"}, + []string{"val1", "val2"}, + "", + "test: invalid value: val3\n", + }, +} + +func TestEnum(t *testing.T) { + for x, tt := range enumTests { + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + reset() + e := Enum('e', tt.values) + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *e != tt.out { + t.Errorf("%s: got %v, want %v", tt.where, *e, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/error.go b/vendor/github.com/pborman/getopt/error.go new file mode 100644 index 0000000..3de8e86 --- /dev/null +++ b/vendor/github.com/pborman/getopt/error.go @@ -0,0 +1,93 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "fmt" + +// An Error is returned by Getopt when it encounters an error. +type Error struct { + ErrorCode // General reason of failure. + Err error // The actual error. + Parameter string // Parameter passed to option, if any + Name string // Option that cause error, if any +} + +// Error returns the error message, implementing the error interface. +func (i *Error) Error() string { return i.Err.Error() } + +// An ErrorCode indicates what sort of error was encountered. +type ErrorCode int + +const ( + NoError = ErrorCode(iota) + UnknownOption // an invalid option was encountered + MissingParameter // the options parameter is missing + ExtraParameter // a value was set to a long flag + Invalid // attempt to set an invalid value +) + +func (e ErrorCode) String() string { + switch e { + case UnknownOption: + return "unknow option" + case MissingParameter: + return "missing argument" + case ExtraParameter: + return "unxpected value" + case Invalid: + return "error setting value" + } + return "unknown error" +} + +// unknownOption returns an Error indicating an unknown option was +// encountered. +func unknownOption(name interface{}) *Error { + i := &Error{ErrorCode: UnknownOption} + switch n := name.(type) { + case rune: + if n == '-' { + i.Name = "-" + } else { + i.Name = "-" + string(n) + } + case string: + i.Name = "--" + n + } + i.Err = fmt.Errorf("unknown option: %s", i.Name) + return i +} + +// missingArg returns an Error inidicating option o was not passed +// a required paramter. +func missingArg(o Option) *Error { + return &Error{ + ErrorCode: MissingParameter, + Name: o.Name(), + Err: fmt.Errorf("missing parameter for %s", o.Name()), + } +} + +// extraArg returns an Error inidicating option o was passed the +// unexpected paramter value. +func extraArg(o Option, value string) *Error { + return &Error{ + ErrorCode: ExtraParameter, + Name: o.Name(), + Parameter: value, + Err: fmt.Errorf("unexpected parameter passed to %s: %q", o.Name(), value), + } +} + +// setError returns an Error inidicating option o and the specified +// error while setting it to value. +func setError(o Option, value string, err error) *Error { + return &Error{ + ErrorCode: Invalid, + Name: o.Name(), + Parameter: value, + Err: err, + } +} diff --git a/vendor/github.com/pborman/getopt/getopt.go b/vendor/github.com/pborman/getopt/getopt.go new file mode 100644 index 0000000..e3279ab --- /dev/null +++ b/vendor/github.com/pborman/getopt/getopt.go @@ -0,0 +1,537 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package getopt (v1) provides traditional getopt processing for implementing +// commands that use traditional command lines. The standard Go flag package +// cannot be used to write a program that parses flags the way ls or ssh does, +// for example. +// +// A new version of this package (v2) (whose package name is also getopt) is +// available as: +// +// "github.com/pborman/getopt/v2" +// +// Getopt supports functionality found in both the standard BSD getopt as well +// as (one of the many versions of) the GNU getopt_long. Being a Go package, +// this package makes common usage easy, but still enables more controlled usage +// if needed. +// +// Typical usage: +// +// // Declare the flags to be used +// helpFlag := getopt.Bool('?', "display help") +// cmdFlag := getopt.StringLong("command", 'c', "", "the command) +// +// func main() { +// // Parse the program arguments +// getopt.Parse() +// // Get the remaining positional parameters +// args := getopt.Args() +// +// If you don't want the program to exit on error, use getopt.Getopt: +// +// err := getopt.Getopt(nil) +// if err != nil { +// // code to handle error +// fmt.Fprintln(os.Stderr, err) +// } +// +// Support is provided for both short (-f) and long (--flag) options. A single +// option may have both a short and a long name. Each option may be a flag or a +// value. A value takes an argument. +// +// Declaring no long names causes this package to process arguments like the +// traditional BSD getopt. +// +// Short flags may be combined into a single parameter. For example, "-a -b -c" +// may also be expressed "-abc". Long flags must stand on their own "--alpha +// --beta" +// +// Values require an argument. For short options the argument may either be +// immediately following the short name or as the next argument. Only one short +// value may be combined with short flags in a single argument; the short value +// must be after all short flags. For example, if f is a flag and v is a value, +// then: +// +// -vvalue (sets v to "value") +// -v value (sets v to "value") +// -fvvalue (sets f, and sets v to "value") +// -fv value (sets f, and sets v to "value") +// -vf value (set v to "f" and value is the first parameter) +// +// For the long value option val: +// +// --val value (sets val to "value") +// --val=value (sets val to "value") +// --valvalue (invalid option "valvalue") +// +// Values with an optional value only set the value if the value is part of the +// same argument. In any event, the option count is increased and the option is +// marked as seen. +// +// -v -f (sets v and f as being seen) +// -vvalue -f (sets v to "value" and sets f) +// --val -f (sets v and f as being seen) +// --val=value -f (sets v to "value" and sets f) +// +// There is no convience function defined for making the value optional. The +// SetOptional method must be called on the actual Option. +// +// v := String("val", 'v', "", "the optional v") +// Lookup("v").SetOptional() +// +// var s string +// StringVar(&s, "val", 'v', "the optional v).SetOptional() +// +// Parsing continues until the first non-option or "--" is encountered. +// +// The short name "-" can be used, but it either is specified as "-" or as part +// of a group of options, for example "-f-". If there are no long options +// specified then "--f" could also be used. If "-" is not declared as an option +// then the single "-" will also terminate the option processing but unlike +// "--", the "-" will be part of the remaining arguments. +// +// Normally the parsing is performed by calling the Parse function. If it is +// important to see the order of the options then the Getopt function should be +// used. The standard Parse function does the equivalent of: +// +// func Parse() { +// if err := getopt.Getopt(os.Args, nil); err != nil { +// fmt.Fprintln(os.Stderr, err) +// s.usage() +// os.Exit(1) +// } +// +// When calling Getopt it is the responsibility of the caller to print any +// errors. +// +// Normally the default option set, CommandLine, is used. Other option sets may +// be created with New. +// +// After parsing, the sets Args will contain the non-option arguments. If an +// error is encountered then Args will begin with argument that caused the +// error. +// +// It is valid to call a set's Parse a second time to amend the current set of +// flags or values. As an example: +// +// var a = getopt.Bool('a', "", "The a flag") +// var b = getopt.Bool('b', "", "The a flag") +// var cmd = "" +// +// var opts = getopt.CommandLine +// +// opts.Parse(os.Args) +// if opts.NArgs() > 0 { +// cmd = opts.Arg(0) +// opts.Parse(opts.Args()) +// } +// +// If called with set to { "prog", "-a", "cmd", "-b", "arg" } then both and and +// b would be set, cmd would be set to "cmd", and opts.Args() would return { +// "arg" }. +// +// Unless an option type explicitly prohibits it, an option may appear more than +// once in the arguments. The last value provided to the option is the value. +// +// SYNTAX +// +// For each option type there are an unfortunately large number of ways, 8, to +// initialize the option. This number is derived from three attributes: +// +// 1) Short or Long name +// 2) Normal vs Var +// 3) Command Line vs Option Set +// +// The first two variations provide 4 signature: +// +// Option(name rune, [value type,] helpvalue... string) +// OptionLong(name string, short rune, [value type,] helpvalue... string) +// OptionVar(p *type, name rune, helpvalue... string) +// OptionVarLong(p *type, name string, short rune, helpvalue... string) +// +// Foo can actually be expressed in terms of FooLong: +// +// func Foo(name rune, value type, helpvalue... string) *type { +// return FooLong("", name, value, helpvalue...) +// } +// +// Normally Foo is used, unless long options are needed. Setting short to 0 +// creates only a long option. +// +// The difference bentween Foo and FooVar is that you pass a pointer, p, to the +// location of the value to FooVar. The default value is simply *p. The +// initial value of *p is the defaut value of the option. +// +// Foo is actually a wrapper around FooVar: +// +// func Foo(name rune, value type, helpvalue... string) *type { +// p := value +// FooVar(&p, name, helpvalue... string) +// return &p +// } +// +// +// The third variation provides a top-level function and a method on a Set: +// +// func Option(...) +// func (s *Set) Option(...) +// +// The top-level function is simply: +// +// func Option(...) *type { +// return CommandLine.Option(...) { +// } +// +// To simplfy documentation, typically only the main top-level function is fully +// documented. The others will have documentation when there is something +// special about them. +// +// VALUEHELP +// +// All non-flag options are created with a "valuehelp" as the last parameter. +// Valuehelp should be 0, 1, or 2 strings. The first string, if provided, is +// the usage message for the option. If the second string, if provided, is the +// name to use for the value when displaying the usage. If not provided the +// term "value" is assumed. +// +// The usage message for the option created with +// +// StringLong("option", 'o', "defval", "a string of letters") +// +// is +// +// -o, -option=value +// +// StringLong("option", 'o', "defval", "a string of letters", "string") +// +// is +// +// -o, -option=string +package getopt + +import ( + "fmt" + "io" + "os" + "path" + "sort" + "strings" +) + +// stderr allows tests to capture output to standard error. +var stderr io.Writer = os.Stderr + +// exit allows tests to capture an os.Exit call +var exit = os.Exit + +// DisplayWidth is used to determine where to split usage long lines. +var DisplayWidth = 80 + +// HelpColumn is the maximum column position that help strings start to display +// at. If the option usage is too long then the help string will be displayed +// on the next line. For example: +// +// -a this is the a flag +// -u, --under=location +// the u flag's usage is quite long +var HelpColumn = 20 + +// PrintUsage prints the usage of the program to w. +func (s *Set) PrintUsage(w io.Writer) { + sort.Sort(s.options) + flags := "" + + // Build up the list of short flag names and also compute + // how to display the option in the longer help listing. + // We also keep track of the longest option usage string + // that is no more than HelpColumn-3 bytes (at which point + // we use two lines to display the help). The three + // is for the leading space and the two spaces before the + // help string. + for _, opt := range s.options { + if opt.name == "" { + opt.name = "value" + } + if opt.uname == "" { + opt.uname = opt.usageName() + } + if opt.flag && opt.short != 0 && opt.short != '-' { + flags += string(opt.short) + } + } + + var opts []string + + // The short option - is special + if s.shortOptions['-'] != nil { + opts = append(opts, "-") + } + + // If we have a bundle of flags, add them to the list + if flags != "" { + opts = append(opts, "-"+flags) + } + + // Now append all the long options and options that require + // values. + for _, opt := range s.options { + if opt.flag { + if opt.short != 0 { + continue + } + flags = "--" + opt.long + } else if opt.short != 0 { + flags = "-" + string(opt.short) + " " + opt.name + } else { + flags = "--" + string(opt.long) + " " + opt.name + } + opts = append(opts, flags) + } + flags = strings.Join(opts, "] [") + if flags != "" { + flags = " [" + flags + "]" + } + if s.parameters != "" { + flags += " " + s.parameters + } + fmt.Fprintf(w, "Usage: %s%s\n", s.program, flags) + s.PrintOptions(w) +} + +// PrintOptions prints the list of options in s to w. +func (s *Set) PrintOptions(w io.Writer) { + sort.Sort(s.options) + max := 4 + for _, opt := range s.options { + if opt.name == "" { + opt.name = "value" + } + if opt.uname == "" { + opt.uname = opt.usageName() + } + if max < len(opt.uname) && len(opt.uname) <= HelpColumn-3 { + max = len(opt.uname) + } + } + // Now print one or more usage lines per option. + for _, opt := range s.options { + if opt.uname != "" { + opt.help = strings.TrimSpace(opt.help) + if len(opt.help) == 0 { + fmt.Fprintf(w, " %s\n", opt.uname) + continue + } + help := strings.Split(opt.help, "\n") + // If they did not put in newlines then we will insert + // them to keep the help messages from wrapping. + if len(help) == 1 { + help = breakup(help[0], DisplayWidth-HelpColumn) + } + if len(opt.uname) <= max { + fmt.Fprintf(w, " %-*s %s\n", max, opt.uname, help[0]) + help = help[1:] + } else { + fmt.Fprintf(w, " %s\n", opt.uname) + } + for _, s := range help { + fmt.Fprintf(w, " %-*s %s\n", max, " ", s) + } + } + } +} + +// breakup breaks s up into strings no longer than max bytes. +func breakup(s string, max int) []string { + var a []string + + for { + // strip leading spaces + for len(s) > 0 && s[0] == ' ' { + s = s[1:] + } + // If the option is no longer than the max just return it + if len(s) <= max { + if len(s) != 0 { + a = append(a, s) + } + return a + } + x := max + for s[x] != ' ' { + // the first word is too long?! + if x == 0 { + x = max + for x < len(s) && s[x] != ' ' { + x++ + } + if x == len(s) { + x-- + } + break + } + x-- + } + for s[x] == ' ' { + x-- + } + a = append(a, s[:x+1]) + s = s[x+1:] + } + panic("unreachable") +} + +// Parse uses Getopt to parse args using the options set for s. The first +// element of args is used to assign the program for s if it is not yet set. On +// error, Parse displays the error message as well as a usage message on +// standard error and then exits the program. +func (s *Set) Parse(args []string) { + if err := s.Getopt(args, nil); err != nil { + fmt.Fprintln(stderr, err) + s.usage() + exit(1) + } +} + +// Parse uses Getopt to parse args using the options set for s. The first +// element of args is used to assign the program for s if it is not yet set. +// Getop calls fn, if not nil, for each option parsed. +// +// Getopt returns nil when all options have been processed (a non-option +// argument was encountered, "--" was encountered, or fn returned false). +// +// On error getopt returns a refernce to an InvalidOption (which implements +// the error interface). +func (s *Set) Getopt(args []string, fn func(Option) bool) (err error) { + s.State = InProgress + defer func() { + if s.State == InProgress { + switch { + case err != nil: + s.State = Failure + case len(s.args) == 0: + s.State = EndOfArguments + default: + s.State = Unknown + } + } + }() + if fn == nil { + fn = func(Option) bool { return true } + } + if len(args) == 0 { + return nil + } + + if s.program == "" { + s.program = path.Base(args[0]) + } + args = args[1:] +Parsing: + for len(args) > 0 { + arg := args[0] + s.args = args + args = args[1:] + + // end of options? + if arg == "" || arg[0] != '-' { + s.State = EndOfOptions + return nil + } + + if arg == "-" { + goto ShortParsing + } + + // explicitly request end of options? + if arg == "--" { + s.args = args + s.State = DashDash + return nil + } + + // Long option processing + if len(s.longOptions) > 0 && arg[1] == '-' { + e := strings.IndexRune(arg, '=') + var value string + if e > 0 { + value = arg[e+1:] + arg = arg[:e] + } + opt := s.longOptions[arg[2:]] + // If we are processing long options then --f is -f + // if f is not defined as a long option. + // This lets you say --f=false + if opt == nil && len(arg[2:]) == 1 { + opt = s.shortOptions[rune(arg[2])] + } + if opt == nil { + return unknownOption(arg[2:]) + } + opt.isLong = true + // If we require an option and did not have an = + // then use the next argument as an option. + if !opt.flag && e < 0 && !opt.optional { + if len(args) == 0 { + return missingArg(opt) + } + value = args[0] + args = args[1:] + } + opt.count++ + + if err := opt.value.Set(value, opt); err != nil { + return setError(opt, value, err) + } + + if !fn(opt) { + s.State = Terminated + return nil + } + continue Parsing + } + + // Short option processing + arg = arg[1:] // strip - + ShortParsing: + for i, c := range arg { + opt := s.shortOptions[c] + if opt == nil { + // In traditional getopt, if - is not registered + // as an option, a lone - is treated as + // if there were a -- in front of it. + if arg == "-" { + s.State = Dash + return nil + } + return unknownOption(c) + } + opt.isLong = false + opt.count++ + var value string + if !opt.flag { + value = arg[1+i:] + if value == "" && !opt.optional { + if len(args) == 0 { + return missingArg(opt) + } + value = args[0] + args = args[1:] + } + } + if err := opt.value.Set(value, opt); err != nil { + return setError(opt, value, err) + } + if !fn(opt) { + s.State = Terminated + return nil + } + if !opt.flag { + continue Parsing + } + } + } + s.args = []string{} + return nil +} diff --git a/vendor/github.com/pborman/getopt/int.go b/vendor/github.com/pborman/getopt/int.go new file mode 100644 index 0000000..3db5fd6 --- /dev/null +++ b/vendor/github.com/pborman/getopt/int.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type intValue int + +func (i *intValue) Set(value string, opt Option) error { + v, err := strconv.ParseInt(value, 0, strconv.IntSize) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = intValue(v) + return nil +} + +func (i *intValue) String() string { + return strconv.FormatInt(int64(*i), 10) +} + +// Int creates an option that parses its value as an integer. +func Int(name rune, value int, helpvalue ...string) *int { + return CommandLine.Int(name, value, helpvalue...) +} + +func (s *Set) Int(name rune, value int, helpvalue ...string) *int { + return s.IntLong("", name, value, helpvalue...) +} + +func IntLong(name string, short rune, value int, helpvalue ...string) *int { + return CommandLine.IntLong(name, short, value, helpvalue...) +} + +func (s *Set) IntLong(name string, short rune, value int, helpvalue ...string) *int { + s.IntVarLong(&value, name, short, helpvalue...) + return &value +} + +func IntVar(p *int, name rune, helpvalue ...string) Option { + return CommandLine.IntVar(p, name, helpvalue...) +} + +func (s *Set) IntVar(p *int, name rune, helpvalue ...string) Option { + return s.IntVarLong(p, "", name, helpvalue...) +} + +func IntVarLong(p *int, name string, short rune, helpvalue ...string) Option { + return CommandLine.IntVarLong(p, name, short, helpvalue...) +} + +func (s *Set) IntVarLong(p *int, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*intValue)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/int16.go b/vendor/github.com/pborman/getopt/int16.go new file mode 100644 index 0000000..2ece51f --- /dev/null +++ b/vendor/github.com/pborman/getopt/int16.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type int16Value int16 + +func (i *int16Value) Set(value string, opt Option) error { + v, err := strconv.ParseInt(value, 0, 16) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = int16Value(v) + return nil +} + +func (i *int16Value) String() string { + return strconv.FormatInt(int64(*i), 10) +} + +// Int16 creates an option that parses its value as an int16. +func Int16(name rune, value int16, helpvalue ...string) *int16 { + return CommandLine.Int16(name, value, helpvalue...) +} + +func (s *Set) Int16(name rune, value int16, helpvalue ...string) *int16 { + return s.Int16Long("", name, value, helpvalue...) +} + +func Int16Long(name string, short rune, value int16, helpvalue ...string) *int16 { + return CommandLine.Int16Long(name, short, value, helpvalue...) +} + +func (s *Set) Int16Long(name string, short rune, value int16, helpvalue ...string) *int16 { + s.Int16VarLong(&value, name, short, helpvalue...) + return &value +} + +func Int16Var(p *int16, name rune, helpvalue ...string) Option { + return CommandLine.Int16Var(p, name, helpvalue...) +} + +func (s *Set) Int16Var(p *int16, name rune, helpvalue ...string) Option { + return s.Int16VarLong(p, "", name, helpvalue...) +} + +func Int16VarLong(p *int16, name string, short rune, helpvalue ...string) Option { + return CommandLine.Int16VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Int16VarLong(p *int16, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*int16Value)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/int16_test.go b/vendor/github.com/pborman/getopt/int16_test.go new file mode 100644 index 0000000..8b83c1e --- /dev/null +++ b/vendor/github.com/pborman/getopt/int16_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var int16Tests = []struct { + where string + in []string + i int16 + int16 int16 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int16", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int16=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt16(t *testing.T) { + for x, tt := range int16Tests { + reset() + i := Int16('i', 17) + opt := Int16Long("int16", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int16; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/int32.go b/vendor/github.com/pborman/getopt/int32.go new file mode 100644 index 0000000..b8f3415 --- /dev/null +++ b/vendor/github.com/pborman/getopt/int32.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type int32Value int32 + +func (i *int32Value) Set(value string, opt Option) error { + v, err := strconv.ParseInt(value, 0, 32) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = int32Value(v) + return nil +} + +func (i *int32Value) String() string { + return strconv.FormatInt(int64(*i), 10) +} + +// Int32 creates an option that parses its value as an int32. +func Int32(name rune, value int32, helpvalue ...string) *int32 { + return CommandLine.Int32(name, value, helpvalue...) +} + +func (s *Set) Int32(name rune, value int32, helpvalue ...string) *int32 { + return s.Int32Long("", name, value, helpvalue...) +} + +func Int32Long(name string, short rune, value int32, helpvalue ...string) *int32 { + return CommandLine.Int32Long(name, short, value, helpvalue...) +} + +func (s *Set) Int32Long(name string, short rune, value int32, helpvalue ...string) *int32 { + s.Int32VarLong(&value, name, short, helpvalue...) + return &value +} + +func Int32Var(p *int32, name rune, helpvalue ...string) Option { + return CommandLine.Int32Var(p, name, helpvalue...) +} + +func (s *Set) Int32Var(p *int32, name rune, helpvalue ...string) Option { + return s.Int32VarLong(p, "", name, helpvalue...) +} + +func Int32VarLong(p *int32, name string, short rune, helpvalue ...string) Option { + return CommandLine.Int32VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Int32VarLong(p *int32, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*int32Value)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/int32_test.go b/vendor/github.com/pborman/getopt/int32_test.go new file mode 100644 index 0000000..9da9aeb --- /dev/null +++ b/vendor/github.com/pborman/getopt/int32_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var int32Tests = []struct { + where string + in []string + i int32 + int32 int32 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int32", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int32=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt32(t *testing.T) { + for x, tt := range int32Tests { + reset() + i := Int32('i', 17) + opt := Int32Long("int32", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int32; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/int64.go b/vendor/github.com/pborman/getopt/int64.go new file mode 100644 index 0000000..d29e6b4 --- /dev/null +++ b/vendor/github.com/pborman/getopt/int64.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type int64Value int64 + +func (i *int64Value) Set(value string, opt Option) error { + v, err := strconv.ParseInt(value, 0, 64) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = int64Value(v) + return nil +} + +func (i *int64Value) String() string { + return strconv.FormatInt(int64(*i), 10) +} + +// Int64 creates an option that parses its value as an int64. +func Int64(name rune, value int64, helpvalue ...string) *int64 { + return CommandLine.Int64(name, value, helpvalue...) +} + +func (s *Set) Int64(name rune, value int64, helpvalue ...string) *int64 { + return s.Int64Long("", name, value, helpvalue...) +} + +func Int64Long(name string, short rune, value int64, helpvalue ...string) *int64 { + return CommandLine.Int64Long(name, short, value, helpvalue...) +} + +func (s *Set) Int64Long(name string, short rune, value int64, helpvalue ...string) *int64 { + s.Int64VarLong(&value, name, short, helpvalue...) + return &value +} + +func Int64Var(p *int64, name rune, helpvalue ...string) Option { + return CommandLine.Int64Var(p, name, helpvalue...) +} + +func (s *Set) Int64Var(p *int64, name rune, helpvalue ...string) Option { + return s.Int64VarLong(p, "", name, helpvalue...) +} + +func Int64VarLong(p *int64, name string, short rune, helpvalue ...string) Option { + return CommandLine.Int64VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Int64VarLong(p *int64, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*int64Value)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/int64_test.go b/vendor/github.com/pborman/getopt/int64_test.go new file mode 100644 index 0000000..7fa01b5 --- /dev/null +++ b/vendor/github.com/pborman/getopt/int64_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var int64Tests = []struct { + where string + in []string + i int64 + int64 int64 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int64", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int64=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt64(t *testing.T) { + for x, tt := range int64Tests { + reset() + i := Int64('i', 17) + opt := Int64Long("int64", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int64; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/int_test.go b/vendor/github.com/pborman/getopt/int_test.go new file mode 100644 index 0000000..f12af31 --- /dev/null +++ b/vendor/github.com/pborman/getopt/int_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var intTests = []struct { + where string + in []string + i int + int int + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt(t *testing.T) { + for x, tt := range intTests { + reset() + i := Int('i', 17) + opt := IntLong("int", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/list.go b/vendor/github.com/pborman/getopt/list.go new file mode 100644 index 0000000..b9d4267 --- /dev/null +++ b/vendor/github.com/pborman/getopt/list.go @@ -0,0 +1,69 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "strings" + +type listValue []string + +func (s *listValue) Set(value string, opt Option) error { + a := strings.Split(value, ",") + // If this is the first time we are seen then nil out the + // default value. + if opt.Count() <= 1 { + *s = nil + } + *s = append(*s, a...) + return nil +} + +func (s *listValue) String() string { + return strings.Join([]string(*s), ",") +} + +// List creates an option that returns a slice of strings. The parameters +// passed are converted from a comma seperated value list into a slice. +// Subsequent occurrences append to the list. +func List(name rune, helpvalue ...string) *[]string { + return CommandLine.List(name, helpvalue...) +} + +func (s *Set) List(name rune, helpvalue ...string) *[]string { + p := []string{} + s.ListVar(&p, name, helpvalue...) + return &p +} + +func ListLong(name string, short rune, helpvalue ...string) *[]string { + return CommandLine.ListLong(name, short, helpvalue...) +} + +func (s *Set) ListLong(name string, short rune, helpvalue ...string) *[]string { + p := []string{} + s.ListVarLong(&p, name, short, helpvalue...) + return &p +} + +// ListVar creats a list option and places the values in p. If p is pointing +// to a list of values then those are considered the default values. The first +// time name is seen in the options the list will be set to list specified by +// the parameter to the option. Subsequent instances of the option will append +// to the list. +func ListVar(p *[]string, name rune, helpvalue ...string) Option { + return CommandLine.ListVar(p, name, helpvalue...) +} + +func (s *Set) ListVar(p *[]string, name rune, helpvalue ...string) Option { + return s.ListVarLong(p, "", name, helpvalue...) +} + +func ListVarLong(p *[]string, name string, short rune, helpvalue ...string) Option { + return CommandLine.ListVarLong(p, name, short, helpvalue...) +} + +func (s *Set) ListVarLong(p *[]string, name string, short rune, helpvalue ...string) Option { + opt := s.VarLong((*listValue)(p), name, short, helpvalue...) + return opt +} diff --git a/vendor/github.com/pborman/getopt/list_test.go b/vendor/github.com/pborman/getopt/list_test.go new file mode 100644 index 0000000..71f9c32 --- /dev/null +++ b/vendor/github.com/pborman/getopt/list_test.go @@ -0,0 +1,99 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "testing" + +var listTests = []struct { + where string + in []string + l, list []string + err string +}{ + { + loc(), + []string{}, + nil, nil, + "", + }, + { + loc(), + []string{"test", "-l", "one"}, + []string{"one"}, nil, + "", + }, + { + loc(), + []string{"test", "-lone", "-ltwo"}, + []string{"one", "two"}, nil, + "", + }, + { + loc(), + []string{"test", "--list", "one"}, + nil, []string{"one"}, + "", + }, + { + loc(), + []string{"test", "--list=one", "--list=two"}, + nil, []string{"one", "two"}, + "", + }, + { + loc(), + []string{"test", "--list=one,two"}, + nil, []string{"one", "two"}, + "", + }, +} + +func TestList(t *testing.T) { + for _, tt := range listTests { + reset() + l := List('l') + list := ListLong("list", 0) + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if badSlice(*l, tt.l) { + t.Errorf("%s: got s = %q, want %q", tt.where, *l, tt.l) + } + if badSlice(*list, tt.list) { + t.Errorf("%s: got s = %q, want %q", tt.where, *list, tt.list) + } + } +} + +func TestDefaultList(t *testing.T) { + reset() + list := []string{"d1", "d2", "d3"} + ListVar(&list, 'l') + parse([]string{"test"}) + + want := []string{"d1", "d2", "d3"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } + + parse([]string{"test", "-l", "one"}) + want = []string{"one"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } + + parse([]string{"test", "-l", "two"}) + want = []string{"one", "two"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } + Lookup('l').Reset() + want = []string{"d1", "d2", "d3"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } +} diff --git a/vendor/github.com/pborman/getopt/option.go b/vendor/github.com/pborman/getopt/option.go new file mode 100644 index 0000000..17dbe58 --- /dev/null +++ b/vendor/github.com/pborman/getopt/option.go @@ -0,0 +1,193 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" +) + +// An Option can be either a Flag or a Value +type Option interface { + // Name returns the name of the option. If the option has been seen + // then the last way it was referenced (short or long) is returned + // otherwise if there is a short name then this will be the short name + // as a string, else it will be the long name. + Name() string + + // IsFlag returns true if Option is a flag. + IsFlag() bool + + // Seen returns true if the flag was seen. + Seen() bool + + // Count returns the number of times the flag was seen. + Count() int + + // String returns the last value the option was set to. + String() string + + // Value returns the Value of the option. + Value() Value + + // SetOptional makes the value optional. The option and value are + // always a single argument. Either --option or --option=value. In + // the former case the value of the option does not change but the Set() + // will return true and the value returned by Count() is incremented. + // The short form is either -o or -ovalue. SetOptional returns + // the Option + SetOptional() Option + + // SetFlag makes the value a flag. Flags are boolean values and + // normally do not taken a value. They are set to true when seen. + // If a value is passed in the long form then it must be on, case + // insenstive, one of "true", "false", "t", "f", "on", "off", "1", "0". + // SetFlag returns the Option + SetFlag() Option + + // Reset resets the state of the option so it appears it has not + // yet been seen, including resetting the value of the option + // to its original default state. + Reset() +} + +type option struct { + short rune // 0 means no short name + long string // "" means no long name + isLong bool // True if they used the long name + flag bool // true if a boolean flag + defval string // default value + optional bool // true if we take an optional value + help string // help message + where string // file where the option was defined + value Value // current value of option + count int // number of times we have seen this option + name string // name of the value (for usage) + uname string // name of the option (for usage) +} + +// usageName returns the name of the option for printing usage lines in one +// of the following forms: +// +// -f +// --flag +// -f, --flag +// -s value +// --set=value +// -s, --set=value +func (o *option) usageName() string { + // Don't print help messages if we have none and there is only one + // way to specify the option. + if o.help == "" && (o.short == 0 || o.long == "") { + return "" + } + n := "" + + switch { + case o.short != 0 && o.long == "": + n = "-" + string(o.short) + case o.short == 0 && o.long != "": + n = " --" + o.long + case o.short != 0 && o.long != "": + n = "-" + string(o.short) + ", --" + o.long + } + + switch { + case o.flag: + return n + case o.optional: + return n + "[=" + o.name + "]" + case o.long != "": + return n + "=" + o.name + } + return n + " " + o.name +} + +// sortName returns the name to sort the option on. +func (o *option) sortName() string { + if o.short != 0 { + return string(o.short) + o.long + } + return o.long[:1] + o.long +} + +func (o *option) Seen() bool { return o.count > 0 } +func (o *option) Count() int { return o.count } +func (o *option) IsFlag() bool { return o.flag } +func (o *option) String() string { return o.value.String() } +func (o *option) SetOptional() Option { o.optional = true; return o } +func (o *option) SetFlag() Option { o.flag = true; return o } + +func (o *option) Value() Value { + if o == nil { + return nil + } + return o.value +} + +func (o *option) Name() string { + if !o.isLong && o.short != 0 { + return "-" + string(o.short) + } + return "--" + o.long +} + +// Reset rests an option so that it appears it has not yet been seen. +func (o *option) Reset() { + o.isLong = false + o.count = 0 + o.value.Set(o.defval, o) +} + +type optionList []*option + +func (ol optionList) Len() int { return len(ol) } +func (ol optionList) Swap(i, j int) { ol[i], ol[j] = ol[j], ol[i] } +func (ol optionList) Less(i, j int) bool { + // first check the short names (or the first letter of the long name) + // If they are not equal (case insensitive) then we have our answer + n1 := ol[i].sortName() + n2 := ol[j].sortName() + l1 := strings.ToLower(n1) + l2 := strings.ToLower(n2) + if l1 < l2 { + return true + } + if l2 < l1 { + return false + } + return n1 < n2 +} + +// AddOption add the option o to set CommandLine if o is not already in set +// CommandLine. +func AddOption(o Option) { + CommandLine.AddOption(o) +} + +// AddOption add the option o to set s if o is not already in set s. +func (s *Set) AddOption(o Option) { + opt := o.(*option) + for _, eopt := range s.options { + if opt == eopt { + return + } + } + if opt.short != 0 { + if oo, ok := s.shortOptions[opt.short]; ok { + fmt.Fprintf(stderr, "%s: -%c already declared at %s\n", opt.where, opt.short, oo.where) + exit(1) + } + s.shortOptions[opt.short] = opt + } + if opt.long != "" { + if oo, ok := s.longOptions[opt.long]; ok { + fmt.Fprintf(stderr, "%s: --%s already declared at %s\n", opt.where, opt.long, oo.where) + exit(1) + } + s.longOptions[opt.long] = opt + } + s.options = append(s.options, opt) +} diff --git a/vendor/github.com/pborman/getopt/set.go b/vendor/github.com/pborman/getopt/set.go new file mode 100644 index 0000000..64d9ecf --- /dev/null +++ b/vendor/github.com/pborman/getopt/set.go @@ -0,0 +1,268 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "io" + "os" + "sort" +) + +// A Termination says why Getopt returned. +type State int + +const ( + InProgress = State(iota) // Getopt is still running + Dash // Returned on "-" + DashDash // Returned on "--" + EndOfOptions // End of options reached + EndOfArguments // No more arguments + Terminated // Terminated by callback function + Failure // Terminated due to error + Unknown // Indicates internal error +) + +type Set struct { + State // State of getopt + + // args are the parameters remaining after parsing the optoins. + args []string + + // program is the name of the program for usage and error messages. + // If not set it will automatically be set to the base name of the + // first argument passed to parse. + program string + + // parameters is what is displayed on the usage line after displaying + // the various options. + parameters string + + usage func() // usage should print the programs usage and exit. + + shortOptions map[rune]*option + longOptions map[string]*option + options optionList +} + +// New returns a newly created option set. +func New() *Set { + s := &Set{ + shortOptions: make(map[rune]*option), + longOptions: make(map[string]*option), + parameters: "[parameters ...]", + } + + s.usage = func() { + s.PrintUsage(stderr) + } + return s +} + +// The default set of command-line options. +var CommandLine = New() + +// PrintUsage calls PrintUsage in the default option set. +func PrintUsage(w io.Writer) { CommandLine.PrintUsage(w) } + +// Usage calls the usage function in the default option set. +func Usage() { CommandLine.usage() } + +// Parse calls Parse in the default option set with the command line arguments +// found in os.Args. +func Parse() { CommandLine.Parse(os.Args) } + +// Getops returns the result of calling Getop in the default option set with the +// command line arguments found in os.Args. The fn function, which may be nil, +// is passed to Getopt. +func Getopt(fn func(Option) bool) error { return CommandLine.Getopt(os.Args, fn) } + +// Arg returns the n'th command-line argument. Arg(0) is the first remaining +// argument after options have been processed. +func Arg(n int) string { + if n >= 0 && n < len(CommandLine.args) { + return CommandLine.args[n] + } + return "" +} + +// Arg returns the n'th argument. Arg(0) is the first remaining +// argument after options have been processed. +func (s *Set) Arg(n int) string { + if n >= 0 && n < len(s.args) { + return s.args[n] + } + return "" +} + +// Args returns the non-option command line arguments. +func Args() []string { + return CommandLine.args +} + +// Args returns the non-option arguments. +func (s *Set) Args() []string { + return s.args +} + +// NArgs returns the number of non-option command line arguments. +func NArgs() int { + return len(CommandLine.args) +} + +// NArgs returns the number of non-option arguments. +func (s *Set) NArgs() int { + return len(s.args) +} + +// SetParameters sets the parameters string for printing the command line +// usage. It defaults to "[parameters ...]" +func SetParameters(parameters string) { + CommandLine.parameters = parameters +} + +// SetParameters sets the parameters string for printing the s's usage. +// It defaults to "[parameters ...]" +func (s *Set) SetParameters(parameters string) { + s.parameters = parameters +} + +// SetProgram sets the program name to program. Nomrally it is determined +// from the zeroth command line argument (see os.Args). +func SetProgram(program string) { + CommandLine.program = program +} + +// SetProgram sets s's program name to program. Nomrally it is determined +// from the zeroth argument passed to Getopt or Parse. +func (s *Set) SetProgram(program string) { + s.program = program +} + +// SetUsage sets the function used by Parse to display the commands usage +// on error. It defaults to calling PrintUsage(os.Stderr). +func SetUsage(usage func()) { + CommandLine.usage = usage +} + +// SetUsage sets the function used by Parse to display usage on error. It +// defaults to calling f.PrintUsage(os.Stderr). +func (s *Set) SetUsage(usage func()) { + s.usage = usage +} + +// Lookup returns the Option associated with name. Name should either be +// a rune (the short name) or a string (the long name). +func Lookup(name interface{}) Option { + return CommandLine.Lookup(name) +} + +// Lookup returns the Option associated with name in s. Name should either be +// a rune (the short name) or a string (the long name). +func (s *Set) Lookup(name interface{}) Option { + switch v := name.(type) { + case rune: + return s.shortOptions[v] + case int: + return s.shortOptions[rune(v)] + case string: + return s.longOptions[v] + } + return nil +} + +// IsSet returns true if the Option associated with name was seen while +// parsing the command line arguments. Name should either be a rune (the +// short name) or a string (the long name). +func IsSet(name interface{}) bool { + return CommandLine.IsSet(name) +} + +// IsSet returns true if the Option associated with name was seen while +// parsing s. Name should either be a rune (the short name) or a string (the +// long name). +func (s *Set) IsSet(name interface{}) bool { + if opt := s.Lookup(name); opt != nil { + return opt.Seen() + } + return false +} + +// GetCount returns the number of times the Option associated with name has been +// seen while parsing the command line arguments. Name should either be a rune +// (the short name) or a string (the long name). +func GetCount(name interface{}) int { + return CommandLine.GetCount(name) +} + +// GetCount returns the number of times the Option associated with name has been +// seen while parsing s's arguments. Name should either be a rune (the short +// name) or a string (the long name). +func (s *Set) GetCount(name interface{}) int { + if opt := s.Lookup(name); opt != nil { + return opt.Count() + } + return 0 +} + +// GetValue returns the final value set to the command-line Option with name. +// If the option has not been seen while parsing s then the default value is +// returned. Name should either be a rune (the short name) or a string (the +// long name). +func GetValue(name interface{}) string { + return CommandLine.GetValue(name) +} + +// GetValue returns the final value set to the Option in s associated with name. +// If the option has not been seen while parsing s then the default value is +// returned. Name should either be a rune (the short name) or a string (the +// long name). +func (s *Set) GetValue(name interface{}) string { + if opt := s.Lookup(name); opt != nil { + return opt.String() + } + return "" +} + +// Visit visits the command-line options in lexicographical order, calling fn +// for each. It visits only those options that have been set. +func Visit(fn func(Option)) { CommandLine.Visit(fn) } + +// Visit visits the options in s in lexicographical order, calling fn +// for each. It visits only those options that have been set. +func (s *Set) Visit(fn func(Option)) { + sort.Sort(s.options) + for _, opt := range s.options { + if opt.count > 0 { + fn(opt) + } + } +} + +// VisitAll visits the options in s in lexicographical order, calling fn +// for each. It visits all options, even those not set. +func VisitAll(fn func(Option)) { CommandLine.VisitAll(fn) } + +// VisitAll visits the command-line flags in lexicographical order, calling fn +// for each. It visits all flags, even those not set. +func (s *Set) VisitAll(fn func(Option)) { + sort.Sort(s.options) + for _, opt := range s.options { + fn(opt) + } +} + +// Reset resets all the command line options to the initial state so it +// appears none of them have been seen. +func Reset() { + CommandLine.Reset() +} + +// Reset resets all the options in s to the initial state so it +// appears none of them have been seen. +func (s *Set) Reset() { + for _, opt := range s.options { + opt.Reset() + } +} diff --git a/vendor/github.com/pborman/getopt/signed.go b/vendor/github.com/pborman/getopt/signed.go new file mode 100644 index 0000000..a0e059c --- /dev/null +++ b/vendor/github.com/pborman/getopt/signed.go @@ -0,0 +1,110 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type signed int64 + +type SignedLimit struct { + Base int // Base for conversion as per strconv.ParseInt + Bits int // Number of bits as per strconv.ParseInt + Min int64 // Minimum allowed value if both Min and Max are not 0 + Max int64 // Maximum allowed value if both Min and Max are not 0 +} + +var signedLimits = make(map[*signed]*SignedLimit) + +func (n *signed) Set(value string, opt Option) error { + l := signedLimits[n] + if l == nil { + return fmt.Errorf("no limits defined for %s", opt.Name()) + } + v, err := strconv.ParseInt(value, l.Base, l.Bits) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + if l.Min != 0 || l.Max != 0 { + if v < l.Min { + return fmt.Errorf("value out of range (<%v): %s", l.Min, value) + } + if v > l.Max { + return fmt.Errorf("value out of range (>%v): %s", l.Max, value) + } + } + *n = signed(v) + return nil +} + +func (n *signed) String() string { + l := signedLimits[n] + if l != nil && l.Base != 0 { + return strconv.FormatInt(int64(*n), l.Base) + } + return strconv.FormatInt(int64(*n), 10) +} + +// Signed creates an option that is stored in an int64 and is constrained +// by the limits pointed to by l. The Max and Min values are only used if +// at least one of the values are not 0. If Base is 0, the base is implied by +// the string's prefix: base 16 for "0x", base 8 for "0", and base 10 otherwise. +func Signed(name rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + return CommandLine.Signed(name, value, l, helpvalue...) +} + +func (s *Set) Signed(name rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + return s.SignedLong("", name, value, l, helpvalue...) +} + +func SignedLong(name string, short rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + return CommandLine.SignedLong(name, short, value, l, helpvalue...) +} + +func (s *Set) SignedLong(name string, short rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + s.SignedVarLong(&value, name, short, l, helpvalue...) + return &value +} + +func SignedVar(p *int64, name rune, l *SignedLimit, helpvalue ...string) Option { + return CommandLine.SignedVar(p, name, l, helpvalue...) +} + +func (s *Set) SignedVar(p *int64, name rune, l *SignedLimit, helpvalue ...string) Option { + return s.SignedVarLong(p, "", name, l, helpvalue...) +} + +func SignedVarLong(p *int64, name string, short rune, l *SignedLimit, helpvalue ...string) Option { + return CommandLine.SignedVarLong(p, name, short, l, helpvalue...) +} + +func (s *Set) SignedVarLong(p *int64, name string, short rune, l *SignedLimit, helpvalue ...string) Option { + opt := s.VarLong((*signed)(p), name, short, helpvalue...) + if l.Base > 36 || l.Base == 1 || l.Base < 0 { + fmt.Fprintf(stderr, "invalid base for %s: %d\n", opt.Name(), l.Base) + exit(1) + } + if l.Bits < 0 || l.Bits > 64 { + fmt.Fprintf(stderr, "invalid bit size for %s: %d\n", opt.Name(), l.Bits) + exit(1) + } + if l.Min > l.Max { + fmt.Fprintf(stderr, "min greater than max for %s\n", opt.Name()) + exit(1) + } + lim := *l + signedLimits[(*signed)(p)] = &lim + return opt +} diff --git a/vendor/github.com/pborman/getopt/signed_test.go b/vendor/github.com/pborman/getopt/signed_test.go new file mode 100644 index 0000000..2d0635a --- /dev/null +++ b/vendor/github.com/pborman/getopt/signed_test.go @@ -0,0 +1,97 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var signedNumberTests = []struct { + where string + in []string + l SignedLimit + out int64 + err string +}{ + { + where: loc(), + }, + { + loc(), + []string{"test", "-n", "1010"}, + SignedLimit{Base: 2, Bits: 5}, + 10, + "", + }, + { + loc(), + []string{"test", "-n", "1010"}, + SignedLimit{Base: 2, Bits: 4}, + 0, + "test: value out of range: 1010\n", + }, + { + loc(), + []string{"test", "-n", "-1000"}, + SignedLimit{Base: 2, Bits: 4}, + -8, + "", + }, + { + loc(), + []string{"test", "-n", "3"}, + SignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (<4): 3\n", + }, + { + loc(), + []string{"test", "-n", "4"}, + SignedLimit{Min: 4, Max: 6}, + 4, + "", + }, + { + loc(), + []string{"test", "-n", "5"}, + SignedLimit{Min: 4, Max: 6}, + 5, + "", + }, + { + loc(), + []string{"test", "-n", "6"}, + SignedLimit{Min: 4, Max: 6}, + 6, + "", + }, + { + loc(), + []string{"test", "-n", "7"}, + SignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (>6): 7\n", + }, +} + +func TestSigneds(t *testing.T) { + for x, tt := range signedNumberTests { + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + reset() + n := Signed('n', 0, &tt.l) + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *n != tt.out { + t.Errorf("%s: got %v, want %v", tt.where, *n, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/string.go b/vendor/github.com/pborman/getopt/string.go new file mode 100644 index 0000000..1121867 --- /dev/null +++ b/vendor/github.com/pborman/getopt/string.go @@ -0,0 +1,53 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +type stringValue string + +func (s *stringValue) Set(value string, opt Option) error { + *s = stringValue(value) + return nil +} + +func (s *stringValue) String() string { + return string(*s) +} + +// String returns a value option that stores is value as a string. The +// initial value of the string is passed in value. +func String(name rune, value string, helpvalue ...string) *string { + return CommandLine.String(name, value, helpvalue...) +} + +func (s *Set) String(name rune, value string, helpvalue ...string) *string { + p := value + s.StringVarLong(&p, "", name, helpvalue...) + return &p +} + +func StringLong(name string, short rune, value string, helpvalue ...string) *string { + return CommandLine.StringLong(name, short, value, helpvalue...) +} + +func (s *Set) StringLong(name string, short rune, value string, helpvalue ...string) *string { + s.StringVarLong(&value, name, short, helpvalue...) + return &value +} + +func StringVar(p *string, name rune, helpvalue ...string) Option { + return CommandLine.StringVar(p, name, helpvalue...) +} + +func (s *Set) StringVar(p *string, name rune, helpvalue ...string) Option { + return s.VarLong((*stringValue)(p), "", name, helpvalue...) +} + +func StringVarLong(p *string, name string, short rune, helpvalue ...string) Option { + return CommandLine.StringVarLong(p, name, short, helpvalue...) +} + +func (s *Set) StringVarLong(p *string, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*stringValue)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/string_test.go b/vendor/github.com/pborman/getopt/string_test.go new file mode 100644 index 0000000..c39a56c --- /dev/null +++ b/vendor/github.com/pborman/getopt/string_test.go @@ -0,0 +1,77 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "testing" + +var stringTests = []struct { + where string + in []string + sout string + optout string + err string +}{ + { + loc(), + []string{}, + "one", + "two", + "", + }, + { + loc(), + []string{"test", "-s"}, + "one", + "two", + "test: missing parameter for -s\n", + }, + { + loc(), + []string{"test", "--opt"}, + "one", + "two", + "test: missing parameter for --opt\n", + }, + { + loc(), + []string{"test", "-svalue", "--opt=option"}, + "value", + "option", + "", + }, + { + loc(), + []string{"test", "-s", "value", "--opt", "option"}, + "value", + "option", + "", + }, + { + loc(), + []string{"test", "-swrong", "--opt=wrong", "-s", "value", "--opt", "option"}, + "value", + "option", + "", + }, +} + +func TestString(t *testing.T) { + for _, tt := range stringTests { + reset() + s := String('s', "one") + opt := StringLong("opt", 0, "two") + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *s != tt.sout { + t.Errorf("%s: got s = %q, want %q", tt.where, *s, tt.sout) + } + if *opt != tt.optout { + t.Errorf("%s: got opt = %q, want %q", tt.where, *opt, tt.optout) + } + } +} diff --git a/vendor/github.com/pborman/getopt/uint.go b/vendor/github.com/pborman/getopt/uint.go new file mode 100644 index 0000000..bdb82b4 --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type uintValue uint + +func (i *uintValue) Set(value string, opt Option) error { + v, err := strconv.ParseUint(value, 0, strconv.IntSize) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = uintValue(v) + return nil +} + +func (i *uintValue) String() string { + return strconv.FormatUint(uint64(*i), 10) +} + +// Uint creates an option that parses its value as an unsigned integer. +func Uint(name rune, value uint, helpvalue ...string) *uint { + return CommandLine.Uint(name, value, helpvalue...) +} + +func (s *Set) Uint(name rune, value uint, helpvalue ...string) *uint { + return s.UintLong("", name, value, helpvalue...) +} + +func UintLong(name string, short rune, value uint, helpvalue ...string) *uint { + return CommandLine.UintLong(name, short, value, helpvalue...) +} + +func (s *Set) UintLong(name string, short rune, value uint, helpvalue ...string) *uint { + s.UintVarLong(&value, name, short, helpvalue...) + return &value +} + +func UintVar(p *uint, name rune, helpvalue ...string) Option { + return CommandLine.UintVar(p, name, helpvalue...) +} + +func (s *Set) UintVar(p *uint, name rune, helpvalue ...string) Option { + return s.UintVarLong(p, "", name, helpvalue...) +} + +func UintVarLong(p *uint, name string, short rune, helpvalue ...string) Option { + return CommandLine.UintVarLong(p, name, short, helpvalue...) +} + +func (s *Set) UintVarLong(p *uint, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*uintValue)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/uint16.go b/vendor/github.com/pborman/getopt/uint16.go new file mode 100644 index 0000000..92013e0 --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint16.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type uint16Value uint16 + +func (i *uint16Value) Set(value string, opt Option) error { + v, err := strconv.ParseUint(value, 0, 16) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = uint16Value(v) + return nil +} + +func (i *uint16Value) String() string { + return strconv.FormatUint(uint64(*i), 10) +} + +// Uint16 creates an option that parses its value as an uint16. +func Uint16(name rune, value uint16, helpvalue ...string) *uint16 { + return CommandLine.Uint16(name, value, helpvalue...) +} + +func (s *Set) Uint16(name rune, value uint16, helpvalue ...string) *uint16 { + return s.Uint16Long("", name, value, helpvalue...) +} + +func Uint16Long(name string, short rune, value uint16, helpvalue ...string) *uint16 { + return CommandLine.Uint16Long(name, short, value, helpvalue...) +} + +func (s *Set) Uint16Long(name string, short rune, value uint16, helpvalue ...string) *uint16 { + s.Uint16VarLong(&value, name, short, helpvalue...) + return &value +} + +func Uint16Var(p *uint16, name rune, helpvalue ...string) Option { + return CommandLine.Uint16Var(p, name, helpvalue...) +} + +func (s *Set) Uint16Var(p *uint16, name rune, helpvalue ...string) Option { + return s.Uint16VarLong(p, "", name, helpvalue...) +} + +func Uint16VarLong(p *uint16, name string, short rune, helpvalue ...string) Option { + return CommandLine.Uint16VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Uint16VarLong(p *uint16, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*uint16Value)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/uint16_test.go b/vendor/github.com/pborman/getopt/uint16_test.go new file mode 100644 index 0000000..5363a0c --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint16_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var uint16Tests = []struct { + where string + in []string + i uint16 + uint16 uint16 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint16", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint16=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint16(t *testing.T) { + for x, tt := range uint16Tests { + reset() + i := Uint16('i', 17) + opt := Uint16Long("uint16", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint16; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/uint32.go b/vendor/github.com/pborman/getopt/uint32.go new file mode 100644 index 0000000..abe911d --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint32.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type uint32Value uint32 + +func (i *uint32Value) Set(value string, opt Option) error { + v, err := strconv.ParseUint(value, 0, 32) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = uint32Value(v) + return nil +} + +func (i *uint32Value) String() string { + return strconv.FormatUint(uint64(*i), 10) +} + +// Uint32 creates an option that parses its value as an uint32. +func Uint32(name rune, value uint32, helpvalue ...string) *uint32 { + return CommandLine.Uint32(name, value, helpvalue...) +} + +func (s *Set) Uint32(name rune, value uint32, helpvalue ...string) *uint32 { + return s.Uint32Long("", name, value, helpvalue...) +} + +func Uint32Long(name string, short rune, value uint32, helpvalue ...string) *uint32 { + return CommandLine.Uint32Long(name, short, value, helpvalue...) +} + +func (s *Set) Uint32Long(name string, short rune, value uint32, helpvalue ...string) *uint32 { + s.Uint32VarLong(&value, name, short, helpvalue...) + return &value +} + +func Uint32Var(p *uint32, name rune, helpvalue ...string) Option { + return CommandLine.Uint32Var(p, name, helpvalue...) +} + +func (s *Set) Uint32Var(p *uint32, name rune, helpvalue ...string) Option { + return s.Uint32VarLong(p, "", name, helpvalue...) +} + +func Uint32VarLong(p *uint32, name string, short rune, helpvalue ...string) Option { + return CommandLine.Uint32VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Uint32VarLong(p *uint32, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*uint32Value)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/uint32_test.go b/vendor/github.com/pborman/getopt/uint32_test.go new file mode 100644 index 0000000..80b4d11 --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint32_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var uint32Tests = []struct { + where string + in []string + i uint32 + uint32 uint32 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint32", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint32=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint32(t *testing.T) { + for x, tt := range uint32Tests { + reset() + i := Uint32('i', 17) + opt := Uint32Long("uint32", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint32; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/uint64.go b/vendor/github.com/pborman/getopt/uint64.go new file mode 100644 index 0000000..788e97f --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint64.go @@ -0,0 +1,67 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type uint64Value uint64 + +func (i *uint64Value) Set(value string, opt Option) error { + v, err := strconv.ParseUint(value, 0, 64) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *i = uint64Value(v) + return nil +} + +func (i *uint64Value) String() string { + return strconv.FormatUint(uint64(*i), 10) +} + +// Uint64 creates an option that parses its value as a uint64. +func Uint64(name rune, value uint64, helpvalue ...string) *uint64 { + return CommandLine.Uint64(name, value, helpvalue...) +} + +func (s *Set) Uint64(name rune, value uint64, helpvalue ...string) *uint64 { + return s.Uint64Long("", name, value, helpvalue...) +} + +func Uint64Long(name string, short rune, value uint64, helpvalue ...string) *uint64 { + return CommandLine.Uint64Long(name, short, value, helpvalue...) +} + +func (s *Set) Uint64Long(name string, short rune, value uint64, helpvalue ...string) *uint64 { + s.Uint64VarLong(&value, name, short, helpvalue...) + return &value +} + +func Uint64Var(p *uint64, name rune, helpvalue ...string) Option { + return CommandLine.Uint64Var(p, name, helpvalue...) +} + +func (s *Set) Uint64Var(p *uint64, name rune, helpvalue ...string) Option { + return s.Uint64VarLong(p, "", name, helpvalue...) +} + +func Uint64VarLong(p *uint64, name string, short rune, helpvalue ...string) Option { + return CommandLine.Uint64VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Uint64VarLong(p *uint64, name string, short rune, helpvalue ...string) Option { + return s.VarLong((*uint64Value)(p), name, short, helpvalue...) +} diff --git a/vendor/github.com/pborman/getopt/uint64_test.go b/vendor/github.com/pborman/getopt/uint64_test.go new file mode 100644 index 0000000..962d369 --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint64_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var uint64Tests = []struct { + where string + in []string + i uint64 + uint64 uint64 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint64", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint64=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint64(t *testing.T) { + for x, tt := range uint64Tests { + reset() + i := Uint64('i', 17) + opt := Uint64Long("uint64", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint64; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/uint_test.go b/vendor/github.com/pborman/getopt/uint_test.go new file mode 100644 index 0000000..48c38cb --- /dev/null +++ b/vendor/github.com/pborman/getopt/uint_test.go @@ -0,0 +1,84 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var uintTests = []struct { + where string + in []string + i uint + uint uint + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint(t *testing.T) { + for x, tt := range uintTests { + reset() + i := Uint('i', 17) + opt := UintLong("uint", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/unsigned.go b/vendor/github.com/pborman/getopt/unsigned.go new file mode 100644 index 0000000..3ded0e7 --- /dev/null +++ b/vendor/github.com/pborman/getopt/unsigned.go @@ -0,0 +1,111 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type unsigned uint64 + +type UnsignedLimit struct { + Base int // Base for conversion as per strconv.ParseInt + Bits int // Number of bits as per strconv.ParseInt + Min uint64 // Minimum allowed value if both Min and Max are not 0 + Max uint64 // Maximum allowed value if both Min and Max are not 0 +} + +var unsignedLimits = make(map[*unsigned]*UnsignedLimit) + +func (n *unsigned) Set(value string, opt Option) error { + l := unsignedLimits[n] + if l == nil { + return fmt.Errorf("no limits defined for %s", opt.Name()) + } + v, err := strconv.ParseUint(value, l.Base, l.Bits) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + if l.Min != 0 || l.Max != 0 { + if v < l.Min { + return fmt.Errorf("value out of range (<%v): %s", l.Min, value) + } + if v > l.Max { + return fmt.Errorf("value out of range (>%v): %s", l.Max, value) + } + } + *n = unsigned(v) + return nil +} + +func (n *unsigned) String() string { + l := unsignedLimits[n] + if l != nil && l.Base != 0 { + return strconv.FormatUint(uint64(*n), l.Base) + } + return strconv.FormatUint(uint64(*n), 10) +} + +// Unsigned creates an option that is stored in a uint64 and is +// constrained by the limits pointed to by l. The Max and Min values are only +// used if at least one of the values are not 0. If Base is 0, the base is +// implied by the string's prefix: base 16 for "0x", base 8 for "0", and base +// 10 otherwise. +func Unsigned(name rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + return CommandLine.Unsigned(name, value, l, helpvalue...) +} + +func (s *Set) Unsigned(name rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + return s.UnsignedLong("", name, value, l, helpvalue...) +} + +func UnsignedLong(name string, short rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + return CommandLine.UnsignedLong(name, short, value, l, helpvalue...) +} + +func (s *Set) UnsignedLong(name string, short rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + s.UnsignedVarLong(&value, name, short, l, helpvalue...) + return &value +} + +func UnsignedVar(p *uint64, name rune, l *UnsignedLimit, helpvalue ...string) Option { + return CommandLine.UnsignedVar(p, name, l, helpvalue...) +} + +func (s *Set) UnsignedVar(p *uint64, name rune, l *UnsignedLimit, helpvalue ...string) Option { + return s.UnsignedVarLong(p, "", name, l, helpvalue...) +} + +func UnsignedVarLong(p *uint64, name string, short rune, l *UnsignedLimit, helpvalue ...string) Option { + return CommandLine.UnsignedVarLong(p, name, short, l, helpvalue...) +} + +func (s *Set) UnsignedVarLong(p *uint64, name string, short rune, l *UnsignedLimit, helpvalue ...string) Option { + opt := s.VarLong((*unsigned)(p), name, short, helpvalue...) + if l.Base > 36 || l.Base == 1 || l.Base < 0 { + fmt.Fprintf(stderr, "invalid base for %s: %d\n", opt.Name(), l.Base) + exit(1) + } + if l.Bits < 0 || l.Bits > 64 { + fmt.Fprintf(stderr, "invalid bit size for %s: %d\n", opt.Name(), l.Bits) + exit(1) + } + if l.Min > l.Max { + fmt.Fprintf(stderr, "min greater than max for %s\n", opt.Name()) + exit(1) + } + lim := *l + unsignedLimits[(*unsigned)(p)] = &lim + return opt +} diff --git a/vendor/github.com/pborman/getopt/unsigned_test.go b/vendor/github.com/pborman/getopt/unsigned_test.go new file mode 100644 index 0000000..0fd60d4 --- /dev/null +++ b/vendor/github.com/pborman/getopt/unsigned_test.go @@ -0,0 +1,97 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var unsignedTests = []struct { + where string + in []string + l UnsignedLimit + out uint64 + err string +}{ + { + where: loc(), + }, + { + loc(), + []string{"test", "-n", "1010"}, + UnsignedLimit{Base: 2, Bits: 5}, + 10, + "", + }, + { + loc(), + []string{"test", "-n", "1010"}, + UnsignedLimit{Base: 2, Bits: 4}, + 10, + "", + }, + { + loc(), + []string{"test", "-n", "1010"}, + UnsignedLimit{Base: 2, Bits: 3}, + 0, + "test: value out of range: 1010\n", + }, + { + loc(), + []string{"test", "-n", "3"}, + UnsignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (<4): 3\n", + }, + { + loc(), + []string{"test", "-n", "4"}, + UnsignedLimit{Min: 4, Max: 6}, + 4, + "", + }, + { + loc(), + []string{"test", "-n", "5"}, + UnsignedLimit{Min: 4, Max: 6}, + 5, + "", + }, + { + loc(), + []string{"test", "-n", "6"}, + UnsignedLimit{Min: 4, Max: 6}, + 6, + "", + }, + { + loc(), + []string{"test", "-n", "7"}, + UnsignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (>6): 7\n", + }, +} + +func TestUnsigneds(t *testing.T) { + for x, tt := range unsignedTests { + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + reset() + n := Unsigned('n', 0, &tt.l) + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *n != tt.out { + t.Errorf("%s: got %v, want %v", tt.where, *n, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/util_test.go b/vendor/github.com/pborman/getopt/util_test.go new file mode 100644 index 0000000..79a732a --- /dev/null +++ b/vendor/github.com/pborman/getopt/util_test.go @@ -0,0 +1,87 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "bytes" + "fmt" + "path" + "reflect" + "runtime" + "strings" +) + +var errorString string + +func reset() { + CommandLine.shortOptions = make(map[rune]*option) + CommandLine.longOptions = make(map[string]*option) + CommandLine.options = nil + CommandLine.args = nil + CommandLine.program = "" + errorString = "" +} + +func parse(args []string) { + err := CommandLine.Getopt(args, nil) + if err != nil { + b := &bytes.Buffer{} + + fmt.Fprintln(b, CommandLine.program+": "+err.Error()) + CommandLine.PrintUsage(b) + errorString = b.String() + } +} + +func badSlice(a, b []string) bool { + if len(a) != len(b) { + return true + } + for x, v := range a { + if b[x] != v { + return true + } + } + return false +} + +func loc() string { + _, file, line, _ := runtime.Caller(1) + return fmt.Sprintf("%s:%d", path.Base(file), line) +} + +func (o *option) Equal(opt *option) bool { + if o.value != nil && opt.value == nil { + return false + } + if o.value == nil && opt.value != nil { + return false + } + if o.value != nil && o.value.String() != opt.value.String() { + return false + } + + oc := *o + optc := *opt + oc.value = nil + optc.value = nil + return reflect.DeepEqual(&oc, &optc) +} + +func newStringValue(s string) *stringValue { return (*stringValue)(&s) } + +func checkError(err string) string { + switch { + case err == errorString: + return "" + case err == "": + return fmt.Sprintf("unexpected error %q", errorString) + case errorString == "": + return fmt.Sprintf("did not get expected error %q", err) + case !strings.HasPrefix(errorString, err): + return fmt.Sprintf("got error %q, want %q", errorString, err) + } + return "" +} diff --git a/vendor/github.com/pborman/getopt/v2/bool.go b/vendor/github.com/pborman/getopt/v2/bool.go new file mode 100644 index 0000000..2899bee --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/bool.go @@ -0,0 +1,36 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +// Bool creates a flag option that is a bool. Bools normally do not take a +// value however one can be assigned by using the long form of the option: +// +// --option=true +// --o=false +// +// The value is case insensitive and one of true, false, t, f, on, off, t and 0. +func Bool(name rune, helpvalue ...string) *bool { + var b bool + CommandLine.Flag(&b, name, helpvalue...) + return &b +} + +func BoolLong(name string, short rune, helpvalue ...string) *bool { + var p bool + CommandLine.FlagLong(&p, name, short, helpvalue...) + return &p +} + +func (s *Set) Bool(name rune, helpvalue ...string) *bool { + var b bool + s.Flag(&b, name, helpvalue...) + return &b +} + +func (s *Set) BoolLong(name string, short rune, helpvalue ...string) *bool { + var p bool + s.FlagLong(&p, name, short, helpvalue...) + return &p +} diff --git a/vendor/github.com/pborman/getopt/v2/bool_test.go b/vendor/github.com/pborman/getopt/v2/bool_test.go new file mode 100644 index 0000000..0a90d96 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/bool_test.go @@ -0,0 +1,106 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var boolTests = []struct { + where string + in []string + f bool + fc int + opt bool + optc int + err string +}{ + { + loc(), + []string{}, + false, 0, + false, 0, + "", + }, + { + loc(), + []string{"test", "-f", "--opt"}, + true, 1, + true, 1, + "", + }, + { + loc(), + []string{"test", "--f", "--opt"}, + true, 1, + true, 1, + "", + }, + { + loc(), + []string{"test", "-ff", "-f", "--opt", "--opt"}, + true, 3, + true, 2, + "", + }, + { + loc(), + []string{"test", "--opt", "--opt=false"}, + false, 0, + false, 2, + "", + }, + { + loc(), + []string{"test", "-f", "false"}, + true, 1, + false, 0, + "", + }, + { + loc(), + []string{"test", "-f=false"}, + true, 1, + false, 0, + "test: unknown option: -=\n", + }, + { + loc(), + []string{"test", "-f", "false"}, + true, 1, + false, 0, + "", + }, +} + +func TestBool(t *testing.T) { + for x, tt := range boolTests { + reset() + f := Bool('f') + opt := BoolLong("opt", 0) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *f, tt.f; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.opt; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := GetCount('f'), tt.fc; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := GetCount("opt"), tt.optc; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/breakup_test.go b/vendor/github.com/pborman/getopt/v2/breakup_test.go new file mode 100644 index 0000000..5609e50 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/breakup_test.go @@ -0,0 +1,34 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "testing" +) + +var breakupTests = []struct { + in string + max int + out []string +}{ + {"", 8, []string{}}, + {"a fox", 8, []string{"a fox"}}, + {"a foxhound is sly", 2, []string{"a", "foxhound", "is", "sly"}}, + {"a foxhound is sly", 5, []string{"a", "foxhound", "is", "sly"}}, + {"a foxhound is sly", 6, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 7, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 8, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 9, []string{"a", "foxhound", "is sly"}}, + {"a foxhound is sly", 10, []string{"a foxhound", "is sly"}}, +} + +func TestBreakup(t *testing.T) { + for x, tt := range breakupTests { + out := breakup(tt.in, tt.max) + if badSlice(out, tt.out) { + t.Errorf("#%d: got %v, want %v", x, out, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/counter.go b/vendor/github.com/pborman/getopt/v2/counter.go new file mode 100644 index 0000000..ab10bc7 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/counter.go @@ -0,0 +1,69 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" +) + +type counterValue int + +func (b *counterValue) Set(value string, opt Option) error { + if value == "" { + *b++ + } else { + v, err := strconv.ParseInt(value, 0, strconv.IntSize) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + *b = counterValue(v) + } + return nil +} + +func (b *counterValue) String() string { + return strconv.Itoa(int(*b)) +} + +// Counter creates a counting flag stored as an int. Each time the option +// is seen while parsing the value is incremented. The value of the counter +// may be explicitly set by using the long form: +// +// --counter=5 +// --c=5 +// +// Further instances of the option will increment from the set value. +func Counter(name rune, helpvalue ...string) *int { + var p int + CommandLine.FlagLong((*counterValue)(&p), "", name, helpvalue...).SetFlag() + return &p +} + +func (s *Set) Counter(name rune, helpvalue ...string) *int { + var p int + s.FlagLong((*counterValue)(&p), "", name, helpvalue...).SetFlag() + return &p +} + +func CounterLong(name string, short rune, helpvalue ...string) *int { + var p int + CommandLine.FlagLong((*counterValue)(&p), name, short, helpvalue...).SetFlag() + return &p +} + +func (s *Set) CounterLong(name string, short rune, helpvalue ...string) *int { + var p int + s.FlagLong((*counterValue)(&p), name, short, helpvalue...).SetFlag() + return &p +} diff --git a/vendor/github.com/pborman/getopt/v2/counter_test.go b/vendor/github.com/pborman/getopt/v2/counter_test.go new file mode 100644 index 0000000..b85a26d --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/counter_test.go @@ -0,0 +1,76 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var counterTests = []struct { + where string + in []string + c int + cnt int + err string +}{ + { + loc(), + []string{}, + 0, + 0, + "", + }, + { + loc(), + []string{"test", "-c", "--cnt"}, + 1, + 1, + "", + }, + { + loc(), + []string{"test", "-cc", "-c", "--cnt", "--cnt"}, + 3, + 2, + "", + }, + { + loc(), + []string{"test", "--c=17", "--cnt=42"}, + 17, + 42, + "", + }, + { + loc(), + []string{"test", "--cnt=false"}, + 0, 0, + "test: not a valid number: false\n", + }, +} + +func TestCounter(t *testing.T) { + for x, tt := range counterTests { + reset() + c := Counter('c') + cnt := CounterLong("cnt", 0) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *c, tt.c; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *cnt, tt.cnt; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/duration.go b/vendor/github.com/pborman/getopt/v2/duration.go new file mode 100644 index 0000000..7607815 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/duration.go @@ -0,0 +1,28 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "time" + +// Duration creates an option that parses its value as a time.Duration. +func Duration(name rune, value time.Duration, helpvalue ...string) *time.Duration { + CommandLine.FlagLong(&value, "", name, helpvalue...) + return &value +} + +func (s *Set) Duration(name rune, value time.Duration, helpvalue ...string) *time.Duration { + s.FlagLong(&value, "", name, helpvalue...) + return &value +} + +func DurationLong(name string, short rune, value time.Duration, helpvalue ...string) *time.Duration { + CommandLine.FlagLong(&value, name, short, helpvalue...) + return &value +} + +func (s *Set) DurationLong(name string, short rune, value time.Duration, helpvalue ...string) *time.Duration { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} diff --git a/vendor/github.com/pborman/getopt/v2/duration_test.go b/vendor/github.com/pborman/getopt/v2/duration_test.go new file mode 100644 index 0000000..ffee177 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/duration_test.go @@ -0,0 +1,73 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" + "time" +) + +var durationTests = []struct { + where string + in []string + d time.Duration + dur time.Duration + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-d", "1s", "--duration", "2s"}, + time.Second, 2 * time.Second, + "", + }, + { + loc(), + []string{"test", "-d1s", "-d2s"}, + 2 * time.Second, 42, + "", + }, + { + loc(), + []string{"test", "-d1"}, + 17, 42, + "test: time: missing unit in duration 1\n", + }, + { + loc(), + []string{"test", "--duration", "foo"}, + 17, 42, + "test: time: invalid duration foo\n", + }, +} + +func TestDuration(t *testing.T) { + for x, tt := range durationTests { + reset() + d := Duration('d', 17) + opt := DurationLong("duration", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *d, tt.d; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.dur; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/enum.go b/vendor/github.com/pborman/getopt/v2/enum.go new file mode 100644 index 0000000..1ca6ff9 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/enum.go @@ -0,0 +1,79 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "errors" + "fmt" + "sync" +) + +type enumValue string + +var ( + enumValuesMu sync.Mutex + enumValues = make(map[*enumValue]map[string]struct{}) +) + +func (s *enumValue) Set(value string, opt Option) error { + enumValuesMu.Lock() + es, ok := enumValues[s] + enumValuesMu.Unlock() + if !ok || es == nil { + return errors.New("this option has no values") + } + if _, ok := es[value]; !ok { + return errors.New("invalid value: " + value) + } + *s = enumValue(value) + return nil +} + +func (s *enumValue) String() string { + return string(*s) +} + +// Enum creates an option that can only be set to one of the enumerated strings +// passed in values. Passing nil or an empty slice results in an option that +// will always fail. If not "", value is the default value of the enum. If +// value is not listed in values then Enum will produce an error on standard +// error and then exit the program with a status of 1. +func Enum(name rune, values []string, value string, helpvalue ...string) *string { + return CommandLine.Enum(name, values, value, helpvalue...) +} + +func (s *Set) Enum(name rune, values []string, value string, helpvalue ...string) *string { + var p enumValue + p.define(values, value, &option{short: name}) + s.FlagLong(&p, "", name, helpvalue...) + return (*string)(&p) +} + +func EnumLong(name string, short rune, values []string, value string, helpvalue ...string) *string { + return CommandLine.EnumLong(name, short, values, value, helpvalue...) +} + +func (s *Set) EnumLong(name string, short rune, values []string, value string, helpvalue ...string) *string { + var p enumValue + p.define(values, value, &option{short: short, long: name}) + s.FlagLong(&p, name, short, helpvalue...) + return (*string)(&p) +} + +func (e *enumValue) define(values []string, def string, opt Option) { + m := make(map[string]struct{}) + for _, v := range values { + m[v] = struct{}{} + } + enumValuesMu.Lock() + enumValues[e] = m + enumValuesMu.Unlock() + if def != "" { + if err := e.Set(def, nil); err != nil { + fmt.Fprintf(stderr, "setting default for %s: %v\n", opt.Name(), err) + exit(1) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/enum_test.go b/vendor/github.com/pborman/getopt/v2/enum_test.go new file mode 100644 index 0000000..c854015 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/enum_test.go @@ -0,0 +1,79 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var enumTests = []struct { + where string + in []string + values []string + def string + out string + err string +}{ + { + loc(), + nil, + []string{}, + "", + "", + "", + }, + { + loc(), + []string{"test", "-e", "val1"}, + []string{"val1", "val2"}, + "", + "val1", + "", + }, + { + loc(), + []string{"test", "-e", "val1", "-e", "val2"}, + []string{"val1", "val2"}, + "", + "val2", + "", + }, + { + loc(), + []string{"test"}, + []string{"val1", "val2"}, + "val2", + "val2", + "", + }, + { + loc(), + []string{"test", "-e", "val3"}, + []string{"val1", "val2"}, + "", + "", + "test: invalid value: val3\n", + }, +} + +func TestEnum(t *testing.T) { + for x, tt := range enumTests { + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + reset() + e := Enum('e', tt.values, tt.def) + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *e != tt.out { + t.Errorf("%s: got %v, want %v", tt.where, *e, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/error.go b/vendor/github.com/pborman/getopt/v2/error.go new file mode 100644 index 0000000..6f668a3 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/error.go @@ -0,0 +1,93 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "fmt" + +// An Error is returned by Getopt when it encounters an error. +type Error struct { + ErrorCode // General reason of failure. + Err error // The actual error. + Parameter string // Parameter passed to option, if any + Name string // Option that cause error, if any +} + +// Error returns the error message, implementing the error interface. +func (i *Error) Error() string { return i.Err.Error() } + +// An ErrorCode indicates what sort of error was encountered. +type ErrorCode int + +const ( + NoError = ErrorCode(iota) + UnknownOption // an invalid option was encountered + MissingParameter // the options parameter is missing + ExtraParameter // a value was set to a long flag + Invalid // attempt to set an invalid value +) + +func (e ErrorCode) String() string { + switch e { + case UnknownOption: + return "unknow option" + case MissingParameter: + return "missing argument" + case ExtraParameter: + return "unxpected value" + case Invalid: + return "error setting value" + } + return "unknown error" +} + +// unknownOption returns an Error indicating an unknown option was +// encountered. +func unknownOption(name interface{}) *Error { + i := &Error{ErrorCode: UnknownOption} + switch n := name.(type) { + case rune: + if n == '-' { + i.Name = "-" + } else { + i.Name = "-" + string(n) + } + case string: + i.Name = "--" + n + } + i.Err = fmt.Errorf("unknown option: %s", i.Name) + return i +} + +// missingArg returns an Error inidicating option o was not passed +// a required paramter. +func missingArg(o Option) *Error { + return &Error{ + ErrorCode: MissingParameter, + Name: o.Name(), + Err: fmt.Errorf("missing parameter for %s", o.Name()), + } +} + +// extraArg returns an Error inidicating option o was passed the +// unexpected paramter value. +func extraArg(o Option, value string) *Error { + return &Error{ + ErrorCode: ExtraParameter, + Name: o.Name(), + Parameter: value, + Err: fmt.Errorf("unexpected parameter passed to %s: %q", o.Name(), value), + } +} + +// setError returns an Error inidicating option o and the specified +// error while setting it to value. +func setError(o Option, value string, err error) *Error { + return &Error{ + ErrorCode: Invalid, + Name: o.Name(), + Parameter: value, + Err: err, + } +} diff --git a/vendor/github.com/pborman/getopt/v2/generic.go b/vendor/github.com/pborman/getopt/v2/generic.go new file mode 100644 index 0000000..913f63b --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/generic.go @@ -0,0 +1,237 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package getopt + +import ( + "fmt" + "strconv" + "strings" + "time" +) + +type generic struct { + p interface{} +} + +// Flag is shorthand for CommandLine.Flag. +func Flag(v interface{}, short rune, helpvalue ...string) Option { + return CommandLine.long(v, "", short, helpvalue...) +} + +// FlagLong is shorthand for CommandLine.LongFlag. +func FlagLong(v interface{}, long string, short rune, helpvalue ...string) Option { + return CommandLine.long(v, long, short, helpvalue...) +} + +// Flag calls FlagLong with only a short flag name. +func (s *Set) Flag(v interface{}, short rune, helpvalue ...string) Option { + return s.long(v, "", short, helpvalue...) +} + +// FlagLong returns an Option in Set s for setting v. If long is not "" then +// the option has a long name, and if short is not 0, the option has a short +// name. v must either be of type getopt.Value or a pointer to one of the +// supported builtin types: +// +// bool, string, []string +// int, int8, int16, int32, int64 +// uint, uint8, uint16, uint32, uint64 +// float32, float64 +// time.Duration +// +// FlagLong will panic if v is not a getopt.Value or one of the supported +// builtin types. +// +// The default value of the flag is the value of v at the time FlagLong is +// called. +func (s *Set) FlagLong(v interface{}, long string, short rune, helpvalue ...string) Option { + return s.long(v, long, short, helpvalue...) +} + +func (s *Set) long(v interface{}, long string, short rune, helpvalue ...string) (opt Option) { + // Fix up our location when we return. + if where := calledFrom(); where != "" { + defer func() { + if opt, ok := opt.(*option); ok { + opt.where = where + } + }() + } + switch p := v.(type) { + case Value: + return s.addFlag(p, long, short, helpvalue...) + case *bool: + return s.addFlag(&generic{v}, long, short, helpvalue...).SetFlag() + case *string, *[]string: + return s.addFlag(&generic{v}, long, short, helpvalue...) + case *int, *int8, *int16, *int32, *int64: + return s.addFlag(&generic{v}, long, short, helpvalue...) + case *uint, *uint8, *uint16, *uint32, *uint64: + return s.addFlag(&generic{v}, long, short, helpvalue...) + case *float32, *float64: + return s.addFlag(&generic{v}, long, short, helpvalue...) + case *time.Duration: + return s.addFlag(&generic{v}, long, short, helpvalue...) + default: + panic(fmt.Sprintf("unsupported flag type: %T", v)) + } +} + +func (g *generic) Set(value string, opt Option) error { + strconvErr := func(err error) error { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + switch p := g.p.(type) { + case *bool: + switch strings.ToLower(value) { + case "", "1", "true", "on", "t": + *p = true + case "0", "false", "off", "f": + *p = false + default: + return fmt.Errorf("invalid value for bool %s: %q", opt.Name(), value) + } + return nil + case *string: + *p = value + return nil + case *[]string: + a := strings.Split(value, ",") + // If this is the first time we are seen then nil out the + // default value. + if opt.Count() <= 1 { + *p = nil + } + *p = append(*p, a...) + return nil + case *int: + i64, err := strconv.ParseInt(value, 0, strconv.IntSize) + if err == nil { + *p = int(i64) + } + return strconvErr(err) + case *int8: + i64, err := strconv.ParseInt(value, 0, 8) + if err == nil { + *p = int8(i64) + } + return strconvErr(err) + case *int16: + i64, err := strconv.ParseInt(value, 0, 16) + if err == nil { + *p = int16(i64) + } + return strconvErr(err) + case *int32: + i64, err := strconv.ParseInt(value, 0, 32) + if err == nil { + *p = int32(i64) + } + return strconvErr(err) + case *int64: + i64, err := strconv.ParseInt(value, 0, 64) + if err == nil { + *p = i64 + } + return strconvErr(err) + case *uint: + u64, err := strconv.ParseUint(value, 0, strconv.IntSize) + if err == nil { + *p = uint(u64) + } + return strconvErr(err) + case *uint8: + u64, err := strconv.ParseUint(value, 0, 8) + if err == nil { + *p = uint8(u64) + } + return strconvErr(err) + case *uint16: + u64, err := strconv.ParseUint(value, 0, 16) + if err == nil { + *p = uint16(u64) + } + return strconvErr(err) + case *uint32: + u64, err := strconv.ParseUint(value, 0, 32) + if err == nil { + *p = uint32(u64) + } + return strconvErr(err) + case *uint64: + u64, err := strconv.ParseUint(value, 0, 64) + if err == nil { + *p = u64 + } + return strconvErr(err) + case *float32: + f64, err := strconv.ParseFloat(value, 32) + if err == nil { + *p = float32(f64) + } + return strconvErr(err) + case *float64: + f64, err := strconv.ParseFloat(value, 64) + if err == nil { + *p = f64 + } + return strconvErr(err) + case *time.Duration: + v, err := time.ParseDuration(value) + if err == nil { + *p = v + } + return err + } + panic("internal error") +} + +func (g *generic) String() string { + switch p := g.p.(type) { + case *bool: + if *p { + return "true" + } + return "false" + case *string: + return *p + case *[]string: + return strings.Join([]string(*p), ",") + case *int: + return strconv.FormatInt(int64(*p), 10) + case *int8: + return strconv.FormatInt(int64(*p), 10) + case *int16: + return strconv.FormatInt(int64(*p), 10) + case *int32: + return strconv.FormatInt(int64(*p), 10) + case *int64: + return strconv.FormatInt(*p, 10) + case *uint: + return strconv.FormatUint(uint64(*p), 10) + case *uint8: + return strconv.FormatUint(uint64(*p), 10) + case *uint16: + return strconv.FormatUint(uint64(*p), 10) + case *uint32: + return strconv.FormatUint(uint64(*p), 10) + case *uint64: + return strconv.FormatUint(*p, 10) + case *float32: + return strconv.FormatFloat(float64(*p), 'g', -1, 32) + case *float64: + return strconv.FormatFloat(*p, 'g', -1, 64) + case *time.Duration: + return p.String() + } + panic("internal error") +} diff --git a/vendor/github.com/pborman/getopt/v2/generic_test.go b/vendor/github.com/pborman/getopt/v2/generic_test.go new file mode 100644 index 0000000..9a247ec --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/generic_test.go @@ -0,0 +1,319 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "bytes" + "fmt" + "os" + "reflect" + "runtime" + "strings" + "testing" + "time" +) + +func TestGeneric(t *testing.T) { + const ( + shortTest = iota + longTest + bothTest + ) + for _, tt := range []struct { + where string + kind int + val interface{} + str string + def interface{} + in []string + err string + }{ + // Do all four tests for string, the rest can mostly just use + // shortTest (the 0 value). + { + where: loc(), + kind: shortTest, + val: "42", + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + kind: longTest, + val: "42", + str: "42", + in: []string{"test", "--long", "42"}, + }, + { + where: loc(), + kind: bothTest, + val: "42", + str: "42", + in: []string{"test", "--both", "42"}, + }, + { + where: loc(), + kind: bothTest, + val: "42", + str: "42", + in: []string{"test", "-b", "42"}, + }, + { + where: loc(), + val: "42", + def: "42", + str: "42", + in: []string{"test"}, + }, + { + where: loc(), + val: "42", + def: "43", + str: "42", + in: []string{"test", "-s", "42"}, + }, + + { + where: loc(), + val: true, + str: "true", + in: []string{"test", "-s"}, + }, + { + where: loc(), + val: true, + def: true, + str: "true", + in: []string{"test"}, + }, + { + where: loc(), + kind: longTest, + val: false, + str: "false", + in: []string{"test", "--long=false"}, + }, + { + where: loc(), + kind: longTest, + val: false, + def: true, + str: "false", + in: []string{"test", "--long=false"}, + }, + + { + where: loc(), + val: int(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: int8(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: int16(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: int32(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: int64(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + + { + where: loc(), + val: uint(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: uint8(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: uint16(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: uint32(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + { + where: loc(), + val: uint64(42), + str: "42", + in: []string{"test", "-s", "42"}, + }, + + { + where: loc(), + val: float32(4.2), + str: "4.2", + in: []string{"test", "-s", "4.2"}, + }, + { + where: loc(), + val: float64(4.2), + str: "4.2", + in: []string{"test", "-s", "4.2"}, + }, + + { + where: loc(), + val: time.Duration(time.Second * 42), + def: time.Second * 2, + str: "42s", + in: []string{"test", "-s", "42s"}, + }, + { + where: loc(), + val: time.Duration(time.Second * 42), + def: time.Second * 2, + str: "42s", + in: []string{"test", "-s42s"}, + }, + { + where: loc(), + val: time.Duration(time.Second * 2), + def: time.Second * 2, + in: []string{"test", "-s42"}, + str: "2s", + err: "test: time: missing unit in duration 42", + }, + + { + where: loc(), + val: []string{"42", "."}, + str: "42,.", + def: []string{"one", "two", "three"}, + in: []string{"test", "-s42", "-s."}, + }, + { + where: loc(), + val: []string{"42", "."}, + str: "42,.", + def: []string{"one", "two", "three"}, + in: []string{"test", "-s42,."}, + }, + { + where: loc(), + val: []string{"one", "two", "three"}, + def: []string{"one", "two", "three"}, + str: "one,two,three", + in: []string{"test"}, + }, + } { + reset() + var opt Option + val := reflect.New(reflect.TypeOf(tt.val)).Interface() + if tt.def != nil { + reflect.ValueOf(val).Elem().Set(reflect.ValueOf(tt.def)) + } + switch tt.kind { + case shortTest: + opt = Flag(val, 's') + case longTest: + opt = FlagLong(val, "long", 0) + case bothTest: + opt = FlagLong(val, "both", 'b') + } + _ = opt + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + continue + } + got := reflect.ValueOf(val).Elem().Interface() + want := reflect.ValueOf(tt.val).Interface() + if !reflect.DeepEqual(got, want) { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if str := opt.String(); str != tt.str { + t.Errorf("%s: got string %q, want %q", tt.where, str, tt.str) + } + } +} + +func TestGenericDup(t *testing.T) { + defer func() { + stderr = os.Stderr + exit = os.Exit + }() + + reset() + var v1, v2 string + type myPanic struct{} + var errbuf bytes.Buffer + stderr = &errbuf + _, file, line, _ := runtime.Caller(0) + Flag(&v1, 's') + line++ // line is now the line number of the first call to Flag. + + exit = func(i int) { panic(myPanic{}) } + defer func() { + p := recover() + if _, ok := p.(myPanic); ok { + err := errbuf.String() + if !strings.Contains(err, "-s already declared") || !strings.Contains(err, fmt.Sprintf("%s:%d", file, line)) { + t.Errorf("unexpected error: %q\nshould contain \"-s already declared\" and \"%s:%d\"", err, file, line) + } + } else if p == nil { + t.Errorf("Second call to Flag did not fail") + } else { + t.Errorf("panic %v", p) + } + }() + Flag(&v2, 's') +} + +func TestGenericDupNested(t *testing.T) { + defer func() { + stderr = os.Stderr + exit = os.Exit + }() + + reset() + type myPanic struct{} + var errbuf bytes.Buffer + stderr = &errbuf + _, file, line, _ := runtime.Caller(0) + String('s', "default") + line++ // line is now the line number of the first call to Flag. + + exit = func(i int) { panic(myPanic{}) } + defer func() { + p := recover() + if _, ok := p.(myPanic); ok { + err := errbuf.String() + if !strings.Contains(err, "-s already declared") || !strings.Contains(err, fmt.Sprintf("%s:%d", file, line)) { + t.Errorf("unexpected error: %q\nshould contain \"-s already declared\" and \"%s:%d\"", err, file, line) + } + } else if p == nil { + t.Errorf("Second call to Flag did not fail") + } else { + t.Errorf("panic %v", p) + } + }() + String('s', "default") +} diff --git a/vendor/github.com/pborman/getopt/v2/getopt.go b/vendor/github.com/pborman/getopt/v2/getopt.go new file mode 100644 index 0000000..cbab895 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/getopt.go @@ -0,0 +1,520 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package getopt (v2) provides traditional getopt processing for implementing +// commands that use traditional command lines. The standard Go flag package +// cannot be used to write a program that parses flags the way ls or ssh does, +// for example. Version 2 of this package has a simplified API. +// +// USAGE +// +// Getopt supports functionality found in both the standard BSD getopt as well +// as (one of the many versions of) the GNU getopt_long. Being a Go package, +// this package makes common usage easy, but still enables more controlled usage +// if needed. +// +// Typical usage: +// +// // Declare flags and have getopt return pointers to the values. +// helpFlag := getopt.Bool('?', "display help") +// cmdFlag := getopt.StringLong("command", 'c', "default", "the command) +// +// // Declare flags against existing variables. +// var { +// fileName = "/the/default/path" +// timeout = time.Second * 5 +// verbose bool +// } +// func init() { +// getopt.Flag(&verbose, 'v', "be verbose") +// getopt.FlagLong(&fileName, "path", 0, "the path") +// getopt.FlagLong(&timeout, "timeout", 't', "some timeout") +// } +// +// func main() { +// // Parse the program arguments +// getopt.Parse() +// // Get the remaining positional parameters +// args := getopt.Args() +// ... +// +// If you don't want the program to exit on error, use getopt.Getopt: +// +// err := getopt.Getopt(nil) +// if err != nil { +// // code to handle error +// fmt.Fprintln(os.Stderr, err) +// } +// +// FLAG SYNTAX +// +// Support is provided for both short (-f) and long (--flag) options. A single +// option may have both a short and a long name. Each option may be a flag or a +// value. A value takes an argument. +// +// Declaring no long names causes this package to process arguments like the +// traditional BSD getopt. +// +// Short flags may be combined into a single parameter. For example, "-a -b -c" +// may also be expressed "-abc". Long flags must stand on their own "--alpha +// --beta" +// +// Values require an argument. For short options the argument may either be +// immediately following the short name or as the next argument. Only one short +// value may be combined with short flags in a single argument; the short value +// must be after all short flags. For example, if f is a flag and v is a value, +// then: +// +// -vvalue (sets v to "value") +// -v value (sets v to "value") +// -fvvalue (sets f, and sets v to "value") +// -fv value (sets f, and sets v to "value") +// -vf value (set v to "f" and value is the first parameter) +// +// For the long value option val: +// +// --val value (sets val to "value") +// --val=value (sets val to "value") +// --valvalue (invalid option "valvalue") +// +// Values with an optional value only set the value if the value is part of the +// same argument. In any event, the option count is increased and the option is +// marked as seen. +// +// -v -f (sets v and f as being seen) +// -vvalue -f (sets v to "value" and sets f) +// --val -f (sets v and f as being seen) +// --val=value -f (sets v to "value" and sets f) +// +// There is no convenience function defined for making the value optional. The +// SetOptional method must be called on the actual Option. +// +// v := String("val", 'v', "", "the optional v") +// Lookup("v").SetOptional() +// +// var s string +// FlagLong(&s, "val", 'v', "the optional v).SetOptional() +// +// Parsing continues until the first non-option or "--" is encountered. +// +// The short name "-" can be used, but it either is specified as "-" or as part +// of a group of options, for example "-f-". If there are no long options +// specified then "--f" could also be used. If "-" is not declared as an option +// then the single "-" will also terminate the option processing but unlike +// "--", the "-" will be part of the remaining arguments. +// +// ADVANCED USAGE +// +// Normally the parsing is performed by calling the Parse function. If it is +// important to see the order of the options then the Getopt function should be +// used. The standard Parse function does the equivalent of: +// +// func Parse() { +// if err := getopt.Getopt(os.Args, nil); err != nil { +// fmt.Fprintln(os.Stderr, err) +// s.usage() +// os.Exit(1) +// } +// +// When calling Getopt it is the responsibility of the caller to print any +// errors. +// +// Normally the default option set, CommandLine, is used. Other option sets may +// be created with New. +// +// After parsing, the sets Args will contain the non-option arguments. If an +// error is encountered then Args will begin with argument that caused the +// error. +// +// It is valid to call a set's Parse a second time to amen flags or values. As +// an example: +// +// var a = getopt.Bool('a', "", "The a flag") +// var b = getopt.Bool('b', "", "The a flag") +// var cmd = "" +// +// var opts = getopt.CommandLine +// +// opts.Parse(os.Args) +// if opts.NArgs() > 0 { +// cmd = opts.Arg(0) +// opts.Parse(opts.Args()) +// } +// +// If called with set to { "prog", "-a", "cmd", "-b", "arg" } then both and and +// b would be set, cmd would be set to "cmd", and opts.Args() would return { +// "arg" }. +// +// Unless an option type explicitly prohibits it, an option may appear more than +// once in the arguments. The last value provided to the option is the value. +// +// BUILTIN TYPES +// +// The Flag and FlagLong functions support most standard Go types. For the +// list, see the description of FlagLong below for a list of supported types. +// +// There are also helper routines to allow single line flag declarations. These +// types are: Bool, Counter, Duration, Enum, Int16, Int32, Int64, Int, List, +// Signed, String, Uint16, Uint32, Uint64, Uint, and Unsigned. +// +// Each comes in a short and long flavor, e.g., Bool and BoolLong and include +// functions to set the flags on the standard command line or for a specific Set +// of flags. +// +// Except for the Counter, Enum, Signed and Unsigned types, all of these types +// can be declared using Flag and FlagLong by passing in a pointer to the +// appropriate type. +// +// DECLARING NEW FLAG TYPES +// +// A pointer to any type that implements the Value interface may be passed to +// Flag or FlagLong. +// +// VALUEHELP +// +// All non-flag options are created with a "valuehelp" as the last parameter. +// Valuehelp should be 0, 1, or 2 strings. The first string, if provided, is +// the usage message for the option. If the second string, if provided, is the +// name to use for the value when displaying the usage. If not provided the +// term "value" is assumed. +// +// The usage message for the option created with +// +// StringLong("option", 'o', "defval", "a string of letters") +// +// is +// +// -o, -option=value +// +// StringLong("option", 'o', "defval", "a string of letters", "string") +// +// is +// +// -o, -option=string +package getopt + +import ( + "fmt" + "io" + "os" + "path" + "sort" + "strings" +) + +// stderr allows tests to capture output to standard error. +var stderr io.Writer = os.Stderr + +// exit allows tests to capture an os.Exit call +var exit = os.Exit + +// DisplayWidth is used to determine where to split usage long lines. +var DisplayWidth = 80 + +// HelpColumn is the maximum column position that help strings start to display +// at. If the option usage is too long then the help string will be displayed +// on the next line. For example: +// +// -a this is the a flag +// -u, --under=location +// the u flag's usage is quite long +var HelpColumn = 20 + +// PrintUsage prints the usage of the program to w. +func (s *Set) PrintUsage(w io.Writer) { + sort.Sort(s.options) + flags := "" + + // Build up the list of short flag names and also compute + // how to display the option in the longer help listing. + // We also keep track of the longest option usage string + // that is no more than HelpColumn-3 bytes (at which point + // we use two lines to display the help). The three + // is for the leading space and the two spaces before the + // help string. + for _, opt := range s.options { + if opt.name == "" { + opt.name = "value" + } + if opt.uname == "" { + opt.uname = opt.usageName() + } + if opt.flag && opt.short != 0 && opt.short != '-' { + flags += string(opt.short) + } + } + + var opts []string + + // The short option - is special + if s.shortOptions['-'] != nil { + opts = append(opts, "-") + } + + // If we have a bundle of flags, add them to the list + if flags != "" { + opts = append(opts, "-"+flags) + } + + // Now append all the long options and options that require + // values. + for _, opt := range s.options { + if opt.flag { + if opt.short != 0 { + continue + } + flags = "--" + opt.long + } else if opt.short != 0 { + flags = "-" + string(opt.short) + " " + opt.name + } else { + flags = "--" + string(opt.long) + " " + opt.name + } + opts = append(opts, flags) + } + flags = strings.Join(opts, "] [") + if flags != "" { + flags = " [" + flags + "]" + } + if s.parameters != "" { + flags += " " + s.parameters + } + fmt.Fprintf(w, "Usage: %s%s\n", s.program, flags) + s.PrintOptions(w) +} + +// PrintOptions prints the list of options in s to w. +func (s *Set) PrintOptions(w io.Writer) { + sort.Sort(s.options) + max := 4 + for _, opt := range s.options { + if opt.name == "" { + opt.name = "value" + } + if opt.uname == "" { + opt.uname = opt.usageName() + } + if max < len(opt.uname) && len(opt.uname) <= HelpColumn-3 { + max = len(opt.uname) + } + } + // Now print one or more usage lines per option. + for _, opt := range s.options { + if opt.uname != "" { + opt.help = strings.TrimSpace(opt.help) + if len(opt.help) == 0 { + fmt.Fprintf(w, " %s\n", opt.uname) + continue + } + help := strings.Split(opt.help, "\n") + // If they did not put in newlines then we will insert + // them to keep the help messages from wrapping. + if len(help) == 1 { + help = breakup(help[0], DisplayWidth-HelpColumn) + } + if len(opt.uname) <= max { + fmt.Fprintf(w, " %-*s %s\n", max, opt.uname, help[0]) + help = help[1:] + } else { + fmt.Fprintf(w, " %s\n", opt.uname) + } + for _, s := range help { + fmt.Fprintf(w, " %-*s %s\n", max, " ", s) + } + } + } +} + +// breakup breaks s up into strings no longer than max bytes. +func breakup(s string, max int) []string { + var a []string + + for { + // strip leading spaces + for len(s) > 0 && s[0] == ' ' { + s = s[1:] + } + // If the option is no longer than the max just return it + if len(s) <= max { + if len(s) != 0 { + a = append(a, s) + } + return a + } + x := max + for s[x] != ' ' { + // the first word is too long?! + if x == 0 { + x = max + for x < len(s) && s[x] != ' ' { + x++ + } + if x == len(s) { + x-- + } + break + } + x-- + } + for s[x] == ' ' { + x-- + } + a = append(a, s[:x+1]) + s = s[x+1:] + } + panic("unreachable") +} + +// Parse uses Getopt to parse args using the options set for s. The first +// element of args is used to assign the program for s if it is not yet set. On +// error, Parse displays the error message as well as a usage message on +// standard error and then exits the program. +func (s *Set) Parse(args []string) { + if err := s.Getopt(args, nil); err != nil { + fmt.Fprintln(stderr, err) + s.usage() + exit(1) + } +} + +// Parse uses Getopt to parse args using the options set for s. The first +// element of args is used to assign the program for s if it is not yet set. +// Getop calls fn, if not nil, for each option parsed. +// +// Getopt returns nil when all options have been processed (a non-option +// argument was encountered, "--" was encountered, or fn returned false). +// +// On error getopt returns a reference to an InvalidOption (which implements the +// error interface). +func (s *Set) Getopt(args []string, fn func(Option) bool) (err error) { + s.setState(InProgress) + defer func() { + if s.State() == InProgress { + switch { + case err != nil: + s.setState(Failure) + case len(s.args) == 0: + s.setState(EndOfArguments) + default: + s.setState(Unknown) + } + } + }() + if fn == nil { + fn = func(Option) bool { return true } + } + if len(args) == 0 { + return nil + } + + if s.program == "" { + s.program = path.Base(args[0]) + } + args = args[1:] +Parsing: + for len(args) > 0 { + arg := args[0] + s.args = args + args = args[1:] + + // end of options? + if arg == "" || arg[0] != '-' { + s.setState(EndOfOptions) + return nil + } + + if arg == "-" { + goto ShortParsing + } + + // explicitly request end of options? + if arg == "--" { + s.args = args + s.setState(DashDash) + return nil + } + + // Long option processing + if len(s.longOptions) > 0 && arg[1] == '-' { + e := strings.IndexRune(arg, '=') + var value string + if e > 0 { + value = arg[e+1:] + arg = arg[:e] + } + opt := s.longOptions[arg[2:]] + // If we are processing long options then --f is -f + // if f is not defined as a long option. + // This lets you say --f=false + if opt == nil && len(arg[2:]) == 1 { + opt = s.shortOptions[rune(arg[2])] + } + if opt == nil { + return unknownOption(arg[2:]) + } + opt.isLong = true + // If we require an option and did not have an = + // then use the next argument as an option. + if !opt.flag && e < 0 && !opt.optional { + if len(args) == 0 { + return missingArg(opt) + } + value = args[0] + args = args[1:] + } + opt.count++ + + if err := opt.value.Set(value, opt); err != nil { + return setError(opt, value, err) + } + + if !fn(opt) { + s.setState(Terminated) + return nil + } + continue Parsing + } + + // Short option processing + arg = arg[1:] // strip - + ShortParsing: + for i, c := range arg { + opt := s.shortOptions[c] + if opt == nil { + // In traditional getopt, if - is not registered + // as an option, a lone - is treated as + // if there were a -- in front of it. + if arg == "-" { + s.setState(Dash) + return nil + } + return unknownOption(c) + } + opt.isLong = false + opt.count++ + var value string + if !opt.flag { + value = arg[1+i:] + if value == "" && !opt.optional { + if len(args) == 0 { + return missingArg(opt) + } + value = args[0] + args = args[1:] + } + } + if err := opt.value.Set(value, opt); err != nil { + return setError(opt, value, err) + } + if !fn(opt) { + s.setState(Terminated) + return nil + } + if !opt.flag { + continue Parsing + } + } + } + s.args = []string{} + return nil +} diff --git a/vendor/github.com/pborman/getopt/v2/int.go b/vendor/github.com/pborman/getopt/v2/int.go new file mode 100644 index 0000000..b4c27bf --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/int.go @@ -0,0 +1,160 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +// Int creates an option that parses its value as an integer. +func Int(name rune, value int, helpvalue ...string) *int { + return CommandLine.Int(name, value, helpvalue...) +} + +func (s *Set) Int(name rune, value int, helpvalue ...string) *int { + s.Flag(&value, name, helpvalue...) + return &value +} + +func IntLong(name string, short rune, value int, helpvalue ...string) *int { + return CommandLine.IntLong(name, short, value, helpvalue...) +} + +func (s *Set) IntLong(name string, short rune, value int, helpvalue ...string) *int { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Int16 creates an option that parses its value as a 16 bit integer. +func Int16(name rune, value int16, helpvalue ...string) *int16 { + return CommandLine.Int16(name, value, helpvalue...) +} + +func (s *Set) Int16(name rune, value int16, helpvalue ...string) *int16 { + s.Flag(&value, name, helpvalue...) + return &value +} + +func Int16Long(name string, short rune, value int16, helpvalue ...string) *int16 { + return CommandLine.Int16Long(name, short, value, helpvalue...) +} + +func (s *Set) Int16Long(name string, short rune, value int16, helpvalue ...string) *int16 { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Int32 creates an option that parses its value as a 32 bit integer. +func Int32(name rune, value int32, helpvalue ...string) *int32 { + return CommandLine.Int32(name, value, helpvalue...) +} + +func (s *Set) Int32(name rune, value int32, helpvalue ...string) *int32 { + s.Flag(&value, name, helpvalue...) + return &value +} + +func Int32Long(name string, short rune, value int32, helpvalue ...string) *int32 { + return CommandLine.Int32Long(name, short, value, helpvalue...) +} + +func (s *Set) Int32Long(name string, short rune, value int32, helpvalue ...string) *int32 { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Int64 creates an option that parses its value as a 64 bit integer. +func Int64(name rune, value int64, helpvalue ...string) *int64 { + return CommandLine.Int64(name, value, helpvalue...) +} + +func (s *Set) Int64(name rune, value int64, helpvalue ...string) *int64 { + s.Flag(&value, name, helpvalue...) + return &value +} + +func Int64Long(name string, short rune, value int64, helpvalue ...string) *int64 { + return CommandLine.Int64Long(name, short, value, helpvalue...) +} + +func (s *Set) Int64Long(name string, short rune, value int64, helpvalue ...string) *int64 { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Uint creates an option that parses its value as an unsigned integer. +func Uint(name rune, value uint, helpvalue ...string) *uint { + return CommandLine.Uint(name, value, helpvalue...) +} + +func (s *Set) Uint(name rune, value uint, helpvalue ...string) *uint { + s.Flag(&value, name, helpvalue...) + return &value +} + +func UintLong(name string, short rune, value uint, helpvalue ...string) *uint { + return CommandLine.UintLong(name, short, value, helpvalue...) +} + +func (s *Set) UintLong(name string, short rune, value uint, helpvalue ...string) *uint { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Uint16 creates an option that parses its value as a 16 bit unsigned integer. +func Uint16(name rune, value uint16, helpvalue ...string) *uint16 { + return CommandLine.Uint16(name, value, helpvalue...) + return &value +} + +func (s *Set) Uint16(name rune, value uint16, helpvalue ...string) *uint16 { + s.Flag(&value, name, helpvalue...) + return &value +} + +func Uint16Long(name string, short rune, value uint16, helpvalue ...string) *uint16 { + return CommandLine.Uint16Long(name, short, value, helpvalue...) +} + +func (s *Set) Uint16Long(name string, short rune, value uint16, helpvalue ...string) *uint16 { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Uint32 creates an option that parses its value as a 32 bit unsigned integer. +func Uint32(name rune, value uint32, helpvalue ...string) *uint32 { + return CommandLine.Uint32(name, value, helpvalue...) + return &value +} + +func (s *Set) Uint32(name rune, value uint32, helpvalue ...string) *uint32 { + s.Flag(&value, name, helpvalue...) + return &value +} + +func Uint32Long(name string, short rune, value uint32, helpvalue ...string) *uint32 { + return CommandLine.Uint32Long(name, short, value, helpvalue...) +} + +func (s *Set) Uint32Long(name string, short rune, value uint32, helpvalue ...string) *uint32 { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} + +// Uint64 creates an option that parses its value as a 64 bit unsigned integer. +func Uint64(name rune, value uint64, helpvalue ...string) *uint64 { + return CommandLine.Uint64(name, value, helpvalue...) + return &value +} + +func (s *Set) Uint64(name rune, value uint64, helpvalue ...string) *uint64 { + s.Flag(&value, name, helpvalue...) + return &value +} + +func Uint64Long(name string, short rune, value uint64, helpvalue ...string) *uint64 { + return CommandLine.Uint64Long(name, short, value, helpvalue...) +} + +func (s *Set) Uint64Long(name string, short rune, value uint64, helpvalue ...string) *uint64 { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} diff --git a/vendor/github.com/pborman/getopt/v2/int_test.go b/vendor/github.com/pborman/getopt/v2/int_test.go new file mode 100644 index 0000000..57175fd --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/int_test.go @@ -0,0 +1,595 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var intTests = []struct { + where string + in []string + i int + int int + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt(t *testing.T) { + for x, tt := range intTests { + reset() + i := Int('i', 17) + opt := IntLong("int", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var int16Tests = []struct { + where string + in []string + i int16 + int16 int16 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int16", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int16=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt16(t *testing.T) { + for x, tt := range int16Tests { + reset() + i := Int16('i', 17) + opt := Int16Long("int16", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int16; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var int32Tests = []struct { + where string + in []string + i int32 + int32 int32 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int32", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int32=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt32(t *testing.T) { + for x, tt := range int32Tests { + reset() + i := Int32('i', 17) + opt := Int32Long("int32", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int32; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var int64Tests = []struct { + where string + in []string + i int64 + int64 int64 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--int64", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--int64=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestInt64(t *testing.T) { + for x, tt := range int64Tests { + reset() + i := Int64('i', 17) + opt := Int64Long("int64", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.int64; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var uintTests = []struct { + where string + in []string + i uint + uint uint + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint(t *testing.T) { + for x, tt := range uintTests { + reset() + i := Uint('i', 17) + opt := UintLong("uint", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var uint16Tests = []struct { + where string + in []string + i uint16 + uint16 uint16 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint16", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint16=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint16(t *testing.T) { + for x, tt := range uint16Tests { + reset() + i := Uint16('i', 17) + opt := Uint16Long("uint16", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint16; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var uint32Tests = []struct { + where string + in []string + i uint32 + uint32 uint32 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint32", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint32=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint32(t *testing.T) { + for x, tt := range uint32Tests { + reset() + i := Uint32('i', 17) + opt := Uint32Long("uint32", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint32; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} + +var uint64Tests = []struct { + where string + in []string + i uint64 + uint64 uint64 + err string +}{ + { + loc(), + []string{}, + 17, 42, + "", + }, + { + loc(), + []string{"test", "-i", "1", "--uint64", "2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "--uint64=2"}, + 1, 2, + "", + }, + { + loc(), + []string{"test", "-i1", "-i2"}, + 2, 42, + "", + }, + { + loc(), + []string{"test", "-i=1"}, + 17, 42, + "test: not a valid number: =1\n", + }, + { + loc(), + []string{"test", "-i0x20"}, + 0x20, 42, + "", + }, + { + loc(), + []string{"test", "-i010"}, + 8, 42, + "", + }, +} + +func TestUint64(t *testing.T) { + for x, tt := range uint64Tests { + reset() + i := Uint64('i', 17) + opt := Uint64Long("uint64", 0, 42) + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if got, want := *i, tt.i; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + if got, want := *opt, tt.uint64; got != want { + t.Errorf("%s: got %v, want %v", tt.where, got, want) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/list.go b/vendor/github.com/pborman/getopt/v2/list.go new file mode 100644 index 0000000..99a09ef --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/list.go @@ -0,0 +1,32 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +// List creates an option that returns a slice of strings. The parameters +// passed are converted from a comma separated value list into a slice. +// Subsequent occurrences append to the list. +func List(name rune, helpvalue ...string) *[]string { + p := []string{} + CommandLine.Flag(&p, name, helpvalue...) + return &p +} + +func (s *Set) List(name rune, helpvalue ...string) *[]string { + p := []string{} + s.Flag(&p, name, helpvalue...) + return &p +} + +func ListLong(name string, short rune, helpvalue ...string) *[]string { + p := []string{} + CommandLine.FlagLong(&p, name, short, helpvalue...) + return &p +} + +func (s *Set) ListLong(name string, short rune, helpvalue ...string) *[]string { + p := []string{} + s.FlagLong(&p, name, short, helpvalue...) + return &p +} diff --git a/vendor/github.com/pborman/getopt/v2/list_test.go b/vendor/github.com/pborman/getopt/v2/list_test.go new file mode 100644 index 0000000..e8c8d18 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/list_test.go @@ -0,0 +1,99 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "testing" + +var listTests = []struct { + where string + in []string + l, list []string + err string +}{ + { + loc(), + []string{}, + nil, nil, + "", + }, + { + loc(), + []string{"test", "-l", "one"}, + []string{"one"}, nil, + "", + }, + { + loc(), + []string{"test", "-lone", "-ltwo"}, + []string{"one", "two"}, nil, + "", + }, + { + loc(), + []string{"test", "--list", "one"}, + nil, []string{"one"}, + "", + }, + { + loc(), + []string{"test", "--list=one", "--list=two"}, + nil, []string{"one", "two"}, + "", + }, + { + loc(), + []string{"test", "--list=one,two"}, + nil, []string{"one", "two"}, + "", + }, +} + +func TestList(t *testing.T) { + for _, tt := range listTests { + reset() + l := List('l') + list := ListLong("list", 0) + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if badSlice(*l, tt.l) { + t.Errorf("%s: got s = %q, want %q", tt.where, *l, tt.l) + } + if badSlice(*list, tt.list) { + t.Errorf("%s: got s = %q, want %q", tt.where, *list, tt.list) + } + } +} + +func TestDefaultList(t *testing.T) { + reset() + list := []string{"d1", "d2", "d3"} + Flag(&list, 'l') + parse([]string{"test"}) + + want := []string{"d1", "d2", "d3"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } + + parse([]string{"test", "-l", "one"}) + want = []string{"one"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } + + parse([]string{"test", "-l", "two"}) + want = []string{"one", "two"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } + Lookup('l').Reset() + want = []string{"d1", "d2", "d3"} + if badSlice(list, want) { + t.Errorf("got s = %q, want %q", list, want) + } +} diff --git a/vendor/github.com/pborman/getopt/v2/option.go b/vendor/github.com/pborman/getopt/v2/option.go new file mode 100644 index 0000000..6d5fc47 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/option.go @@ -0,0 +1,193 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" +) + +// An Option can be either a Flag or a Value +type Option interface { + // Name returns the name of the option. If the option has been seen + // then the last way it was referenced (short or long) is returned + // otherwise if there is a short name then this will be the short name + // as a string, else it will be the long name. + Name() string + + // IsFlag returns true if Option is a flag. + IsFlag() bool + + // Seen returns true if the flag was seen. + Seen() bool + + // Count returns the number of times the flag was seen. + Count() int + + // String returns the last value the option was set to. + String() string + + // Value returns the Value of the option. + Value() Value + + // SetOptional makes the value optional. The option and value are + // always a single argument. Either --option or --option=value. In + // the former case the value of the option does not change but the Set() + // will return true and the value returned by Count() is incremented. + // The short form is either -o or -ovalue. SetOptional returns + // the Option + SetOptional() Option + + // SetFlag makes the value a flag. Flags are boolean values and + // normally do not taken a value. They are set to true when seen. + // If a value is passed in the long form then it must be on, case + // insensitivinsensitive, one of "true", "false", "t", "f", "on", "off", "1", "0". + // SetFlag returns the Option + SetFlag() Option + + // Reset resets the state of the option so it appears it has not + // yet been seen, including resetting the value of the option + // to its original default state. + Reset() +} + +type option struct { + short rune // 0 means no short name + long string // "" means no long name + isLong bool // True if they used the long name + flag bool // true if a boolean flag + defval string // default value + optional bool // true if we take an optional value + help string // help message + where string // file where the option was defined + value Value // current value of option + count int // number of times we have seen this option + name string // name of the value (for usage) + uname string // name of the option (for usage) +} + +// usageName returns the name of the option for printing usage lines in one +// of the following forms: +// +// -f +// --flag +// -f, --flag +// -s value +// --set=value +// -s, --set=value +func (o *option) usageName() string { + // Don't print help messages if we have none and there is only one + // way to specify the option. + if o.help == "" && (o.short == 0 || o.long == "") { + return "" + } + n := "" + + switch { + case o.short != 0 && o.long == "": + n = "-" + string(o.short) + case o.short == 0 && o.long != "": + n = " --" + o.long + case o.short != 0 && o.long != "": + n = "-" + string(o.short) + ", --" + o.long + } + + switch { + case o.flag: + return n + case o.optional: + return n + "[=" + o.name + "]" + case o.long != "": + return n + "=" + o.name + } + return n + " " + o.name +} + +// sortName returns the name to sort the option on. +func (o *option) sortName() string { + if o.short != 0 { + return string(o.short) + o.long + } + return o.long[:1] + o.long +} + +func (o *option) Seen() bool { return o.count > 0 } +func (o *option) Count() int { return o.count } +func (o *option) IsFlag() bool { return o.flag } +func (o *option) String() string { return o.value.String() } +func (o *option) SetOptional() Option { o.optional = true; return o } +func (o *option) SetFlag() Option { o.flag = true; return o } + +func (o *option) Value() Value { + if o == nil { + return nil + } + return o.value +} + +func (o *option) Name() string { + if !o.isLong && o.short != 0 { + return "-" + string(o.short) + } + return "--" + o.long +} + +// Reset rests an option so that it appears it has not yet been seen. +func (o *option) Reset() { + o.isLong = false + o.count = 0 + o.value.Set(o.defval, o) +} + +type optionList []*option + +func (ol optionList) Len() int { return len(ol) } +func (ol optionList) Swap(i, j int) { ol[i], ol[j] = ol[j], ol[i] } +func (ol optionList) Less(i, j int) bool { + // first check the short names (or the first letter of the long name) + // If they are not equal (case insensitive) then we have our answer + n1 := ol[i].sortName() + n2 := ol[j].sortName() + l1 := strings.ToLower(n1) + l2 := strings.ToLower(n2) + if l1 < l2 { + return true + } + if l2 < l1 { + return false + } + return n1 < n2 +} + +// AddOption add the option o to set CommandLine if o is not already in set +// CommandLine. +func AddOption(o Option) { + CommandLine.AddOption(o) +} + +// AddOption add the option o to set s if o is not already in set s. +func (s *Set) AddOption(o Option) { + opt := o.(*option) + for _, eopt := range s.options { + if opt == eopt { + return + } + } + if opt.short != 0 { + if oo, ok := s.shortOptions[opt.short]; ok { + fmt.Fprintf(stderr, "%s: -%c already declared at %s\n", opt.where, opt.short, oo.where) + exit(1) + } + s.shortOptions[opt.short] = opt + } + if opt.long != "" { + if oo, ok := s.longOptions[opt.long]; ok { + fmt.Fprintf(stderr, "%s: --%s already declared at %s\n", opt.where, opt.long, oo.where) + exit(1) + } + s.longOptions[opt.long] = opt + } + s.options = append(s.options, opt) +} diff --git a/vendor/github.com/pborman/getopt/v2/set.go b/vendor/github.com/pborman/getopt/v2/set.go new file mode 100644 index 0000000..ce546ed --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/set.go @@ -0,0 +1,284 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "io" + "os" + "sort" + "sync" +) + +// A State is why the Getopt returned. +type State int + +const ( + InProgress = State(iota) // Getopt is still running + Dash // Returned on "-" + DashDash // Returned on "--" + EndOfOptions // End of options reached + EndOfArguments // No more arguments + Terminated // Terminated by callback function + Failure // Terminated due to error + Unknown // Indicates internal error +) + +type Set struct { + stateMu sync.Mutex + state State + + // args are the parameters remaining after parsing the optoins. + args []string + + // program is the name of the program for usage and error messages. + // If not set it will automatically be set to the base name of the + // first argument passed to parse. + program string + + // parameters is what is displayed on the usage line after displaying + // the various options. + parameters string + + usage func() // usage should print the programs usage and exit. + + shortOptions map[rune]*option + longOptions map[string]*option + options optionList +} + +// New returns a newly created option set. +func New() *Set { + s := &Set{ + shortOptions: make(map[rune]*option), + longOptions: make(map[string]*option), + parameters: "[parameters ...]", + } + + s.usage = func() { + s.PrintUsage(stderr) + } + return s +} + +func (s *Set) setState(state State) { + s.stateMu.Lock() + s.state = state + s.stateMu.Unlock() +} + +// State returns the current state of the Set s. The state is normally the +// reason the most recent call to Getopt returned. +func (s *Set) State() State { + s.stateMu.Lock() + defer s.stateMu.Unlock() + return s.state +} + +// The default set of command-line options. +var CommandLine = New() + +// PrintUsage calls PrintUsage in the default option set. +func PrintUsage(w io.Writer) { CommandLine.PrintUsage(w) } + +// Usage calls the usage function in the default option set. +func Usage() { CommandLine.usage() } + +// Parse calls Parse in the default option set with the command line arguments +// found in os.Args. +func Parse() { CommandLine.Parse(os.Args) } + +// Getops returns the result of calling Getop in the default option set with the +// command line arguments found in os.Args. The fn function, which may be nil, +// is passed to Getopt. +func Getopt(fn func(Option) bool) error { return CommandLine.Getopt(os.Args, fn) } + +// Arg returns the n'th command-line argument. Arg(0) is the first remaining +// argument after options have been processed. +func Arg(n int) string { + if n >= 0 && n < len(CommandLine.args) { + return CommandLine.args[n] + } + return "" +} + +// Arg returns the n'th argument. Arg(0) is the first remaining +// argument after options have been processed. +func (s *Set) Arg(n int) string { + if n >= 0 && n < len(s.args) { + return s.args[n] + } + return "" +} + +// Args returns the non-option command line arguments. +func Args() []string { + return CommandLine.args +} + +// Args returns the non-option arguments. +func (s *Set) Args() []string { + return s.args +} + +// NArgs returns the number of non-option command line arguments. +func NArgs() int { + return len(CommandLine.args) +} + +// NArgs returns the number of non-option arguments. +func (s *Set) NArgs() int { + return len(s.args) +} + +// SetParameters sets the parameters string for printing the command line +// usage. It defaults to "[parameters ...]" +func SetParameters(parameters string) { + CommandLine.parameters = parameters +} + +// SetParameters sets the parameters string for printing the s's usage. +// It defaults to "[parameters ...]" +func (s *Set) SetParameters(parameters string) { + s.parameters = parameters +} + +// SetProgram sets the program name to program. Normally it is determined +// from the zeroth command line argument (see os.Args). +func SetProgram(program string) { + CommandLine.program = program +} + +// SetProgram sets s's program name to program. Normally it is determined +// from the zeroth argument passed to Getopt or Parse. +func (s *Set) SetProgram(program string) { + s.program = program +} + +// SetUsage sets the function used by Parse to display the commands usage +// on error. It defaults to calling PrintUsage(os.Stderr). +func SetUsage(usage func()) { + CommandLine.usage = usage +} + +// SetUsage sets the function used by Parse to display usage on error. It +// defaults to calling f.PrintUsage(os.Stderr). +func (s *Set) SetUsage(usage func()) { + s.usage = usage +} + +// Lookup returns the Option associated with name. Name should either be +// a rune (the short name) or a string (the long name). +func Lookup(name interface{}) Option { + return CommandLine.Lookup(name) +} + +// Lookup returns the Option associated with name in s. Name should either be +// a rune (the short name) or a string (the long name). +func (s *Set) Lookup(name interface{}) Option { + switch v := name.(type) { + case rune: + return s.shortOptions[v] + case int: + return s.shortOptions[rune(v)] + case string: + return s.longOptions[v] + } + return nil +} + +// IsSet returns true if the Option associated with name was seen while +// parsing the command line arguments. Name should either be a rune (the +// short name) or a string (the long name). +func IsSet(name interface{}) bool { + return CommandLine.IsSet(name) +} + +// IsSet returns true if the Option associated with name was seen while +// parsing s. Name should either be a rune (the short name) or a string (the +// long name). +func (s *Set) IsSet(name interface{}) bool { + if opt := s.Lookup(name); opt != nil { + return opt.Seen() + } + return false +} + +// GetCount returns the number of times the Option associated with name has been +// seen while parsing the command line arguments. Name should either be a rune +// (the short name) or a string (the long name). +func GetCount(name interface{}) int { + return CommandLine.GetCount(name) +} + +// GetCount returns the number of times the Option associated with name has been +// seen while parsing s's arguments. Name should either be a rune (the short +// name) or a string (the long name). +func (s *Set) GetCount(name interface{}) int { + if opt := s.Lookup(name); opt != nil { + return opt.Count() + } + return 0 +} + +// GetValue returns the final value set to the command-line Option with name. +// If the option has not been seen while parsing s then the default value is +// returned. Name should either be a rune (the short name) or a string (the +// long name). +func GetValue(name interface{}) string { + return CommandLine.GetValue(name) +} + +// GetValue returns the final value set to the Option in s associated with name. +// If the option has not been seen while parsing s then the default value is +// returned. Name should either be a rune (the short name) or a string (the +// long name). +func (s *Set) GetValue(name interface{}) string { + if opt := s.Lookup(name); opt != nil { + return opt.String() + } + return "" +} + +// Visit visits the command-line options in lexicographical order, calling fn +// for each. It visits only those options that have been set. +func Visit(fn func(Option)) { CommandLine.Visit(fn) } + +// Visit visits the options in s in lexicographical order, calling fn +// for each. It visits only those options that have been set. +func (s *Set) Visit(fn func(Option)) { + sort.Sort(s.options) + for _, opt := range s.options { + if opt.count > 0 { + fn(opt) + } + } +} + +// VisitAll visits the options in s in lexicographical order, calling fn +// for each. It visits all options, even those not set. +func VisitAll(fn func(Option)) { CommandLine.VisitAll(fn) } + +// VisitAll visits the command-line flags in lexicographical order, calling fn +// for each. It visits all flags, even those not set. +func (s *Set) VisitAll(fn func(Option)) { + sort.Sort(s.options) + for _, opt := range s.options { + fn(opt) + } +} + +// Reset resets all the command line options to the initial state so it +// appears none of them have been seen. +func Reset() { + CommandLine.Reset() +} + +// Reset resets all the options in s to the initial state so it +// appears none of them have been seen. +func (s *Set) Reset() { + for _, opt := range s.options { + opt.Reset() + } +} diff --git a/vendor/github.com/pborman/getopt/v2/signed.go b/vendor/github.com/pborman/getopt/v2/signed.go new file mode 100644 index 0000000..dc371a7 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/signed.go @@ -0,0 +1,110 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" + "sync" +) + +type signed int64 + +type SignedLimit struct { + Base int // Base for conversion as per strconv.ParseInt + Bits int // Number of bits as per strconv.ParseInt + Min int64 // Minimum allowed value if both Min and Max are not 0 + Max int64 // Maximum allowed value if both Min and Max are not 0 +} + +var ( + signedLimitsMu sync.Mutex + signedLimits = make(map[*signed]*SignedLimit) +) + +func (n *signed) Set(value string, opt Option) error { + signedLimitsMu.Lock() + l := signedLimits[n] + signedLimitsMu.Unlock() + if l == nil { + return fmt.Errorf("no limits defined for %s", opt.Name()) + } + v, err := strconv.ParseInt(value, l.Base, l.Bits) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + if l.Min != 0 || l.Max != 0 { + if v < l.Min { + return fmt.Errorf("value out of range (<%v): %s", l.Min, value) + } + if v > l.Max { + return fmt.Errorf("value out of range (>%v): %s", l.Max, value) + } + } + *n = signed(v) + return nil +} + +func (n *signed) String() string { + signedLimitsMu.Lock() + l := signedLimits[n] + signedLimitsMu.Unlock() + if l != nil && l.Base != 0 { + return strconv.FormatInt(int64(*n), l.Base) + } + return strconv.FormatInt(int64(*n), 10) +} + +// Signed creates an option that is stored in an int64 and is constrained +// by the limits pointed to by l. The Max and Min values are only used if +// at least one of the values are not 0. If Base is 0, the base is implied by +// the string's prefix: base 16 for "0x", base 8 for "0", and base 10 otherwise. +func Signed(name rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + CommandLine.signedOption(&value, "", name, l, helpvalue...) + return &value +} + +func (s *Set) Signed(name rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + s.signedOption(&value, "", name, l, helpvalue...) + return &value +} + +func SignedLong(name string, short rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + CommandLine.signedOption(&value, name, short, l, helpvalue...) + return &value +} + +func (s *Set) SignedLong(name string, short rune, value int64, l *SignedLimit, helpvalue ...string) *int64 { + s.signedOption(&value, name, short, l, helpvalue...) + return &value +} + +func (s *Set) signedOption(p *int64, name string, short rune, l *SignedLimit, helpvalue ...string) { + opt := s.FlagLong((*signed)(p), name, short, helpvalue...) + if l.Base > 36 || l.Base == 1 || l.Base < 0 { + fmt.Fprintf(stderr, "invalid base for %s: %d\n", opt.Name(), l.Base) + exit(1) + } + if l.Bits < 0 || l.Bits > 64 { + fmt.Fprintf(stderr, "invalid bit size for %s: %d\n", opt.Name(), l.Bits) + exit(1) + } + if l.Min > l.Max { + fmt.Fprintf(stderr, "min greater than max for %s\n", opt.Name()) + exit(1) + } + lim := *l + signedLimitsMu.Lock() + signedLimits[(*signed)(p)] = &lim + signedLimitsMu.Unlock() +} diff --git a/vendor/github.com/pborman/getopt/v2/signed_test.go b/vendor/github.com/pborman/getopt/v2/signed_test.go new file mode 100644 index 0000000..768a06d --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/signed_test.go @@ -0,0 +1,97 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var signedNumberTests = []struct { + where string + in []string + l SignedLimit + out int64 + err string +}{ + { + where: loc(), + }, + { + loc(), + []string{"test", "-n", "1010"}, + SignedLimit{Base: 2, Bits: 5}, + 10, + "", + }, + { + loc(), + []string{"test", "-n", "1010"}, + SignedLimit{Base: 2, Bits: 4}, + 0, + "test: value out of range: 1010\n", + }, + { + loc(), + []string{"test", "-n", "-1000"}, + SignedLimit{Base: 2, Bits: 4}, + -8, + "", + }, + { + loc(), + []string{"test", "-n", "3"}, + SignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (<4): 3\n", + }, + { + loc(), + []string{"test", "-n", "4"}, + SignedLimit{Min: 4, Max: 6}, + 4, + "", + }, + { + loc(), + []string{"test", "-n", "5"}, + SignedLimit{Min: 4, Max: 6}, + 5, + "", + }, + { + loc(), + []string{"test", "-n", "6"}, + SignedLimit{Min: 4, Max: 6}, + 6, + "", + }, + { + loc(), + []string{"test", "-n", "7"}, + SignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (>6): 7\n", + }, +} + +func TestSigneds(t *testing.T) { + for x, tt := range signedNumberTests { + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + reset() + n := Signed('n', 0, &tt.l) + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *n != tt.out { + t.Errorf("%s: got %v, want %v", tt.where, *n, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/string.go b/vendor/github.com/pborman/getopt/v2/string.go new file mode 100644 index 0000000..cab5733 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/string.go @@ -0,0 +1,27 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +// String returns a value option that stores is value as a string. The +// initial value of the string is passed in value. +func String(name rune, value string, helpvalue ...string) *string { + CommandLine.Flag(&value, name, helpvalue...) + return &value +} + +func (s *Set) String(name rune, value string, helpvalue ...string) *string { + s.Flag(&value, name, helpvalue...) + return &value +} + +func StringLong(name string, short rune, value string, helpvalue ...string) *string { + CommandLine.FlagLong(&value, name, short, helpvalue...) + return &value +} + +func (s *Set) StringLong(name string, short rune, value string, helpvalue ...string) *string { + s.FlagLong(&value, name, short, helpvalue...) + return &value +} diff --git a/vendor/github.com/pborman/getopt/v2/string_test.go b/vendor/github.com/pborman/getopt/v2/string_test.go new file mode 100644 index 0000000..31abae8 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/string_test.go @@ -0,0 +1,77 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import "testing" + +var stringTests = []struct { + where string + in []string + sout string + optout string + err string +}{ + { + loc(), + []string{}, + "one", + "two", + "", + }, + { + loc(), + []string{"test", "-s"}, + "one", + "two", + "test: missing parameter for -s\n", + }, + { + loc(), + []string{"test", "--opt"}, + "one", + "two", + "test: missing parameter for --opt\n", + }, + { + loc(), + []string{"test", "-svalue", "--opt=option"}, + "value", + "option", + "", + }, + { + loc(), + []string{"test", "-s", "value", "--opt", "option"}, + "value", + "option", + "", + }, + { + loc(), + []string{"test", "-swrong", "--opt=wrong", "-s", "value", "--opt", "option"}, + "value", + "option", + "", + }, +} + +func TestString(t *testing.T) { + for _, tt := range stringTests { + reset() + s := String('s', "one") + opt := StringLong("opt", 0, "two") + + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *s != tt.sout { + t.Errorf("%s: got s = %q, want %q", tt.where, *s, tt.sout) + } + if *opt != tt.optout { + t.Errorf("%s: got opt = %q, want %q", tt.where, *opt, tt.optout) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/unsigned.go b/vendor/github.com/pborman/getopt/v2/unsigned.go new file mode 100644 index 0000000..5594660 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/unsigned.go @@ -0,0 +1,111 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strconv" + "sync" +) + +type unsigned uint64 + +type UnsignedLimit struct { + Base int // Base for conversion as per strconv.ParseInt + Bits int // Number of bits as per strconv.ParseInt + Min uint64 // Minimum allowed value if both Min and Max are not 0 + Max uint64 // Maximum allowed value if both Min and Max are not 0 +} + +var ( + unsignedLimitsMu sync.Mutex + unsignedLimits = make(map[*unsigned]*UnsignedLimit) +) + +func (n *unsigned) Set(value string, opt Option) error { + unsignedLimitsMu.Lock() + l := unsignedLimits[n] + unsignedLimitsMu.Unlock() + if l == nil { + return fmt.Errorf("no limits defined for %s", opt.Name()) + } + v, err := strconv.ParseUint(value, l.Base, l.Bits) + if err != nil { + if e, ok := err.(*strconv.NumError); ok { + switch e.Err { + case strconv.ErrRange: + err = fmt.Errorf("value out of range: %s", value) + case strconv.ErrSyntax: + err = fmt.Errorf("not a valid number: %s", value) + } + } + return err + } + if l.Min != 0 || l.Max != 0 { + if v < l.Min { + return fmt.Errorf("value out of range (<%v): %s", l.Min, value) + } + if v > l.Max { + return fmt.Errorf("value out of range (>%v): %s", l.Max, value) + } + } + *n = unsigned(v) + return nil +} + +func (n *unsigned) String() string { + unsignedLimitsMu.Lock() + l := unsignedLimits[n] + unsignedLimitsMu.Unlock() + if l != nil && l.Base != 0 { + return strconv.FormatUint(uint64(*n), l.Base) + } + return strconv.FormatUint(uint64(*n), 10) +} + +// Unsigned creates an option that is stored in a uint64 and is +// constrained by the limits pointed to by l. The Max and Min values are only +// used if at least one of the values are not 0. If Base is 0, the base is +// implied by the string's prefix: base 16 for "0x", base 8 for "0", and base +// 10 otherwise. +func Unsigned(name rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + CommandLine.unsignedOption(&value, "", name, l, helpvalue...) + return &value +} + +func (s *Set) Unsigned(name rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + s.unsignedOption(&value, "", name, l, helpvalue...) + return &value +} + +func UnsignedLong(name string, short rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + CommandLine.unsignedOption(&value, name, short, l, helpvalue...) + return &value +} + +func (s *Set) UnsignedLong(name string, short rune, value uint64, l *UnsignedLimit, helpvalue ...string) *uint64 { + s.unsignedOption(&value, name, short, l, helpvalue...) + return &value +} + +func (s *Set) unsignedOption(p *uint64, name string, short rune, l *UnsignedLimit, helpvalue ...string) { + opt := s.FlagLong((*unsigned)(p), name, short, helpvalue...) + if l.Base > 36 || l.Base == 1 || l.Base < 0 { + fmt.Fprintf(stderr, "invalid base for %s: %d\n", opt.Name(), l.Base) + exit(1) + } + if l.Bits < 0 || l.Bits > 64 { + fmt.Fprintf(stderr, "invalid bit size for %s: %d\n", opt.Name(), l.Bits) + exit(1) + } + if l.Min > l.Max { + fmt.Fprintf(stderr, "min greater than max for %s\n", opt.Name()) + exit(1) + } + lim := *l + unsignedLimitsMu.Lock() + unsignedLimits[(*unsigned)(p)] = &lim + unsignedLimitsMu.Unlock() +} diff --git a/vendor/github.com/pborman/getopt/v2/unsigned_test.go b/vendor/github.com/pborman/getopt/v2/unsigned_test.go new file mode 100644 index 0000000..bf3d61a --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/unsigned_test.go @@ -0,0 +1,97 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "strings" + "testing" +) + +var unsignedTests = []struct { + where string + in []string + l UnsignedLimit + out uint64 + err string +}{ + { + where: loc(), + }, + { + loc(), + []string{"test", "-n", "1010"}, + UnsignedLimit{Base: 2, Bits: 5}, + 10, + "", + }, + { + loc(), + []string{"test", "-n", "1010"}, + UnsignedLimit{Base: 2, Bits: 4}, + 10, + "", + }, + { + loc(), + []string{"test", "-n", "1010"}, + UnsignedLimit{Base: 2, Bits: 3}, + 0, + "test: value out of range: 1010\n", + }, + { + loc(), + []string{"test", "-n", "3"}, + UnsignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (<4): 3\n", + }, + { + loc(), + []string{"test", "-n", "4"}, + UnsignedLimit{Min: 4, Max: 6}, + 4, + "", + }, + { + loc(), + []string{"test", "-n", "5"}, + UnsignedLimit{Min: 4, Max: 6}, + 5, + "", + }, + { + loc(), + []string{"test", "-n", "6"}, + UnsignedLimit{Min: 4, Max: 6}, + 6, + "", + }, + { + loc(), + []string{"test", "-n", "7"}, + UnsignedLimit{Min: 4, Max: 6}, + 0, + "test: value out of range (>6): 7\n", + }, +} + +func TestUnsigneds(t *testing.T) { + for x, tt := range unsignedTests { + if strings.Index(tt.where, ":-") > 0 { + tt.where = fmt.Sprintf("#%d", x) + } + + reset() + n := Unsigned('n', 0, &tt.l) + parse(tt.in) + if s := checkError(tt.err); s != "" { + t.Errorf("%s: %s", tt.where, s) + } + if *n != tt.out { + t.Errorf("%s: got %v, want %v", tt.where, *n, tt.out) + } + } +} diff --git a/vendor/github.com/pborman/getopt/v2/util_test.go b/vendor/github.com/pborman/getopt/v2/util_test.go new file mode 100644 index 0000000..d46e198 --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/util_test.go @@ -0,0 +1,85 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "bytes" + "fmt" + "path" + "reflect" + "runtime" + "strings" +) + +var errorString string + +func reset() { + CommandLine.shortOptions = make(map[rune]*option) + CommandLine.longOptions = make(map[string]*option) + CommandLine.options = nil + CommandLine.args = nil + CommandLine.program = "" + errorString = "" +} + +func parse(args []string) { + err := CommandLine.Getopt(args, nil) + if err != nil { + b := &bytes.Buffer{} + + fmt.Fprintln(b, CommandLine.program+": "+err.Error()) + CommandLine.PrintUsage(b) + errorString = b.String() + } +} + +func badSlice(a, b []string) bool { + if len(a) != len(b) { + return true + } + for x, v := range a { + if b[x] != v { + return true + } + } + return false +} + +func loc() string { + _, file, line, _ := runtime.Caller(1) + return fmt.Sprintf("%s:%d", path.Base(file), line) +} + +func (o *option) Equal(opt *option) bool { + if o.value != nil && opt.value == nil { + return false + } + if o.value == nil && opt.value != nil { + return false + } + if o.value != nil && o.value.String() != opt.value.String() { + return false + } + + oc := *o + optc := *opt + oc.value = nil + optc.value = nil + return reflect.DeepEqual(&oc, &optc) +} + +func checkError(err string) string { + switch { + case err == errorString: + return "" + case err == "": + return fmt.Sprintf("unexpected error %q", errorString) + case errorString == "": + return fmt.Sprintf("did not get expected error %q", err) + case !strings.HasPrefix(errorString, err): + return fmt.Sprintf("got error %q, want %q", errorString, err) + } + return "" +} diff --git a/vendor/github.com/pborman/getopt/v2/var.go b/vendor/github.com/pborman/getopt/v2/var.go new file mode 100644 index 0000000..0aaa79c --- /dev/null +++ b/vendor/github.com/pborman/getopt/v2/var.go @@ -0,0 +1,100 @@ +// Copyright 2017 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "runtime" + "strings" +) + +// Value is the interface to the dynamic value stored in a flag. Flags of type +// Value are declared using the Flag and FlagLong functions. +type Value interface { + // Set converts value into the appropriate type and assigns it to the + // receiver value. Option details are provided via opt (such as the + // flags name). + // + // Set is used to reset the value of an option to its default value + // (which is stored in string form internally). + Set(value string, opt Option) error + + // String returns the value of the flag as a string. + String() string +} + +var thisPackage string + +// init initializes thisPackage to our full package with the trailing . +// included. +func init() { + pc, _, _, ok := runtime.Caller(0) + if !ok { + return + } + f := runtime.FuncForPC(pc) + if f == nil { + return + } + thisPackage = f.Name() + x := strings.LastIndex(thisPackage, "/") + if x < 0 { + return + } + y := strings.Index(thisPackage[x:], ".") + if y < 0 { + return + } + // thisPackage includes the trailing . after the package name. + thisPackage = thisPackage[:x+y+1] +} + +// calledFrom returns a string containing the file and linenumber of the first +// stack frame above us that is not part of this package and is not a test. +// This is used to determine where a flag was initialized. +func calledFrom() string { + for i := 2; ; i++ { + pc, file, line, ok := runtime.Caller(i) + if !ok { + return "" + } + if !strings.HasSuffix(file, "_test.go") { + f := runtime.FuncForPC(pc) + if f != nil && strings.HasPrefix(f.Name(), thisPackage) { + continue + } + } + return fmt.Sprintf("%s:%d", file, line) + } +} + +func (s *Set) addFlag(p Value, name string, short rune, helpvalue ...string) Option { + opt := &option{ + short: short, + long: name, + value: p, + defval: p.String(), + } + + switch len(helpvalue) { + case 2: + opt.name = helpvalue[1] + fallthrough + case 1: + opt.help = helpvalue[0] + case 0: + default: + panic("Too many strings for String helpvalue") + } + if where := calledFrom(); where != "" { + opt.where = where + } + if opt.short == 0 && opt.long == "" { + fmt.Fprintf(stderr, opt.where+": no short or long option given") + exit(1) + } + s.AddOption(opt) + return opt +} diff --git a/vendor/github.com/pborman/getopt/var.go b/vendor/github.com/pborman/getopt/var.go new file mode 100644 index 0000000..fd816b9 --- /dev/null +++ b/vendor/github.com/pborman/getopt/var.go @@ -0,0 +1,63 @@ +// Copyright 2013 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package getopt + +import ( + "fmt" + "runtime" +) + +// Value is the interface to the dynamic value stored in a flag. (The default +// value is represented as a string.) Set is passed the string to set the +// value to as well as the Option that is being processed. +type Value interface { + Set(string, Option) error + String() string +} + +// Var creates an option of the specified name. The type and value of the option +// are represented by the first argument, of type Value, which typically holds a +// user-defined implementation of Value. All options are ultimately created +// as a Var. +func Var(p Value, name rune, helpvalue ...string) Option { + return CommandLine.VarLong(p, "", name, helpvalue...) +} + +func VarLong(p Value, name string, short rune, helpvalue ...string) Option { + return CommandLine.VarLong(p, name, short, helpvalue...) +} + +func (s *Set) Var(p Value, name rune, helpvalue ...string) Option { + return s.VarLong(p, "", name, helpvalue...) +} + +func (s *Set) VarLong(p Value, name string, short rune, helpvalue ...string) Option { + opt := &option{ + short: short, + long: name, + value: p, + defval: p.String(), + } + + switch len(helpvalue) { + case 2: + opt.name = helpvalue[1] + fallthrough + case 1: + opt.help = helpvalue[0] + case 0: + default: + panic("Too many strings for String helpvalue") + } + if _, file, line, ok := runtime.Caller(1); ok { + opt.where = fmt.Sprintf("%s:%d", file, line) + } + if opt.short == 0 && opt.long == "" { + fmt.Fprintf(stderr, opt.where+": no short or long option given") + exit(1) + } + s.AddOption(opt) + return opt +} diff --git a/vendor/github.com/utahta/go-openuri/openuri.go b/vendor/github.com/utahta/go-openuri/openuri.go new file mode 100644 index 0000000..a1ce966 --- /dev/null +++ b/vendor/github.com/utahta/go-openuri/openuri.go @@ -0,0 +1,54 @@ +package openuri + +import ( + "io" + "net/http" + "os" + "strings" +) + +// Client type +type Client struct { + httpClient *http.Client +} + +// ClientOption type +type ClientOption func(*Client) error + +// New returns a Client struct +func New(options ...ClientOption) (*Client, error) { + c := &Client{httpClient: http.DefaultClient} + for _, option := range options { + if err := option(c); err != nil { + return nil, err + } + } + return c, nil +} + +// Open an io.ReadCloser from a local file or URL +func Open(name string, options ...ClientOption) (io.ReadCloser, error) { + c, err := New(options...) + if err != nil { + return nil, err + } + return c.Open(name) +} + +func WithHTTPClient(v *http.Client) ClientOption { + return func(c *Client) error { + c.httpClient = v + return nil + } +} + +func (c *Client) Open(name string) (io.ReadCloser, error) { + if strings.HasPrefix(name, "http://") || strings.HasPrefix(name, "https://") { + resp, err := c.httpClient.Get(name) + if err != nil { + return nil, err + } + return resp.Body, nil + } + return os.Open(name) +} diff --git a/vendor/github.com/utahta/go-openuri/openuri_test.go b/vendor/github.com/utahta/go-openuri/openuri_test.go new file mode 100644 index 0000000..7f653e6 --- /dev/null +++ b/vendor/github.com/utahta/go-openuri/openuri_test.go @@ -0,0 +1,74 @@ +package openuri + +import ( + "io/ioutil" + "net/http" + "strings" + "testing" +) + +type dummyRoundTripper struct{} + +func (d *dummyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + return &http.Response{Status: "dummy", Body: ioutil.NopCloser(strings.NewReader("body dummy"))}, nil +} + +func TestNew(t *testing.T) { + _, err := New() + if err != nil { + t.Error(err) + } +} + +func TestWithHTTPClient(t *testing.T) { + c, err := New(WithHTTPClient(&http.Client{Transport: &dummyRoundTripper{}})) + if err != nil { + t.Error(err) + } + + resp, _ := c.httpClient.Get("test") + if resp.Status != "dummy" { + t.Errorf("Expected status dummy, got %s", resp.Status) + } +} + +func TestOpen_File(t *testing.T) { + o, err := Open("./openuri.go") + if err != nil { + t.Error(err) + } + + b, err := ioutil.ReadAll(o) + if err != nil { + t.Error(err) + } + + if !strings.HasPrefix(string(b), "package openuri") { + t.Errorf("Expected open file, go %s", string(b)) + } +} + +func TestOpen_URL(t *testing.T) { + tests := []struct { + url string + }{ + {"http://example.com"}, + {"https://example.com"}, + } + + for _, test := range tests { + o, err := Open(test.url, WithHTTPClient(&http.Client{Transport: &dummyRoundTripper{}})) + if err != nil { + t.Error(err) + } + + b, err := ioutil.ReadAll(o) + if err != nil { + t.Error(err) + } + + if !strings.HasPrefix(string(b), "body dummy") { + t.Errorf("Expected open file, go %s", string(b)) + } + } +} diff --git a/vendor/gopkg.in/go-playground/validator.v9/README.md b/vendor/gopkg.in/go-playground/validator.v9/README.md index 0259370..d783749 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/README.md +++ b/vendor/gopkg.in/go-playground/validator.v9/README.md @@ -1,7 +1,7 @@ Package validator ================ <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v9/logo.png">[![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-9.9.0-green.svg) +![Project status](https://img.shields.io/badge/version-9.11.0-green.svg) [![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) @@ -66,69 +66,71 @@ Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usa Benchmarks ------ -###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.2 darwin/amd64 +###### Run on MacBook Pro (15-inch, 2017) Go version go1.9.4 darwin/amd64 ```go -go test -bench=. -benchmem=true -BenchmarkFieldSuccess-8 20000000 79.9 ns/op 0 B/op 0 allocs/op -BenchmarkFieldSuccessParallel-8 50000000 25.0 ns/op 0 B/op 0 allocs/op -BenchmarkFieldFailure-8 5000000 281 ns/op 208 B/op 4 allocs/op -BenchmarkFieldFailureParallel-8 20000000 97.0 ns/op 208 B/op 4 allocs/op -BenchmarkFieldArrayDiveSuccess-8 3000000 591 ns/op 201 B/op 11 allocs/op -BenchmarkFieldArrayDiveSuccessParallel-8 10000000 195 ns/op 201 B/op 11 allocs/op -BenchmarkFieldArrayDiveFailure-8 2000000 878 ns/op 412 B/op 16 allocs/op -BenchmarkFieldArrayDiveFailureParallel-8 5000000 274 ns/op 413 B/op 16 allocs/op -BenchmarkFieldMapDiveSuccess-8 1000000 1279 ns/op 432 B/op 18 allocs/op -BenchmarkFieldMapDiveSuccessParallel-8 5000000 401 ns/op 432 B/op 18 allocs/op -BenchmarkFieldMapDiveFailure-8 1000000 1060 ns/op 512 B/op 16 allocs/op -BenchmarkFieldMapDiveFailureParallel-8 5000000 334 ns/op 512 B/op 16 allocs/op -BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1462 ns/op 480 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 463 ns/op 480 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1414 ns/op 721 B/op 21 allocs/op -BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 446 ns/op 721 B/op 21 allocs/op -BenchmarkFieldCustomTypeSuccess-8 10000000 211 ns/op 32 B/op 2 allocs/op -BenchmarkFieldCustomTypeSuccessParallel-8 20000000 65.9 ns/op 32 B/op 2 allocs/op -BenchmarkFieldCustomTypeFailure-8 5000000 270 ns/op 208 B/op 4 allocs/op -BenchmarkFieldCustomTypeFailureParallel-8 20000000 93.3 ns/op 208 B/op 4 allocs/op -BenchmarkFieldOrTagSuccess-8 2000000 729 ns/op 16 B/op 1 allocs/op -BenchmarkFieldOrTagSuccessParallel-8 5000000 367 ns/op 16 B/op 1 allocs/op -BenchmarkFieldOrTagFailure-8 3000000 472 ns/op 224 B/op 5 allocs/op -BenchmarkFieldOrTagFailureParallel-8 5000000 373 ns/op 224 B/op 5 allocs/op -BenchmarkStructLevelValidationSuccess-8 10000000 201 ns/op 32 B/op 2 allocs/op -BenchmarkStructLevelValidationSuccessParallel-8 20000000 66.3 ns/op 32 B/op 2 allocs/op -BenchmarkStructLevelValidationFailure-8 3000000 468 ns/op 304 B/op 8 allocs/op -BenchmarkStructLevelValidationFailureParallel-8 10000000 172 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCustomTypeSuccess-8 5000000 376 ns/op 32 B/op 2 allocs/op -BenchmarkStructSimpleCustomTypeSuccessParallel-8 20000000 126 ns/op 32 B/op 2 allocs/op -BenchmarkStructSimpleCustomTypeFailure-8 2000000 646 ns/op 424 B/op 9 allocs/op -BenchmarkStructSimpleCustomTypeFailureParallel-8 10000000 240 ns/op 440 B/op 10 allocs/op -BenchmarkStructFilteredSuccess-8 3000000 582 ns/op 288 B/op 9 allocs/op -BenchmarkStructFilteredSuccessParallel-8 10000000 198 ns/op 288 B/op 9 allocs/op -BenchmarkStructFilteredFailure-8 3000000 447 ns/op 256 B/op 7 allocs/op -BenchmarkStructFilteredFailureParallel-8 10000000 156 ns/op 256 B/op 7 allocs/op -BenchmarkStructPartialSuccess-8 3000000 536 ns/op 256 B/op 6 allocs/op -BenchmarkStructPartialSuccessParallel-8 10000000 175 ns/op 256 B/op 6 allocs/op -BenchmarkStructPartialFailure-8 2000000 738 ns/op 480 B/op 11 allocs/op -BenchmarkStructPartialFailureParallel-8 5000000 256 ns/op 480 B/op 11 allocs/op -BenchmarkStructExceptSuccess-8 2000000 835 ns/op 496 B/op 12 allocs/op -BenchmarkStructExceptSuccessParallel-8 10000000 163 ns/op 240 B/op 5 allocs/op -BenchmarkStructExceptFailure-8 2000000 682 ns/op 464 B/op 10 allocs/op -BenchmarkStructExceptFailureParallel-8 10000000 244 ns/op 464 B/op 10 allocs/op -BenchmarkStructSimpleCrossFieldSuccess-8 5000000 392 ns/op 72 B/op 3 allocs/op -BenchmarkStructSimpleCrossFieldSuccessParallel-8 20000000 126 ns/op 72 B/op 3 allocs/op -BenchmarkStructSimpleCrossFieldFailure-8 2000000 611 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 214 ns/op 304 B/op 8 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 3000000 567 ns/op 80 B/op 4 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 177 ns/op 80 B/op 4 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 807 ns/op 320 B/op 9 allocs/op -BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 268 ns/op 320 B/op 9 allocs/op -BenchmarkStructSimpleSuccess-8 5000000 256 ns/op 0 B/op 0 allocs/op -BenchmarkStructSimpleSuccessParallel-8 20000000 76.3 ns/op 0 B/op 0 allocs/op -BenchmarkStructSimpleFailure-8 2000000 625 ns/op 424 B/op 9 allocs/op -BenchmarkStructSimpleFailureParallel-8 10000000 219 ns/op 424 B/op 9 allocs/op -BenchmarkStructComplexSuccess-8 1000000 1431 ns/op 128 B/op 8 allocs/op -BenchmarkStructComplexSuccessParallel-8 3000000 427 ns/op 128 B/op 8 allocs/op -BenchmarkStructComplexFailure-8 300000 4065 ns/op 3041 B/op 53 allocs/op -BenchmarkStructComplexFailureParallel-8 1000000 1478 ns/op 3041 B/op 53 allocs/op +goos: darwin +goarch: amd64 +pkg: github.com/go-playground/validator +BenchmarkFieldSuccess-8 20000000 86.4 ns/op 0 B/op 0 allocs/op +BenchmarkFieldSuccessParallel-8 50000000 27.6 ns/op 0 B/op 0 allocs/op +BenchmarkFieldFailure-8 5000000 297 ns/op 208 B/op 4 allocs/op +BenchmarkFieldFailureParallel-8 20000000 107 ns/op 208 B/op 4 allocs/op +BenchmarkFieldArrayDiveSuccess-8 2000000 618 ns/op 201 B/op 11 allocs/op +BenchmarkFieldArrayDiveSuccessParallel-8 10000000 225 ns/op 201 B/op 11 allocs/op +BenchmarkFieldArrayDiveFailure-8 2000000 863 ns/op 412 B/op 16 allocs/op +BenchmarkFieldArrayDiveFailureParallel-8 5000000 322 ns/op 413 B/op 16 allocs/op +BenchmarkFieldMapDiveSuccess-8 1000000 1336 ns/op 432 B/op 18 allocs/op +BenchmarkFieldMapDiveSuccessParallel-8 3000000 474 ns/op 432 B/op 18 allocs/op +BenchmarkFieldMapDiveFailure-8 1000000 1103 ns/op 512 B/op 16 allocs/op +BenchmarkFieldMapDiveFailureParallel-8 5000000 412 ns/op 512 B/op 16 allocs/op +BenchmarkFieldMapDiveWithKeysSuccess-8 1000000 1572 ns/op 480 B/op 21 allocs/op +BenchmarkFieldMapDiveWithKeysSuccessParallel-8 3000000 615 ns/op 480 B/op 21 allocs/op +BenchmarkFieldMapDiveWithKeysFailure-8 1000000 1438 ns/op 721 B/op 21 allocs/op +BenchmarkFieldMapDiveWithKeysFailureParallel-8 3000000 543 ns/op 721 B/op 21 allocs/op +BenchmarkFieldCustomTypeSuccess-8 10000000 230 ns/op 32 B/op 2 allocs/op +BenchmarkFieldCustomTypeSuccessParallel-8 20000000 82.5 ns/op 32 B/op 2 allocs/op +BenchmarkFieldCustomTypeFailure-8 5000000 284 ns/op 208 B/op 4 allocs/op +BenchmarkFieldCustomTypeFailureParallel-8 20000000 118 ns/op 208 B/op 4 allocs/op +BenchmarkFieldOrTagSuccess-8 2000000 824 ns/op 16 B/op 1 allocs/op +BenchmarkFieldOrTagSuccessParallel-8 3000000 472 ns/op 16 B/op 1 allocs/op +BenchmarkFieldOrTagFailure-8 3000000 487 ns/op 224 B/op 5 allocs/op +BenchmarkFieldOrTagFailureParallel-8 5000000 405 ns/op 224 B/op 5 allocs/op +BenchmarkStructLevelValidationSuccess-8 10000000 214 ns/op 32 B/op 2 allocs/op +BenchmarkStructLevelValidationSuccessParallel-8 20000000 78.0 ns/op 32 B/op 2 allocs/op +BenchmarkStructLevelValidationFailure-8 3000000 475 ns/op 304 B/op 8 allocs/op +BenchmarkStructLevelValidationFailureParallel-8 10000000 200 ns/op 304 B/op 8 allocs/op +BenchmarkStructSimpleCustomTypeSuccess-8 3000000 403 ns/op 32 B/op 2 allocs/op +BenchmarkStructSimpleCustomTypeSuccessParallel-8 10000000 143 ns/op 32 B/op 2 allocs/op +BenchmarkStructSimpleCustomTypeFailure-8 2000000 655 ns/op 424 B/op 9 allocs/op +BenchmarkStructSimpleCustomTypeFailureParallel-8 5000000 286 ns/op 440 B/op 10 allocs/op +BenchmarkStructFilteredSuccess-8 2000000 598 ns/op 288 B/op 9 allocs/op +BenchmarkStructFilteredSuccessParallel-8 10000000 231 ns/op 288 B/op 9 allocs/op +BenchmarkStructFilteredFailure-8 3000000 455 ns/op 256 B/op 7 allocs/op +BenchmarkStructFilteredFailureParallel-8 10000000 197 ns/op 256 B/op 7 allocs/op +BenchmarkStructPartialSuccess-8 3000000 552 ns/op 256 B/op 6 allocs/op +BenchmarkStructPartialSuccessParallel-8 10000000 206 ns/op 256 B/op 6 allocs/op +BenchmarkStructPartialFailure-8 2000000 750 ns/op 480 B/op 11 allocs/op +BenchmarkStructPartialFailureParallel-8 5000000 317 ns/op 480 B/op 11 allocs/op +BenchmarkStructExceptSuccess-8 2000000 853 ns/op 496 B/op 12 allocs/op +BenchmarkStructExceptSuccessParallel-8 10000000 179 ns/op 240 B/op 5 allocs/op +BenchmarkStructExceptFailure-8 2000000 698 ns/op 464 B/op 10 allocs/op +BenchmarkStructExceptFailureParallel-8 5000000 276 ns/op 464 B/op 10 allocs/op +BenchmarkStructSimpleCrossFieldSuccess-8 3000000 412 ns/op 72 B/op 3 allocs/op +BenchmarkStructSimpleCrossFieldSuccessParallel-8 10000000 148 ns/op 72 B/op 3 allocs/op +BenchmarkStructSimpleCrossFieldFailure-8 2000000 630 ns/op 304 B/op 8 allocs/op +BenchmarkStructSimpleCrossFieldFailureParallel-8 10000000 244 ns/op 304 B/op 8 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 2000000 610 ns/op 80 B/op 4 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-8 10000000 205 ns/op 80 B/op 4 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldFailure-8 2000000 861 ns/op 320 B/op 9 allocs/op +BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-8 5000000 315 ns/op 320 B/op 9 allocs/op +BenchmarkStructSimpleSuccess-8 5000000 279 ns/op 0 B/op 0 allocs/op +BenchmarkStructSimpleSuccessParallel-8 20000000 86.4 ns/op 0 B/op 0 allocs/op +BenchmarkStructSimpleFailure-8 2000000 636 ns/op 424 B/op 9 allocs/op +BenchmarkStructSimpleFailureParallel-8 10000000 264 ns/op 424 B/op 9 allocs/op +BenchmarkStructComplexSuccess-8 1000000 1539 ns/op 128 B/op 8 allocs/op +BenchmarkStructComplexSuccessParallel-8 3000000 557 ns/op 128 B/op 8 allocs/op +BenchmarkStructComplexFailure-8 300000 4136 ns/op 3041 B/op 53 allocs/op +BenchmarkStructComplexFailureParallel-8 1000000 1855 ns/op 3041 B/op 53 allocs/op ``` Complementary Software diff --git a/vendor/gopkg.in/go-playground/validator.v9/baked_in.go b/vendor/gopkg.in/go-playground/validator.v9/baked_in.go index 6654094..231b78e 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/baked_in.go +++ b/vendor/gopkg.in/go-playground/validator.v9/baked_in.go @@ -6,7 +6,9 @@ import ( "net" "net/url" "reflect" + "strconv" "strings" + "sync" "time" "unicode/utf8" ) @@ -55,88 +57,130 @@ var ( // you can add, remove or even replace items to suite your needs, // or even disregard and use your own map if so desired. bakedInValidators = map[string]Func{ - "required": hasValue, - "isdefault": isDefault, - "len": hasLengthOf, - "min": hasMinOf, - "max": hasMaxOf, - "eq": isEq, - "ne": isNe, - "lt": isLt, - "lte": isLte, - "gt": isGt, - "gte": isGte, - "eqfield": isEqField, - "eqcsfield": isEqCrossStructField, - "necsfield": isNeCrossStructField, - "gtcsfield": isGtCrossStructField, - "gtecsfield": isGteCrossStructField, - "ltcsfield": isLtCrossStructField, - "ltecsfield": isLteCrossStructField, - "nefield": isNeField, - "gtefield": isGteField, - "gtfield": isGtField, - "ltefield": isLteField, - "ltfield": isLtField, - "alpha": isAlpha, - "alphanum": isAlphanum, - "alphaunicode": isAlphaUnicode, - "alphanumunicode": isAlphanumUnicode, - "numeric": isNumeric, - "number": isNumber, - "hexadecimal": isHexadecimal, - "hexcolor": isHEXColor, - "rgb": isRGB, - "rgba": isRGBA, - "hsl": isHSL, - "hsla": isHSLA, - "email": isEmail, - "url": isURL, - "uri": isURI, - "base64": isBase64, - "contains": contains, - "containsany": containsAny, - "containsrune": containsRune, - "excludes": excludes, - "excludesall": excludesAll, - "excludesrune": excludesRune, - "isbn": isISBN, - "isbn10": isISBN10, - "isbn13": isISBN13, - "uuid": isUUID, - "uuid3": isUUID3, - "uuid4": isUUID4, - "uuid5": isUUID5, - "ascii": isASCII, - "printascii": isPrintableASCII, - "multibyte": hasMultiByteCharacter, - "datauri": isDataURI, - "latitude": isLatitude, - "longitude": isLongitude, - "ssn": isSSN, - "ipv4": isIPv4, - "ipv6": isIPv6, - "ip": isIP, - "cidrv4": isCIDRv4, - "cidrv6": isCIDRv6, - "cidr": isCIDR, - "tcp4_addr": isTCP4AddrResolvable, - "tcp6_addr": isTCP6AddrResolvable, - "tcp_addr": isTCPAddrResolvable, - "udp4_addr": isUDP4AddrResolvable, - "udp6_addr": isUDP6AddrResolvable, - "udp_addr": isUDPAddrResolvable, - "ip4_addr": isIP4AddrResolvable, - "ip6_addr": isIP6AddrResolvable, - "ip_addr": isIPAddrResolvable, - "unix_addr": isUnixAddrResolvable, - "mac": isMAC, - "hostname": isHostname, - "fqdn": isFQDN, - "unique": isUnique, + "required": hasValue, + "isdefault": isDefault, + "len": hasLengthOf, + "min": hasMinOf, + "max": hasMaxOf, + "eq": isEq, + "ne": isNe, + "lt": isLt, + "lte": isLte, + "gt": isGt, + "gte": isGte, + "eqfield": isEqField, + "eqcsfield": isEqCrossStructField, + "necsfield": isNeCrossStructField, + "gtcsfield": isGtCrossStructField, + "gtecsfield": isGteCrossStructField, + "ltcsfield": isLtCrossStructField, + "ltecsfield": isLteCrossStructField, + "nefield": isNeField, + "gtefield": isGteField, + "gtfield": isGtField, + "ltefield": isLteField, + "ltfield": isLtField, + "alpha": isAlpha, + "alphanum": isAlphanum, + "alphaunicode": isAlphaUnicode, + "alphanumunicode": isAlphanumUnicode, + "numeric": isNumeric, + "number": isNumber, + "hexadecimal": isHexadecimal, + "hexcolor": isHEXColor, + "rgb": isRGB, + "rgba": isRGBA, + "hsl": isHSL, + "hsla": isHSLA, + "email": isEmail, + "url": isURL, + "uri": isURI, + "base64": isBase64, + "contains": contains, + "containsany": containsAny, + "containsrune": containsRune, + "excludes": excludes, + "excludesall": excludesAll, + "excludesrune": excludesRune, + "isbn": isISBN, + "isbn10": isISBN10, + "isbn13": isISBN13, + "uuid": isUUID, + "uuid3": isUUID3, + "uuid4": isUUID4, + "uuid5": isUUID5, + "ascii": isASCII, + "printascii": isPrintableASCII, + "multibyte": hasMultiByteCharacter, + "datauri": isDataURI, + "latitude": isLatitude, + "longitude": isLongitude, + "ssn": isSSN, + "ipv4": isIPv4, + "ipv6": isIPv6, + "ip": isIP, + "cidrv4": isCIDRv4, + "cidrv6": isCIDRv6, + "cidr": isCIDR, + "tcp4_addr": isTCP4AddrResolvable, + "tcp6_addr": isTCP6AddrResolvable, + "tcp_addr": isTCPAddrResolvable, + "udp4_addr": isUDP4AddrResolvable, + "udp6_addr": isUDP6AddrResolvable, + "udp_addr": isUDPAddrResolvable, + "ip4_addr": isIP4AddrResolvable, + "ip6_addr": isIP6AddrResolvable, + "ip_addr": isIPAddrResolvable, + "unix_addr": isUnixAddrResolvable, + "mac": isMAC, + "hostname": isHostnameRFC952, // RFC 952 + "hostname_rfc1123": isHostnameRFC1123, // RFC 1123 + "fqdn": isFQDN, + "unique": isUnique, + "oneof": isOneOf, } ) +var oneofValsCache = map[string][]string{} +var oneofValsCacheRWLock = sync.RWMutex{} + +func parseOneOfParam2(s string) []string { + oneofValsCacheRWLock.RLock() + vals, ok := oneofValsCache[s] + oneofValsCacheRWLock.RUnlock() + if !ok { + oneofValsCacheRWLock.Lock() + vals = strings.Fields(s) + oneofValsCache[s] = vals + oneofValsCacheRWLock.Unlock() + } + return vals +} + +func isOneOf(fl FieldLevel) bool { + vals := parseOneOfParam2(fl.Param()) + + field := fl.Field() + + var v string + switch field.Kind() { + case reflect.String: + v = field.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v = strconv.FormatInt(field.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v = strconv.FormatUint(field.Uint(), 10) + default: + panic(fmt.Sprintf("Bad field type %T", field.Interface())) + } + for i := 0; i < len(vals); i++ { + if vals[i] == v { + return true + } + } + return false +} + // isUnique is the validation function for validating if each array|slice element is unique func isUnique(fl FieldLevel) bool { @@ -1511,8 +1555,12 @@ func isIP6Addr(fl FieldLevel) bool { return ip != nil && ip.To4() == nil } -func isHostname(fl FieldLevel) bool { - return hostnameRegex.MatchString(fl.Field().String()) +func isHostnameRFC952(fl FieldLevel) bool { + return hostnameRegexRFC952.MatchString(fl.Field().String()) +} + +func isHostnameRFC1123(fl FieldLevel) bool { + return hostnameRegexRFC1123.MatchString(fl.Field().String()) } func isFQDN(fl FieldLevel) bool { @@ -1526,6 +1574,6 @@ func isFQDN(fl FieldLevel) bool { val = val[0 : len(val)-1] } - return (strings.IndexAny(val, ".") > -1) && - hostnameRegex.MatchString(val) + return strings.ContainsAny(val, ".") && + hostnameRegexRFC952.MatchString(val) } diff --git a/vendor/gopkg.in/go-playground/validator.v9/benchmarks_test.go b/vendor/gopkg.in/go-playground/validator.v9/benchmarks_test.go index 3e7e79f..5ac871f 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/benchmarks_test.go +++ b/vendor/gopkg.in/go-playground/validator.v9/benchmarks_test.go @@ -1184,3 +1184,27 @@ func BenchmarkStructComplexFailureParallel(b *testing.B) { } }) } + +type TestOneof struct { + Color string `validate:"oneof=red green"` +} + +func BenchmarkOneof(b *testing.B) { + w := &TestOneof{Color: "green"} + val := New() + for i := 0; i < b.N; i++ { + val.Struct(w) + } +} + +func BenchmarkOneofParallel(b *testing.B) { + w := &TestOneof{Color: "green"} + val := New() + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + val.Struct(w) + } + }) +} diff --git a/vendor/gopkg.in/go-playground/validator.v9/cache.go b/vendor/gopkg.in/go-playground/validator.v9/cache.go index 8c59e16..c7fb0fb 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/cache.go +++ b/vendor/gopkg.in/go-playground/validator.v9/cache.go @@ -91,12 +91,14 @@ type cTag struct { aliasTag string actualAliasTag string param string - typeof tagType keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation next *cTag + fn FuncCtx + typeof tagType hasTag bool hasAlias bool - fn FuncCtx + hasParam bool // true if parameter used eg. eq= where the equal sign has been set + isBlockEnd bool // indicates the current tag represents the last validation in the block } func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { @@ -291,6 +293,7 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true} current = current.next } + current.hasParam = len(vals) > 1 current.tag = vals[0] if len(current.tag) == 0 { @@ -309,8 +312,26 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) } } + current.isBlockEnd = true } } - return } + +func (v *Validate) fetchCacheTag(tag string) *cTag { + // find cached tag + ctag, found := v.tagCache.Get(tag) + if !found { + v.tagCache.lock.Lock() + defer v.tagCache.lock.Unlock() + + // could have been multiple trying to access, but once first is done this ensures tag + // isn't parsed again. + ctag, found = v.tagCache.Get(tag) + if !found { + ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) + v.tagCache.Set(tag, ctag) + } + } + return ctag +} diff --git a/vendor/gopkg.in/go-playground/validator.v9/doc.go b/vendor/gopkg.in/go-playground/validator.v9/doc.go index d3a69f7..f7efe23 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/doc.go +++ b/vendor/gopkg.in/go-playground/validator.v9/doc.go @@ -94,7 +94,7 @@ used "eqcsfield" it could be multiple levels down. Example: // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed // into the function - // when calling validate.FieldWithValue(val, field, tag) val will be + // when calling validate.VarWithValue(val, field, tag) val will be // whatever you pass, struct, field... // when calling validate.Field(field, tag) val will be nil @@ -132,7 +132,7 @@ so the above will become excludesall=0x2C. Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation. } -Pipe ("|") is the default separator of validation tags. If you wish to +Pipe ("|") is the 'or' validation tags deparator. If you wish to have a pipe included within the parameter i.e. excludesall=| you will need to use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe, so the above will become excludesall=0x7C @@ -295,6 +295,16 @@ validates the number of items. Usage: ne=10 +One Of + +For strings, ints, and uints, oneof will ensure that the value +is one of the values in the parameter. The parameter should be +a list of values separated by whitespace. Values may be +strings or numbers. + + Usage: oneof=red green + oneof=5 7 9 + Greater Than For numbers, this will ensure that the value is greater than the @@ -369,7 +379,7 @@ Example #1: Example #2: // Validating by field: - validate.FieldWithValue(password, confirmpassword, "eqfield") + validate.VarWithValue(password, confirmpassword, "eqfield") Field Equals Another Field (relative) @@ -391,7 +401,7 @@ Examples: Usage: nefield=Color2 // Validating by field: - validate.FieldWithValue(color1, color2, "nefield") + validate.VarWithValue(color1, color2, "nefield") Field Does Not Equal Another Field (relative) @@ -414,7 +424,7 @@ Example #1: Example #2: // Validating by field: - validate.FieldWithValue(start, end, "gtfield") + validate.VarWithValue(start, end, "gtfield") Field Greater Than Another Relative Field @@ -438,7 +448,7 @@ Example #1: Example #2: // Validating by field: - validate.FieldWithValue(start, end, "gtefield") + validate.VarWithValue(start, end, "gtefield") Field Greater Than or Equal To Another Relative Field @@ -461,7 +471,7 @@ Example #1: Example #2: // Validating by field: - validate.FieldWithValue(start, end, "ltfield") + validate.VarWithValue(start, end, "ltfield") Less Than Another Relative Field @@ -484,7 +494,7 @@ Example #1: Example #2: // Validating by field: - validate.FieldWithValue(start, end, "ltefield") + validate.VarWithValue(start, end, "ltefield") Less Than or Equal To Another Relative Field @@ -832,12 +842,18 @@ Note: See Go's ParseMAC for accepted formats and types: http://golang.org/src/net/mac.go?s=866:918#L29 -Hostname +Hostname RFC 952 -This validates that a string value is a valid Hostname +This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 Usage: hostname +Hostname RFC 1123 + +This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 + + Usage: hostname_rfc1123 or if you want to continue to use 'hostname' in your tags, create an alias. + Full Qualified Domain Name (FQDN) This validates that a string value contains a valid FQDN. diff --git a/vendor/gopkg.in/go-playground/validator.v9/regexes.go b/vendor/gopkg.in/go-playground/validator.v9/regexes.go index ec78ceb..78f3ea0 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/regexes.go +++ b/vendor/gopkg.in/go-playground/validator.v9/regexes.go @@ -30,7 +30,8 @@ const ( latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" sSNRegexString = `^\d{3}[- ]?\d{2}[- ]?\d{4}$` - hostnameRegexString = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-z-Az0-9]$` + hostnameRegexStringRFC952 = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-z-Az0-9]$` // https://tools.ietf.org/html/rfc952 + hostnameRegexStringRFC1123 = `^[a-zA-Z0-9][a-zA-Z0-9\-\.]+[a-z-Az0-9]$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123 ) var ( @@ -61,5 +62,6 @@ var ( latitudeRegex = regexp.MustCompile(latitudeRegexString) longitudeRegex = regexp.MustCompile(longitudeRegexString) sSNRegex = regexp.MustCompile(sSNRegexString) - hostnameRegex = regexp.MustCompile(hostnameRegexString) + hostnameRegexRFC952 = regexp.MustCompile(hostnameRegexStringRFC952) + hostnameRegexRFC1123 = regexp.MustCompile(hostnameRegexStringRFC1123) ) diff --git a/vendor/gopkg.in/go-playground/validator.v9/util.go b/vendor/gopkg.in/go-playground/validator.v9/util.go index a01d4b1..16a5517 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/util.go +++ b/vendor/gopkg.in/go-playground/validator.v9/util.go @@ -80,7 +80,7 @@ BEGIN: typ := current.Type() fld := namespace - ns := namespace + var ns string if typ != timeType { diff --git a/vendor/gopkg.in/go-playground/validator.v9/validator.go b/vendor/gopkg.in/go-playground/validator.v9/validator.go index f180a9c..483e0a2 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/validator.go +++ b/vendor/gopkg.in/go-playground/validator.v9/validator.go @@ -14,24 +14,19 @@ type validate struct { ns []byte actualNs []byte errs ValidationErrors + includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise + ffn FilterFunc + slflParent reflect.Value // StructLevel & FieldLevel + slCurrent reflect.Value // StructLevel & FieldLevel + flField reflect.Value // StructLevel & FieldLevel + cf *cField // StructLevel & FieldLevel + ct *cTag // StructLevel & FieldLevel + misc []byte // misc reusable + str1 string // misc reusable + str2 string // misc reusable + fldIsPointer bool // StructLevel & FieldLevel isPartial bool hasExcludes bool - includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise - - ffn FilterFunc - - // StructLevel & FieldLevel fields - slflParent reflect.Value - slCurrent reflect.Value - flField reflect.Value - fldIsPointer bool - cf *cField - ct *cTag - - // misc reusable values - misc []byte - str1 string - str2 string } // parent and current will be the same the first run of validateStruct @@ -127,7 +122,6 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr } if kind == reflect.Invalid { - v.errs = append(v.errs, &fieldError{ v: v.v, @@ -378,14 +372,13 @@ OUTER: v.misc = append(v.misc, '|') v.misc = append(v.misc, ct.tag...) - if len(ct.param) > 0 { + if ct.hasParam { v.misc = append(v.misc, '=') v.misc = append(v.misc, ct.param...) } - if ct.next == nil || ct.next.typeof != typeOr { // ct.typeof != typeOr + if ct.isBlockEnd || ct.next == nil { // if we get here, no valid 'or' value and no more tags - v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { @@ -474,9 +467,7 @@ OUTER: ) return - } - ct = ct.next } } diff --git a/vendor/gopkg.in/go-playground/validator.v9/validator_instance.go b/vendor/gopkg.in/go-playground/validator.v9/validator_instance.go index d3a1543..e84b452 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/validator_instance.go +++ b/vendor/gopkg.in/go-playground/validator.v9/validator_instance.go @@ -370,39 +370,37 @@ func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}, fields . typ := val.Type() name := typ.Name() - if fields != nil { - for _, k := range fields { + for _, k := range fields { - flds := strings.Split(k, namespaceSeparator) - if len(flds) > 0 { + flds := strings.Split(k, namespaceSeparator) + if len(flds) > 0 { - vd.misc = append(vd.misc[0:0], name...) - vd.misc = append(vd.misc, '.') - - for _, s := range flds { + vd.misc = append(vd.misc[0:0], name...) + vd.misc = append(vd.misc, '.') - idx := strings.Index(s, leftBracket) + for _, s := range flds { - if idx != -1 { - for idx != -1 { - vd.misc = append(vd.misc, s[:idx]...) - vd.includeExclude[string(vd.misc)] = struct{}{} + idx := strings.Index(s, leftBracket) - idx2 := strings.Index(s, rightBracket) - idx2++ - vd.misc = append(vd.misc, s[idx:idx2]...) - vd.includeExclude[string(vd.misc)] = struct{}{} - s = s[idx2:] - idx = strings.Index(s, leftBracket) - } - } else { + if idx != -1 { + for idx != -1 { + vd.misc = append(vd.misc, s[:idx]...) + vd.includeExclude[string(vd.misc)] = struct{}{} - vd.misc = append(vd.misc, s...) + idx2 := strings.Index(s, rightBracket) + idx2++ + vd.misc = append(vd.misc, s[idx:idx2]...) vd.includeExclude[string(vd.misc)] = struct{}{} + s = s[idx2:] + idx = strings.Index(s, leftBracket) } + } else { - vd.misc = append(vd.misc, '.') + vd.misc = append(vd.misc, s...) + vd.includeExclude[string(vd.misc)] = struct{}{} } + + vd.misc = append(vd.misc, '.') } } } @@ -520,36 +518,18 @@ func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (e return nil } - // find cached tag - ctag, ok := v.tagCache.Get(tag) - if !ok { - v.tagCache.lock.Lock() - defer v.tagCache.lock.Unlock() - - // could have been multiple trying to access, but once first is done this ensures tag - // isn't parsed again. - ctag, ok = v.tagCache.Get(tag) - if !ok { - ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) - v.tagCache.Set(tag, ctag) - } - } - + ctag := v.fetchCacheTag(tag) val := reflect.ValueOf(field) - vd := v.pool.Get().(*validate) vd.top = val vd.isPartial = false - vd.traverseField(ctx, val, val, vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } - v.pool.Put(vd) - return } @@ -590,36 +570,17 @@ func (v *Validate) VarWithValueCtx(ctx context.Context, field interface{}, other if len(tag) == 0 || tag == skipValidationTag { return nil } - - // find cached tag - ctag, ok := v.tagCache.Get(tag) - if !ok { - v.tagCache.lock.Lock() - defer v.tagCache.lock.Unlock() - - // could have been multiple trying to access, but once first is done this ensures tag - // isn't parsed again. - ctag, ok = v.tagCache.Get(tag) - if !ok { - ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false) - v.tagCache.Set(tag, ctag) - } - } - + ctag := v.fetchCacheTag(tag) otherVal := reflect.ValueOf(other) - vd := v.pool.Get().(*validate) vd.top = otherVal vd.isPartial = false - vd.traverseField(ctx, otherVal, reflect.ValueOf(field), vd.ns[0:0], vd.actualNs[0:0], defaultCField, ctag) if len(vd.errs) > 0 { err = vd.errs vd.errs = nil } - v.pool.Put(vd) - return } diff --git a/vendor/gopkg.in/go-playground/validator.v9/validator_test.go b/vendor/gopkg.in/go-playground/validator.v9/validator_test.go index 7d085e8..9600d0f 100644 --- a/vendor/gopkg.in/go-playground/validator.v9/validator_test.go +++ b/vendor/gopkg.in/go-playground/validator.v9/validator_test.go @@ -1564,10 +1564,6 @@ func TestCrossNamespaceFieldValidation(t *testing.T) { Name string } - type MapStruct struct { - Name string - } - type Inner struct { CreatedAt *time.Time Slice []string @@ -1653,10 +1649,10 @@ func TestCrossNamespaceFieldValidation(t *testing.T) { Equal(t, kind, reflect.String) Equal(t, current.String(), "val2") - current, kind, ok = v.getStructFieldOKInternal(val, "Inner.CrazyNonExistantField") + current, _, ok = v.getStructFieldOKInternal(val, "Inner.CrazyNonExistantField") Equal(t, ok, false) - current, kind, ok = v.getStructFieldOKInternal(val, "Inner.Slice[101]") + current, _, ok = v.getStructFieldOKInternal(val, "Inner.Slice[101]") Equal(t, ok, false) current, kind, ok = v.getStructFieldOKInternal(val, "Inner.Map[key3]") @@ -1854,8 +1850,6 @@ func TestSQLValue2Validation(t *testing.T) { PanicMatches(t, func() { validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error") - type myValuer valuer - myVal := valuer{ Name: "", } @@ -1907,8 +1901,6 @@ func TestSQLValueValidation(t *testing.T) { PanicMatches(t, func() { errs = validate.Var(val, "required") }, "SQL Driver Valuer error: some kind of error") - type myValuer valuer - myVal := valuer{ Name: "", } @@ -2696,11 +2688,8 @@ func TestBadKeyValidation(t *testing.T) { func TestInterfaceErrValidation(t *testing.T) { - var v1 interface{} - var v2 interface{} - - v2 = 1 - v1 = v2 + var v2 interface{} = 1 + var v1 interface{} = v2 validate := New() errs := validate.Var(v1, "len=1") @@ -4325,6 +4314,66 @@ func TestIsEqValidation(t *testing.T) { PanicMatches(t, func() { validate.Var(now, "eq=now") }, "Bad field type time.Time") } +func TestOneOfValidation(t *testing.T) { + validate := New() + + passSpecs := []struct { + f interface{} + t string + }{ + {f: "red", t: "oneof=red green"}, + {f: "green", t: "oneof=red green"}, + {f: 5, t: "oneof=5 6"}, + {f: 6, t: "oneof=5 6"}, + {f: int8(6), t: "oneof=5 6"}, + {f: int16(6), t: "oneof=5 6"}, + {f: int32(6), t: "oneof=5 6"}, + {f: int64(6), t: "oneof=5 6"}, + {f: uint(6), t: "oneof=5 6"}, + {f: uint8(6), t: "oneof=5 6"}, + {f: uint16(6), t: "oneof=5 6"}, + {f: uint32(6), t: "oneof=5 6"}, + {f: uint64(6), t: "oneof=5 6"}, + } + + for _, spec := range passSpecs { + t.Logf("%#v", spec) + errs := validate.Var(spec.f, spec.t) + Equal(t, errs, nil) + } + + failSpecs := []struct { + f interface{} + t string + }{ + {f: "", t: "oneof=red green"}, + {f: "yellow", t: "oneof=red green"}, + {f: 5, t: "oneof=red green"}, + {f: 6, t: "oneof=red green"}, + {f: 6, t: "oneof=7"}, + {f: uint(6), t: "oneof=7"}, + {f: int8(5), t: "oneof=red green"}, + {f: int16(5), t: "oneof=red green"}, + {f: int32(5), t: "oneof=red green"}, + {f: int64(5), t: "oneof=red green"}, + {f: uint(5), t: "oneof=red green"}, + {f: uint8(5), t: "oneof=red green"}, + {f: uint16(5), t: "oneof=red green"}, + {f: uint32(5), t: "oneof=red green"}, + {f: uint64(5), t: "oneof=red green"}, + } + + for _, spec := range failSpecs { + t.Logf("%#v", spec) + errs := validate.Var(spec.f, spec.t) + AssertError(t, errs, "", "", "", "", "oneof") + } + + PanicMatches(t, func() { + validate.Var(3.14, "oneof=red green") + }, "Bad field type float64") +} + func TestBase64Validation(t *testing.T) { validate := New() @@ -5585,6 +5634,13 @@ func TestOrTag(t *testing.T) { errs = validate.Var(s, "omitempty,rgb|rgba") Equal(t, errs, nil) + s = "green" + errs = validate.Var(s, "eq=|eq=blue,rgb|rgba") //should fail on first validation block + NotEqual(t, errs, nil) + ve := errs.(ValidationErrors) + Equal(t, len(ve), 1) + Equal(t, ve[0].Tag(), "eq=|eq=blue") + s = "this is right, but a blank or isn't" PanicMatches(t, func() { validate.Var(s, "rgb||len=13") }, "Invalid validation tag on field ''") @@ -7139,7 +7195,7 @@ func TestValidateStructRegisterCtx(t *testing.T) { Equal(t, ctxSlVal, "slVal") } -func TestHostnameValidation(t *testing.T) { +func TestHostnameRFC952Validation(t *testing.T) { tests := []struct { param string expected bool @@ -7150,6 +7206,7 @@ func TestHostnameValidation(t *testing.T) { {"test.example24.com", true}, {"test24.example24.com", true}, {"example", true}, + {"1.foo.com", false}, {"test.example.com.", false}, {"example.com.", false}, {"example24.com.", false}, @@ -7171,15 +7228,112 @@ func TestHostnameValidation(t *testing.T) { if test.expected { if !IsEqual(errs, nil) { - t.Fatalf("Index: %d hostname failed Error: %s", i, errs) + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "hostname" { + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) + } + } + } + } +} + +func TestHostnameRFC1123Validation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"test.example.com", true}, + {"example.com", true}, + {"example24.com", true}, + {"test.example24.com", true}, + {"test24.example24.com", true}, + {"example", true}, + {"1.foo.com", true}, + {"test.example.com.", false}, + {"example.com.", false}, + {"example24.com.", false}, + {"test.example24.com.", false}, + {"test24.example24.com.", false}, + {"example.", false}, + {"192.168.0.1", true}, + {"email@example.com", false}, + {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, + {"2001:cdba:0:0:0:0:3257:9652", false}, + {"2001:cdba::3257:9652", false}, + } + + validate := New() + + for i, test := range tests { + + errs := validate.Var(test.param, "hostname_rfc1123") + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "hostname_rfc1123" { + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) + } + } + } + } +} + +func TestHostnameRFC1123AliasValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"test.example.com", true}, + {"example.com", true}, + {"example24.com", true}, + {"test.example24.com", true}, + {"test24.example24.com", true}, + {"example", true}, + {"1.foo.com", true}, + {"test.example.com.", false}, + {"example.com.", false}, + {"example24.com.", false}, + {"test.example24.com.", false}, + {"test24.example24.com.", false}, + {"example.", false}, + {"192.168.0.1", true}, + {"email@example.com", false}, + {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, + {"2001:cdba:0:0:0:0:3257:9652", false}, + {"2001:cdba::3257:9652", false}, + } + + validate := New() + validate.RegisterAlias("hostname", "hostname_rfc1123") + + for i, test := range tests { + + errs := validate.Var(test.param, "hostname") + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { - t.Fatalf("Index: %d hostname failed Error: %s", i, errs) + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "hostname" { - t.Fatalf("Index: %d hostname failed Error: %s", i, errs) + t.Fatalf("Index: %d hostname failed Error: %v", i, errs) } } } @@ -7219,15 +7373,15 @@ func TestFQDNValidation(t *testing.T) { if test.expected { if !IsEqual(errs, nil) { - t.Fatalf("Index: %d fqdn failed Error: %s", i, errs) + t.Fatalf("Index: %d fqdn failed Error: %v", i, errs) } } else { if IsEqual(errs, nil) { - t.Fatalf("Index: %d fqdn failed Error: %s", i, errs) + t.Fatalf("Index: %d fqdn failed Error: %v", i, errs) } else { val := getError(errs, "", "") if val.Tag() != "fqdn" { - t.Fatalf("Index: %d fqdn failed Error: %s", i, errs) + t.Fatalf("Index: %d fqdn failed Error: %v", i, errs) } } } |