From e541eb6298700df919d57fe28e26b579089324a4 Mon Sep 17 00:00:00 2001 From: Boshi Lian Date: Mon, 19 Feb 2018 08:41:42 +0800 Subject: [PATCH] make upstream driver pluginable --- Gopkg.lock | 20 +- Gopkg.toml | 8 - sshpiperd/{ => auditor}/audit.go | 0 sshpiperd/challenger/challenger.go | 3 +- sshpiperd/challenger/pam_challenger.go | 2 +- sshpiperd/cmd.go | 99 ++ sshpiperd/config.go | 159 --- sshpiperd/log.go | 23 + sshpiperd/registry/plugin.go | 13 + sshpiperd/registry/registry.go | 46 + sshpiperd/sshpiperd.go | 76 +- sshpiperd/upstream/loader/load.go | 5 + sshpiperd/upstream/provider.go | 33 + sshpiperd/upstream/workingdir/config.go | 9 + sshpiperd/upstream/workingdir/plug.go | 37 + .../{ => upstream/workingdir}/workingdir.go | 2 +- .../workingdir}/workingdir_test.go | 2 +- sshpiperd/ver.go | 31 + vendor/github.com/glacjay/goini/.gitignore | 8 - vendor/github.com/glacjay/goini/LICENSE.txt | 21 - vendor/github.com/glacjay/goini/Makefile | 7 - vendor/github.com/glacjay/goini/README.md | 5 - vendor/github.com/glacjay/goini/empty.ini | 0 vendor/github.com/glacjay/goini/example.ini | 18 - vendor/github.com/glacjay/goini/ini.go | 267 ---- vendor/github.com/glacjay/goini/ini_test.go | 191 --- .../github.com/jessevdk/go-flags/.travis.yml | 38 + .../pflag => jessevdk/go-flags}/LICENSE | 16 +- vendor/github.com/jessevdk/go-flags/README.md | 135 ++ vendor/github.com/jessevdk/go-flags/arg.go | 27 + .../github.com/jessevdk/go-flags/arg_test.go | 163 +++ .../jessevdk/go-flags/assert_test.go | 177 +++ .../jessevdk/go-flags/check_crosscompile.sh | 16 + .../github.com/jessevdk/go-flags/closest.go | 59 + .../github.com/jessevdk/go-flags/command.go | 455 +++++++ .../jessevdk/go-flags/command_test.go | 582 +++++++++ .../jessevdk/go-flags/completion.go | 309 +++++ .../jessevdk/go-flags/completion_test.go | 315 +++++ .../github.com/jessevdk/go-flags/convert.go | 348 +++++ .../jessevdk/go-flags/convert_test.go | 159 +++ vendor/github.com/jessevdk/go-flags/error.go | 134 ++ .../jessevdk/go-flags/example_test.go | 110 ++ .../jessevdk/go-flags/examples/add.go | 23 + .../go-flags/examples/bash-completion | 9 + .../jessevdk/go-flags/examples/main.go | 79 ++ .../jessevdk/go-flags/examples/rm.go | 23 + vendor/github.com/jessevdk/go-flags/flags.go | 258 ++++ vendor/github.com/jessevdk/go-flags/group.go | 395 ++++++ .../jessevdk/go-flags/group_test.go | 255 ++++ vendor/github.com/jessevdk/go-flags/help.go | 491 +++++++ .../github.com/jessevdk/go-flags/help_test.go | 538 ++++++++ vendor/github.com/jessevdk/go-flags/ini.go | 597 +++++++++ .../github.com/jessevdk/go-flags/ini_test.go | 1053 +++++++++++++++ .../github.com/jessevdk/go-flags/long_test.go | 85 ++ vendor/github.com/jessevdk/go-flags/man.go | 205 +++ .../jessevdk/go-flags/marshal_test.go | 119 ++ .../github.com/jessevdk/go-flags/multitag.go | 140 ++ vendor/github.com/jessevdk/go-flags/option.go | 461 +++++++ .../jessevdk/go-flags/options_test.go | 45 + .../jessevdk/go-flags/optstyle_other.go | 67 + .../jessevdk/go-flags/optstyle_windows.go | 108 ++ vendor/github.com/jessevdk/go-flags/parser.go | 700 ++++++++++ .../jessevdk/go-flags/parser_test.go | 612 +++++++++ .../jessevdk/go-flags/pointer_test.go | 164 +++ .../jessevdk/go-flags/short_test.go | 234 ++++ .../github.com/jessevdk/go-flags/tag_test.go | 38 + .../github.com/jessevdk/go-flags/termsize.go | 28 + .../jessevdk/go-flags/termsize_linux.go | 7 + .../jessevdk/go-flags/termsize_nosysioctl.go | 7 + .../jessevdk/go-flags/termsize_other.go | 7 + .../jessevdk/go-flags/termsize_unix.go | 7 + .../jessevdk/go-flags/unknown_test.go | 66 + .../github.com/rakyll/globalconf/.travis.yml | 2 - vendor/github.com/rakyll/globalconf/README.md | 144 --- .../rakyll/globalconf/globalconf.go | 177 --- .../rakyll/globalconf/globalconf_test.go | 283 ----- .../rakyll/globalconf/testdata/custom.ini | 2 - .../rakyll/globalconf/testdata/global.ini | 3 - .../globalconf/testdata/globalandcustom.ini | 6 - vendor/github.com/spf13/pflag/.gitignore | 2 - vendor/github.com/spf13/pflag/.travis.yml | 21 - vendor/github.com/spf13/pflag/README.md | 296 ----- vendor/github.com/spf13/pflag/bool.go | 94 -- vendor/github.com/spf13/pflag/bool_slice.go | 147 --- .../github.com/spf13/pflag/bool_slice_test.go | 215 ---- vendor/github.com/spf13/pflag/bool_test.go | 179 --- vendor/github.com/spf13/pflag/count.go | 96 -- vendor/github.com/spf13/pflag/count_test.go | 52 - vendor/github.com/spf13/pflag/duration.go | 86 -- vendor/github.com/spf13/pflag/example_test.go | 36 - vendor/github.com/spf13/pflag/export_test.go | 29 - vendor/github.com/spf13/pflag/flag.go | 1128 ----------------- vendor/github.com/spf13/pflag/flag_test.go | 1085 ---------------- vendor/github.com/spf13/pflag/float32.go | 88 -- vendor/github.com/spf13/pflag/float64.go | 84 -- vendor/github.com/spf13/pflag/golangflag.go | 101 -- .../github.com/spf13/pflag/golangflag_test.go | 39 - vendor/github.com/spf13/pflag/int.go | 84 -- vendor/github.com/spf13/pflag/int32.go | 88 -- vendor/github.com/spf13/pflag/int64.go | 84 -- vendor/github.com/spf13/pflag/int8.go | 88 -- vendor/github.com/spf13/pflag/int_slice.go | 128 -- .../github.com/spf13/pflag/int_slice_test.go | 165 --- vendor/github.com/spf13/pflag/ip.go | 94 -- vendor/github.com/spf13/pflag/ip_slice.go | 148 --- .../github.com/spf13/pflag/ip_slice_test.go | 222 ---- vendor/github.com/spf13/pflag/ip_test.go | 63 - vendor/github.com/spf13/pflag/ipmask.go | 122 -- vendor/github.com/spf13/pflag/ipnet.go | 98 -- vendor/github.com/spf13/pflag/ipnet_test.go | 70 - vendor/github.com/spf13/pflag/string.go | 80 -- vendor/github.com/spf13/pflag/string_array.go | 103 -- .../spf13/pflag/string_array_test.go | 233 ---- vendor/github.com/spf13/pflag/string_slice.go | 129 -- .../spf13/pflag/string_slice_test.go | 253 ---- vendor/github.com/spf13/pflag/uint.go | 88 -- vendor/github.com/spf13/pflag/uint16.go | 88 -- vendor/github.com/spf13/pflag/uint32.go | 88 -- vendor/github.com/spf13/pflag/uint64.go | 88 -- vendor/github.com/spf13/pflag/uint8.go | 88 -- vendor/github.com/spf13/pflag/uint_slice.go | 126 -- .../github.com/spf13/pflag/uint_slice_test.go | 161 --- vendor/github.com/spf13/pflag/verify/all.sh | 69 - vendor/github.com/spf13/pflag/verify/gofmt.sh | 19 - .../github.com/spf13/pflag/verify/golint.sh | 15 - 125 files changed, 10196 insertions(+), 8230 deletions(-) rename sshpiperd/{ => auditor}/audit.go (100%) create mode 100644 sshpiperd/cmd.go delete mode 100644 sshpiperd/config.go create mode 100644 sshpiperd/log.go create mode 100644 sshpiperd/registry/plugin.go create mode 100644 sshpiperd/registry/registry.go create mode 100644 sshpiperd/upstream/loader/load.go create mode 100644 sshpiperd/upstream/provider.go create mode 100644 sshpiperd/upstream/workingdir/config.go create mode 100644 sshpiperd/upstream/workingdir/plug.go rename sshpiperd/{ => upstream/workingdir}/workingdir.go (99%) rename sshpiperd/{ => upstream/workingdir}/workingdir_test.go (99%) create mode 100644 sshpiperd/ver.go delete mode 100644 vendor/github.com/glacjay/goini/.gitignore delete mode 100644 vendor/github.com/glacjay/goini/LICENSE.txt delete mode 100644 vendor/github.com/glacjay/goini/Makefile delete mode 100644 vendor/github.com/glacjay/goini/README.md delete mode 100644 vendor/github.com/glacjay/goini/empty.ini delete mode 100644 vendor/github.com/glacjay/goini/example.ini delete mode 100644 vendor/github.com/glacjay/goini/ini.go delete mode 100644 vendor/github.com/glacjay/goini/ini_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/.travis.yml rename vendor/github.com/{spf13/pflag => jessevdk/go-flags}/LICENSE (70%) create mode 100644 vendor/github.com/jessevdk/go-flags/README.md create mode 100644 vendor/github.com/jessevdk/go-flags/arg.go create mode 100644 vendor/github.com/jessevdk/go-flags/arg_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/assert_test.go create mode 100755 vendor/github.com/jessevdk/go-flags/check_crosscompile.sh create mode 100644 vendor/github.com/jessevdk/go-flags/closest.go create mode 100644 vendor/github.com/jessevdk/go-flags/command.go create mode 100644 vendor/github.com/jessevdk/go-flags/command_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/completion.go create mode 100644 vendor/github.com/jessevdk/go-flags/completion_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/convert.go create mode 100644 vendor/github.com/jessevdk/go-flags/convert_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/error.go create mode 100644 vendor/github.com/jessevdk/go-flags/example_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/examples/add.go create mode 100644 vendor/github.com/jessevdk/go-flags/examples/bash-completion create mode 100644 vendor/github.com/jessevdk/go-flags/examples/main.go create mode 100644 vendor/github.com/jessevdk/go-flags/examples/rm.go create mode 100644 vendor/github.com/jessevdk/go-flags/flags.go create mode 100644 vendor/github.com/jessevdk/go-flags/group.go create mode 100644 vendor/github.com/jessevdk/go-flags/group_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/help.go create mode 100644 vendor/github.com/jessevdk/go-flags/help_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/ini.go create mode 100644 vendor/github.com/jessevdk/go-flags/ini_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/long_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/man.go create mode 100644 vendor/github.com/jessevdk/go-flags/marshal_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/multitag.go create mode 100644 vendor/github.com/jessevdk/go-flags/option.go create mode 100644 vendor/github.com/jessevdk/go-flags/options_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/optstyle_other.go create mode 100644 vendor/github.com/jessevdk/go-flags/optstyle_windows.go create mode 100644 vendor/github.com/jessevdk/go-flags/parser.go create mode 100644 vendor/github.com/jessevdk/go-flags/parser_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/pointer_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/short_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/tag_test.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_linux.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_other.go create mode 100644 vendor/github.com/jessevdk/go-flags/termsize_unix.go create mode 100644 vendor/github.com/jessevdk/go-flags/unknown_test.go delete mode 100644 vendor/github.com/rakyll/globalconf/.travis.yml delete mode 100644 vendor/github.com/rakyll/globalconf/README.md delete mode 100644 vendor/github.com/rakyll/globalconf/globalconf.go delete mode 100644 vendor/github.com/rakyll/globalconf/globalconf_test.go delete mode 100644 vendor/github.com/rakyll/globalconf/testdata/custom.ini delete mode 100644 vendor/github.com/rakyll/globalconf/testdata/global.ini delete mode 100644 vendor/github.com/rakyll/globalconf/testdata/globalandcustom.ini delete mode 100644 vendor/github.com/spf13/pflag/.gitignore delete mode 100644 vendor/github.com/spf13/pflag/.travis.yml delete mode 100644 vendor/github.com/spf13/pflag/README.md delete mode 100644 vendor/github.com/spf13/pflag/bool.go delete mode 100644 vendor/github.com/spf13/pflag/bool_slice.go delete mode 100644 vendor/github.com/spf13/pflag/bool_slice_test.go delete mode 100644 vendor/github.com/spf13/pflag/bool_test.go delete mode 100644 vendor/github.com/spf13/pflag/count.go delete mode 100644 vendor/github.com/spf13/pflag/count_test.go delete mode 100644 vendor/github.com/spf13/pflag/duration.go delete mode 100644 vendor/github.com/spf13/pflag/example_test.go delete mode 100644 vendor/github.com/spf13/pflag/export_test.go delete mode 100644 vendor/github.com/spf13/pflag/flag.go delete mode 100644 vendor/github.com/spf13/pflag/flag_test.go delete mode 100644 vendor/github.com/spf13/pflag/float32.go delete mode 100644 vendor/github.com/spf13/pflag/float64.go delete mode 100644 vendor/github.com/spf13/pflag/golangflag.go delete mode 100644 vendor/github.com/spf13/pflag/golangflag_test.go delete mode 100644 vendor/github.com/spf13/pflag/int.go delete mode 100644 vendor/github.com/spf13/pflag/int32.go delete mode 100644 vendor/github.com/spf13/pflag/int64.go delete mode 100644 vendor/github.com/spf13/pflag/int8.go delete mode 100644 vendor/github.com/spf13/pflag/int_slice.go delete mode 100644 vendor/github.com/spf13/pflag/int_slice_test.go delete mode 100644 vendor/github.com/spf13/pflag/ip.go delete mode 100644 vendor/github.com/spf13/pflag/ip_slice.go delete mode 100644 vendor/github.com/spf13/pflag/ip_slice_test.go delete mode 100644 vendor/github.com/spf13/pflag/ip_test.go delete mode 100644 vendor/github.com/spf13/pflag/ipmask.go delete mode 100644 vendor/github.com/spf13/pflag/ipnet.go delete mode 100644 vendor/github.com/spf13/pflag/ipnet_test.go delete mode 100644 vendor/github.com/spf13/pflag/string.go delete mode 100644 vendor/github.com/spf13/pflag/string_array.go delete mode 100644 vendor/github.com/spf13/pflag/string_array_test.go delete mode 100644 vendor/github.com/spf13/pflag/string_slice.go delete mode 100644 vendor/github.com/spf13/pflag/string_slice_test.go delete mode 100644 vendor/github.com/spf13/pflag/uint.go delete mode 100644 vendor/github.com/spf13/pflag/uint16.go delete mode 100644 vendor/github.com/spf13/pflag/uint32.go delete mode 100644 vendor/github.com/spf13/pflag/uint64.go delete mode 100644 vendor/github.com/spf13/pflag/uint8.go delete mode 100644 vendor/github.com/spf13/pflag/uint_slice.go delete mode 100644 vendor/github.com/spf13/pflag/uint_slice_test.go delete mode 100755 vendor/github.com/spf13/pflag/verify/all.sh delete mode 100755 vendor/github.com/spf13/pflag/verify/gofmt.sh delete mode 100755 vendor/github.com/spf13/pflag/verify/golint.sh diff --git a/Gopkg.lock b/Gopkg.lock index c30a68df..2db0dc62 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,22 +2,10 @@ [[projects]] - branch = "master" - name = "github.com/glacjay/goini" + name = "github.com/jessevdk/go-flags" packages = ["."] - revision = "fd3024d87ee21a36d3ccc4367f509fec89cd90ee" - -[[projects]] - branch = "master" - name = "github.com/rakyll/globalconf" - packages = ["."] - revision = "7afbf15d8da4ed30174874a9db565d16755e99f7" - -[[projects]] - branch = "master" - name = "github.com/spf13/pflag" - packages = ["."] - revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" + revision = "96dc06278ce32a0e9d957d590bb987c81ee66407" + version = "v1.3.0" [[projects]] branch = "master" @@ -43,6 +31,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "a45bf0b707bd655f13d5cd1ac7586dbc57f2eaee25ffc08bf9c3746189c686f3" + inputs-digest = "26b0711bf90deb21e94cf1291217773961e726ad2d2982d32cfb34b3ffbef73e" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 0a055d9f..b9c25eeb 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -21,14 +21,6 @@ # version = "2.4.0" -[[constraint]] - branch = "master" - name = "github.com/rakyll/globalconf" - -[[constraint]] - branch = "master" - name = "github.com/spf13/pflag" - [[constraint]] branch = "master" name = "github.com/vvanpo/golang-pam" diff --git a/sshpiperd/audit.go b/sshpiperd/auditor/audit.go similarity index 100% rename from sshpiperd/audit.go rename to sshpiperd/auditor/audit.go diff --git a/sshpiperd/challenger/challenger.go b/sshpiperd/challenger/challenger.go index a6a03de1..d4d43f8c 100644 --- a/sshpiperd/challenger/challenger.go +++ b/sshpiperd/challenger/challenger.go @@ -2,8 +2,9 @@ package challenger import ( "fmt" - "golang.org/x/crypto/ssh" "sort" + + "golang.org/x/crypto/ssh" ) type Challenger func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) diff --git a/sshpiperd/challenger/pam_challenger.go b/sshpiperd/challenger/pam_challenger.go index a6429259..7b5b5ef9 100644 --- a/sshpiperd/challenger/pam_challenger.go +++ b/sshpiperd/challenger/pam_challenger.go @@ -4,8 +4,8 @@ package challenger import ( "fmt" - "golang.org/x/crypto/ssh" pam "github.com/vvanpo/golang-pam" + "golang.org/x/crypto/ssh" "os" ) diff --git a/sshpiperd/cmd.go b/sshpiperd/cmd.go new file mode 100644 index 00000000..ce9aea10 --- /dev/null +++ b/sshpiperd/cmd.go @@ -0,0 +1,99 @@ +package main + +import ( + // "fmt" + "os" + + "github.com/jessevdk/go-flags" + + "github.com/tg123/sshpiper/sshpiperd/upstream" + _ "github.com/tg123/sshpiper/sshpiperd/upstream/loader" +) + +type subCommand struct{ callback func(args []string) error } + +func (s *subCommand) Execute(args []string) error { + return s.callback(args) +} + +func addSubCommand(parser *flags.Parser, name, desc string, callback func(args []string) error) { + _, err := parser.AddCommand(name, desc, "", &subCommand{callback}) + + if err != nil { + panic(err) + } +} + +func addOpt(parser *flags.Parser, name string, data interface{}) { + _, err := parser.AddGroup(name, "", data) + + if err != nil { + panic(err) + } +} + +func main() { + + parser := flags.NewNamedParser("sshpiperd", flags.Default) + parser.SubcommandsOptional = true + + // version + addSubCommand(parser, "version", "show version", func(args []string) error { + showVersion() + return nil + }) + + dumpConfig := func(){ + ini := flags.NewIniParser(parser) + ini.Write(os.Stdout, flags.IniIncludeDefaults) + } + + // dumpini + addSubCommand(parser, "dumpconfig", "dump current config ini to stdout", func(args []string) error { + return nil + }) + + config := &piperdConfig{} + addOpt(parser, "sshpiperd", config) + + // registry upstream + //upstreamOpt := make(map[string]interface{}) + for _, n := range upstream.All() { + + u := upstream.Get(n) + + opt := u.GetOpts() + + if opt == nil { + continue + } + + _, err := parser.AddGroup("upstream."+u.GetName(), "", opt) + + if err != nil { + panic(err) + } + + //upstreamOpt[u.GetName()] = opt + } + + if _, err := parser.Parse(); err != nil { + return + } + + // TODO + // load from ini + //ini := flags.NewIniParser(parser) + //err = ini.ParseFile(globalConfig.Config) + + //fmt.Println(err) + + // start to serve + if parser.Active == nil { + showVersion() + dumpConfig() + + startPiper(config) + } + +} diff --git a/sshpiperd/config.go b/sshpiperd/config.go deleted file mode 100644 index de6cd3b0..00000000 --- a/sshpiperd/config.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2014, 2015 tgic. All rights reserved. -// this file is governed by MIT-license -// -// https://github.com/tg123/sshpiper - -package main - -import ( - "flag" - "fmt" - "log" - "os" - "runtime" - "strings" - "text/template" - - "github.com/rakyll/globalconf" - "github.com/spf13/pflag" -) - -var version = "DEV" -var githash = "0000000000" - -var ( - config = struct { - ListenAddr string - Port uint - WorkingDir string - PiperKeyFile string - ShowHelp bool - Challenger string - Logfile string - ShowVersion bool - AllowBadUsername bool - NoCheckPerm bool - RecordTypescript bool - }{} - - out = os.Stdout - - configTemplate *template.Template - versionTemplate *template.Template -) - -func initTemplate() { - configTemplate = template.Must(template.New("config").Parse(` -Listening : {{.ListenAddr}}:{{.Port}} -Server Key File : {{.PiperKeyFile}} -Working Dir : {{.WorkingDir}} -Additional Challenger : {{.Challenger}} -Logging file : {{.Logfile}} - -`[1:])) - - versionTemplate = template.Must(template.New("ver").Parse(` -SSHPiper ver: {{.VER}} by Boshi Lian -https://github.com/tg123/sshpiper - -go runtime : {{.GOVER}} -git hash : {{.GITHASH}} - -`[1:])) -} - -func initLogger() { - // change this value for display might be not a good idea - if config.Logfile != "" { - f, err := os.OpenFile(config.Logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) - if err != nil { - logger.Printf("cannot open log file %v", err) - config.Logfile = fmt.Sprintf("stdout, fall back from %v", config.Logfile) - return - } - - logger = log.New(f, "", logger.Flags()) - } else { - config.Logfile = "stdout" - } -} - -func initConfig() { - configfile := pflag.String("config", "/etc/sshpiperd.conf", "Config file path. Note: any option will be overwrite if it is set by commandline") - - pflag.StringVarP(&config.ListenAddr, "listen_addr", "l", "0.0.0.0", "Listening Address") - pflag.UintVarP(&config.Port, "port", "p", 2222, "Listening Port") - pflag.StringVarP(&config.WorkingDir, "working_dir", "w", "/var/sshpiper", "Working Dir") - pflag.StringVarP(&config.PiperKeyFile, "server_key", "i", "/etc/ssh/ssh_host_rsa_key", "Key file for SSH Piper") - pflag.StringVarP(&config.Challenger, "challenger", "c", "", "Additional challenger name, e.g. pam, empty for no additional challenge") - - pflag.StringVar(&config.Logfile, "log", "", "Logfile path. Leave empty or any error occurs will fall back to stdout") - pflag.BoolVar(&config.AllowBadUsername, "allow_bad_username", false, "Disable username check while search the working dir") - pflag.BoolVar(&config.NoCheckPerm, "no_check_perm", false, "Disable 0400 checking when using files in the working dir") - pflag.BoolVar(&config.RecordTypescript, "record_typescript", false, "record screen output into the working dir with typescript format") - - pflag.BoolVarP(&config.ShowHelp, "help", "h", false, "Print help and exit") - pflag.BoolVar(&config.ShowVersion, "version", false, "Print version and exit") - - pflag.Parse() - - if _, err := os.Stat(*configfile); os.IsNotExist(err) { - if !pflag.Lookup("config").Changed { - *configfile = "" - } else { - logger.Fatalf("config file %v not found", *configfile) - } - } - - gconf, err := globalconf.NewWithOptions(&globalconf.Options{ - Filename: *configfile, - EnvPrefix: "SSHPIPERD_", - }) - - if err != nil { // this error will happen only if file error - logger.Fatalln("load config file error %v: %v", *configfile, err) - } - - // build a dummy flag set for globalconf to parse - fs := flag.NewFlagSet("", flag.ContinueOnError) - - ignoreSet := make(map[string]bool) - pflag.Visit(func(f *pflag.Flag) { - ignoreSet[f.Name] = true - }) - - // should be ignored - ignoreSet["help"] = true - ignoreSet["version"] = true - - pflag.VisitAll(func(f *pflag.Flag) { - - n := f.Name - if !ignoreSet[n] { - n = strings.TrimPrefix(n, "-") - fs.Var(f.Value, n, f.Usage) - } - }) - - gconf.ParseSet("", fs) -} - -func showHelp() { - pflag.Usage() -} - -func showVersion() { - versionTemplate.Execute(out, struct { - VER string - GOVER string - GITHASH string - }{ - VER: version, - GITHASH: githash, - GOVER: runtime.Version(), - }) -} - -func showConfig() { - configTemplate.Execute(out, config) -} diff --git a/sshpiperd/log.go b/sshpiperd/log.go new file mode 100644 index 00000000..2fdde3b0 --- /dev/null +++ b/sshpiperd/log.go @@ -0,0 +1,23 @@ +package main + +import ( + "log" + "os" +) + +var ( + logger = log.New(os.Stdout, "", log.Ldate|log.Ltime) +) + +func initLogger(file string) { + // change this value for display might be not a good idea + if file != "" { + f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + logger.Printf("cannot open log file %v", err) + return + } + + logger = log.New(f, "", logger.Flags()) + } +} diff --git a/sshpiperd/registry/plugin.go b/sshpiperd/registry/plugin.go new file mode 100644 index 00000000..61278e2f --- /dev/null +++ b/sshpiperd/registry/plugin.go @@ -0,0 +1,13 @@ +package registry + +import ( + "log" +) + +type Plugin interface { + GetName() string + + GetOpts() interface{} + + Init(logger *log.Logger) error +} diff --git a/sshpiperd/registry/registry.go b/sshpiperd/registry/registry.go new file mode 100644 index 00000000..a46d1267 --- /dev/null +++ b/sshpiperd/registry/registry.go @@ -0,0 +1,46 @@ +package registry + +import ( + "sort" + "sync" +) + +type Registry struct { + driversMu sync.RWMutex + drivers map[string]interface{} +} + +func NewRegistry() *Registry { + return &Registry{drivers: make(map[string]interface{})} +} + +// copy from database/sql +func (r *Registry) Register(name string, driver interface{}) { + r.driversMu.Lock() + defer r.driversMu.Unlock() + if driver == nil { + panic("Register driver is nil") + } + if _, dup := r.drivers[name]; dup { + panic("Register called twice for driver " + name) + } + r.drivers[name] = driver +} + +func (r *Registry) Drivers() []string { + r.driversMu.RLock() + defer r.driversMu.RUnlock() + var list []string + for name := range r.drivers { + list = append(list, name) + } + sort.Strings(list) + return list +} + +func (r *Registry) Get(name string) interface{} { + r.driversMu.RLock() + defer r.driversMu.RUnlock() + + return r.drivers[name] +} diff --git a/sshpiperd/sshpiperd.go b/sshpiperd/sshpiperd.go index 0f1825c8..7e052a7d 100644 --- a/sshpiperd/sshpiperd.go +++ b/sshpiperd/sshpiperd.go @@ -1,58 +1,54 @@ -// Copyright 2014, 2015 tgic. All rights reserved. -// this file is governed by MIT-license -// -// https://github.com/tg123/sshpiper - package main import ( "fmt" "io/ioutil" - "log" "net" - "os" + + "golang.org/x/crypto/ssh" "github.com/tg123/sshpiper/sshpiperd/challenger" - "golang.org/x/crypto/ssh" + "github.com/tg123/sshpiper/sshpiperd/upstream" ) -var ( - logger = log.New(os.Stdout, "", log.Ldate|log.Ltime) -) +type piperdConfig struct { + Config string `long:"config" description:"Config file path. Higher priority than arg options and environment variables" default:"/etc/sshpiperd.ini" no-ini:"true"` -func showHelpOrVersion() { - if config.ShowHelp { - showHelp() - os.Exit(0) - } + ListenAddr string `short:"l" long:"listen" description:"Listening Address" default:"0.0.0.0" env:"SSHPIPERD_LISTENADDR" ini-name:"listen-address"` + Port uint `short:"p" long:"port" description:"Listening Port" default:"2222" env:"SSHPIPERD_PORT" ini-name:"listen-port"` + PiperKeyFile string `short:"i" long:"server-key" description:"Server key file for SSH Piper" default:"/etc/ssh/ssh_host_rsa_key" env:"SSHPIPERD_SERVER_KEY" ini-name:"server-key"` + Logfile string `long:"log" description:"Logfile path. Leave empty or any error occurs will fall back to stdout" env:"SSHPIPERD_LOG_PATH" ini-name:"log-path"` - if config.ShowVersion { - os.Exit(0) - } + UpstreamDriver string `short:"d" long:"upstream-driver" description:"Upstream provider driver" default:"workingdir" env:"SSHPIPERD_UPSTREAM_DRIVER"` + ChallengerDriver string `short:"c" long:"challenger-driver" description:"Additional challenger name, e.g. pam, empty for no additional challenge" env:"SSHPIPERD_CHALLENGER"` } -func main() { - initConfig() - initTemplate() - initLogger() +func startPiper(config *piperdConfig) { - showVersion() - showHelpOrVersion() + // init log + initLogger(config.Logfile) - showConfig() + logger.Println("sshpiper is about to start") + + // init upstream + upstream := upstream.Get(config.UpstreamDriver) + if upstream == nil { + logger.Fatal("upstream driver %v not found", config.UpstreamDriver) + } + upstream.Init(logger) - // TODO make this pluggable piper := &ssh.SSHPiperConfig{ - FindUpstream: findUpstreamFromUserfile, + FindUpstream: upstream.GetFindUpstreamHandle(), } - if config.Challenger != "" { - ac, err := challenger.GetChallenger(config.Challenger) + // TODO move to plugin + if config.ChallengerDriver != "" { + ac, err := challenger.GetChallenger(config.ChallengerDriver) if err != nil { logger.Fatalln("failed to load challenger", err) } - logger.Printf("using additional challenger %s", config.Challenger) + logger.Printf("using additional challenger %s", config.ChallengerDriver) piper.AdditionalChallenge = ac } @@ -92,18 +88,18 @@ func main() { return } - if config.RecordTypescript { - auditor, err := newFilePtyLogger(p.DownstreamConnMeta().User()) + //if config.RecordTypescript { + // auditor, err := newFilePtyLogger(p.DownstreamConnMeta().User()) - if err != nil { - logger.Printf("connection from %v failed to create auditor reason: %v", c.RemoteAddr(), err) - return - } + // if err != nil { + // logger.Printf("connection from %v failed to create auditor reason: %v", c.RemoteAddr(), err) + // return + // } - defer auditor.Close() + // defer auditor.Close() - p.HookUpstreamMsg = auditor.loggingTty - } + // p.HookUpstreamMsg = auditor.loggingTty + //} err = p.Wait() logger.Printf("connection from %v closed reason: %v", c.RemoteAddr(), err) diff --git a/sshpiperd/upstream/loader/load.go b/sshpiperd/upstream/loader/load.go new file mode 100644 index 00000000..d27a742d --- /dev/null +++ b/sshpiperd/upstream/loader/load.go @@ -0,0 +1,5 @@ +package loader + +import ( + _ "github.com/tg123/sshpiper/sshpiperd/upstream/workingdir" +) diff --git a/sshpiperd/upstream/provider.go b/sshpiperd/upstream/provider.go new file mode 100644 index 00000000..4e0c9ac1 --- /dev/null +++ b/sshpiperd/upstream/provider.go @@ -0,0 +1,33 @@ +package upstream + +import ( + "net" + + "golang.org/x/crypto/ssh" + + "github.com/tg123/sshpiper/sshpiperd/registry" +) + +type UpstreamHandler func(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error) + +type UpstreamProvider interface { + registry.Plugin + + GetFindUpstreamHandle() UpstreamHandler +} + +var ( + drivers = registry.NewRegistry() +) + +func Register(name string, driver UpstreamProvider) { + drivers.Register(name, driver) +} + +func All() []string { + return drivers.Drivers() +} + +func Get(name string) UpstreamProvider { + return drivers.Get(name).(UpstreamProvider) +} diff --git a/sshpiperd/upstream/workingdir/config.go b/sshpiperd/upstream/workingdir/config.go new file mode 100644 index 00000000..0aa9bc8e --- /dev/null +++ b/sshpiperd/upstream/workingdir/config.go @@ -0,0 +1,9 @@ +package workingdir + +var ( + config = struct { + WorkingDir string `long:"workingdir" default:"/var/sshpiper" description:"Path to workingdir" env:"SSHPIPERD_WORKINGDIR" ini-name:"workingdir"` + AllowBadUsername bool `long:"workingdir-allowbadusername" description:"Disable username check while search the working dir" env:"SSHPIPERD_WORKINGDIR_ALLOWBADUSERNAME" ini-name:"workingdir-allowbadusername"` + NoCheckPerm bool `long:"workingdir-nocheckperm" description:"Disable 0400 checking when using files in the working dir" env:"SSHPIPERD_WORKINGDIR_NOCHECKPERM" ini-name:"workingdir-nocheckperm"` + }{} +) diff --git a/sshpiperd/upstream/workingdir/plug.go b/sshpiperd/upstream/workingdir/plug.go new file mode 100644 index 00000000..6ab114e7 --- /dev/null +++ b/sshpiperd/upstream/workingdir/plug.go @@ -0,0 +1,37 @@ +package workingdir + +import ( + "log" + + "github.com/tg123/sshpiper/sshpiperd/upstream" +) + +var logger *log.Logger + +type plugin struct { +} + +func (p *plugin) GetName() string { + return "workingdir" +} + +func (p *plugin) GetOpts() interface{} { + return &config +} + +func (p *plugin) GetFindUpstreamHandle() upstream.UpstreamHandler { + return findUpstreamFromUserfile +} + +func (p *plugin) Init(glogger *log.Logger) error { + + logger = glogger + + logger.Printf("upstream provider: workingdir %v init", config.WorkingDir) + + return nil +} + +func init() { + upstream.Register("workingdir", &plugin{}) +} diff --git a/sshpiperd/workingdir.go b/sshpiperd/upstream/workingdir/workingdir.go similarity index 99% rename from sshpiperd/workingdir.go rename to sshpiperd/upstream/workingdir/workingdir.go index 26cf95e7..e2ee3b0e 100644 --- a/sshpiperd/workingdir.go +++ b/sshpiperd/upstream/workingdir/workingdir.go @@ -3,7 +3,7 @@ // // https://github.com/tg123/sshpiper -package main +package workingdir import ( "bufio" diff --git a/sshpiperd/workingdir_test.go b/sshpiperd/upstream/workingdir/workingdir_test.go similarity index 99% rename from sshpiperd/workingdir_test.go rename to sshpiperd/upstream/workingdir/workingdir_test.go index edd228f4..63e8991f 100644 --- a/sshpiperd/workingdir_test.go +++ b/sshpiperd/upstream/workingdir/workingdir_test.go @@ -3,7 +3,7 @@ // // https://github.com/tg123/sshpiper -package main +package workingdir import ( "bytes" diff --git a/sshpiperd/ver.go b/sshpiperd/ver.go new file mode 100644 index 00000000..3bda07b9 --- /dev/null +++ b/sshpiperd/ver.go @@ -0,0 +1,31 @@ +package main + +import ( + "os" + "runtime" + "text/template" +) + +var version = "DEV" +var githash = "0000000000" + +func showVersion() { + versionTemplate := template.Must(template.New("ver").Parse(` +SSHPiper ver: {{.VER}} by Boshi Lian +https://github.com/tg123/sshpiper + +go runtime : {{.GOVER}} +git hash : {{.GITHASH}} + +`[1:])) + + versionTemplate.Execute(os.Stdout, struct { + VER string + GOVER string + GITHASH string + }{ + VER: version, + GITHASH: githash, + GOVER: runtime.Version(), + }) +} diff --git a/vendor/github.com/glacjay/goini/.gitignore b/vendor/github.com/glacjay/goini/.gitignore deleted file mode 100644 index 6facd5a7..00000000 --- a/vendor/github.com/glacjay/goini/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.*.swp - -*.[689] -[689].out - -_obj -_test -_testmain.go diff --git a/vendor/github.com/glacjay/goini/LICENSE.txt b/vendor/github.com/glacjay/goini/LICENSE.txt deleted file mode 100644 index 38c6bf23..00000000 --- a/vendor/github.com/glacjay/goini/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) [year] [fullname] - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/glacjay/goini/Makefile b/vendor/github.com/glacjay/goini/Makefile deleted file mode 100644 index bc67d570..00000000 --- a/vendor/github.com/glacjay/goini/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -test: - go test - -format: - gofmt -w *.go - -.PHONY: format test diff --git a/vendor/github.com/glacjay/goini/README.md b/vendor/github.com/glacjay/goini/README.md deleted file mode 100644 index 43bbd069..00000000 --- a/vendor/github.com/glacjay/goini/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# goini -INI file parser in go. - -# See Also -For real apps, you can use [TOML](https://github.com/BurntSushi/toml) instead, which is a better INI format :-) diff --git a/vendor/github.com/glacjay/goini/empty.ini b/vendor/github.com/glacjay/goini/empty.ini deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/github.com/glacjay/goini/example.ini b/vendor/github.com/glacjay/goini/example.ini deleted file mode 100644 index 1a21f8e3..00000000 --- a/vendor/github.com/glacjay/goini/example.ini +++ /dev/null @@ -1,18 +0,0 @@ -# -# This is an example of ini file -# - -[Pizza] - -Ham = yes; -Mushrooms = TRUE; -Capres = 0; -Cheese = Non; - - -[Wine] - -Grape = Cabernet Sauvignon; -Year = 1989; -Country = Spain; -Alcohol = 12.5; diff --git a/vendor/github.com/glacjay/goini/ini.go b/vendor/github.com/glacjay/goini/ini.go deleted file mode 100644 index 9b5feeff..00000000 --- a/vendor/github.com/glacjay/goini/ini.go +++ /dev/null @@ -1,267 +0,0 @@ -package ini - -import ( - "bufio" - "bytes" - "fmt" - "io/ioutil" - "os" - "regexp" - "strconv" - "strings" - "unicode" -) - -type Dict map[string]map[string]string - -type Error string - -var ( - regDoubleQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*\"([^\"]*)\"$") - regSingleQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*'([^']*)'$") - regNoQuote = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*([^#;]+)") - regNoValue = regexp.MustCompile("^([^= \t]+)[ \t]*=[ \t]*([#;].*)?") -) - -func MustLoadReader(reader *bufio.Reader) Dict { - dict, err := LoadReader(reader) - if err != nil { - panic(err) - } - return dict -} - -func MustLoad(filename string) Dict { - dict, err := Load(filename) - if err != nil { - panic(err) - } - return dict -} - -func LoadReader(reader *bufio.Reader) (dict Dict, err error) { - dict = make(map[string]map[string]string) - lineno := 0 - section := "" - dict[section] = make(map[string]string) - - for err == nil { - l, _, err := reader.ReadLine() - if err != nil { - break - } - lineno++ - - line := strings.TrimFunc(string(l), unicode.IsSpace) - if len(line) == 0 { - continue - } - - for line[len(line)-1] == '\\' { - line = line[:len(line)-1] - l, _, err := reader.ReadLine() - if err != nil { - return nil, err - } - line += strings.TrimFunc(string(l), unicode.IsSpace) - } - - section, err = dict.parseLine(section, line) - if err != nil { - return nil, newError( - err.Error() + fmt.Sprintf("':%d'.", lineno)) - } - } - - return -} - -func Load(filename string) (Dict, error) { - file, err := os.Open(filename) - if err != nil { - return nil, err - } - defer file.Close() - - reader := bufio.NewReader(file) - return LoadReader(reader) -} - -func Write(filename string, dict *Dict) error { - buffer := dict.format() - return ioutil.WriteFile(filename, buffer.Bytes(), 0644) -} - -func (e Error) Error() string { - return string(e) -} -func (dict Dict) parseLine(section, line string) (string, error) { - // commets - if line[0] == '#' || line[0] == ';' { - return section, nil - } - - // section name - if line[0] == '[' && line[len(line)-1] == ']' { - section := strings.TrimFunc(line[1:len(line)-1], unicode.IsSpace) - section = strings.ToLower(section) - dict[section] = make(map[string]string) - return section, nil - } - - // key = value - if m := regDoubleQuote.FindAllStringSubmatch(line, 1); m != nil { - dict.add(section, m[0][1], m[0][2]) - return section, nil - } else if m = regSingleQuote.FindAllStringSubmatch(line, 1); m != nil { - dict.add(section, m[0][1], m[0][2]) - return section, nil - } else if m = regNoQuote.FindAllStringSubmatch(line, 1); m != nil { - dict.add(section, m[0][1], strings.TrimFunc(m[0][2], unicode.IsSpace)) - return section, nil - } else if m = regNoValue.FindAllStringSubmatch(line, 1); m != nil { - dict.add(section, m[0][1], "") - return section, nil - } - - return section, newError("iniparser: syntax error at ") -} - -func (dict Dict) add(section, key, value string) { - key = strings.ToLower(key) - dict[section][key] = value -} - -func (dict Dict) GetBool(section, key string) (bool, bool) { - sec, ok := dict[section] - if !ok { - return false, false - } - value, ok := sec[key] - if !ok { - return false, false - } - v := value[0] - if v == 'y' || v == 'Y' || v == '1' || v == 't' || v == 'T' { - return true, true - } - if v == 'n' || v == 'N' || v == '0' || v == 'f' || v == 'F' { - return false, true - } - return false, false -} - -func (dict Dict) SetBool(section, key string, value bool) { - dict.SetString(section, key, strconv.FormatBool(value)) -} - -func (dict Dict) GetString(section, key string) (string, bool) { - sec, ok := dict[section] - if !ok { - return "", false - } - value, ok := sec[key] - if !ok { - return "", false - } - return value, true -} - -func (dict Dict) SetString(section, key, value string) { - _, ok := dict[section] - if !ok { - dict[section] = make(map[string]string) - } - dict[section][key] = value -} - -func (dict Dict) GetInt(section, key string) (int, bool) { - sec, ok := dict[section] - if !ok { - return 0, false - } - value, ok := sec[key] - if !ok { - return 0, false - } - i, err := strconv.Atoi(value) - if err != nil { - return 0, false - } - return i, true -} - -func (dict Dict) SetInt(section, key string, value int) { - dict.SetString(section, key, strconv.FormatInt(int64(value), 10)) -} - -func (dict Dict) GetDouble(section, key string) (float64, bool) { - sec, ok := dict[section] - if !ok { - return 0, false - } - value, ok := sec[key] - if !ok { - return 0, false - } - d, err := strconv.ParseFloat(value, 64) - if err != nil { - return 0, false - } - return d, true -} - -func (dict Dict) SetDouble(section, key string, value float64) { - dict.SetString(section, key, strconv.FormatFloat(value, 'f', -1, 64)) -} - -func (dict Dict) Delete(section, key string) { - _, ok := dict[section] - if !ok { - return - } - delete(dict[section], key) - // If there are no items left in the section, - // delete the section. - if len(dict[section]) == 0 { - delete(dict, section) - } -} - -func (dict Dict) GetSections() []string { - size := len(dict) - sections := make([]string, size) - i := 0 - for section, _ := range dict { - sections[i] = section - i++ - } - return sections -} - -func (dict Dict) String() string { - return (*dict.format()).String() -} - -func (dict Dict) format() *bytes.Buffer { - var buffer bytes.Buffer - for key, val := range dict[""] { - buffer.WriteString(fmt.Sprintf("%s = %s\n", key, val)) - } - buffer.WriteString("\n") - for section, vals := range dict { - if section == "" { - continue - } - buffer.WriteString(fmt.Sprintf("[%s]\n", section)) - for key, val := range vals { - buffer.WriteString(fmt.Sprintf("%s = %s\n", key, val)) - } - buffer.WriteString("\n") - } - return &buffer -} - -func newError(message string) (e error) { - return Error(message) -} diff --git a/vendor/github.com/glacjay/goini/ini_test.go b/vendor/github.com/glacjay/goini/ini_test.go deleted file mode 100644 index 4a64eb3f..00000000 --- a/vendor/github.com/glacjay/goini/ini_test.go +++ /dev/null @@ -1,191 +0,0 @@ -package ini - -import ( - "bufio" - "io/ioutil" - "os" - "strings" - "testing" -) - -var ( - dict Dict - err error -) - -func init() { - dict, err = Load("example.ini") -} - -func TestLoad(t *testing.T) { - if err != nil { - t.Error("Example: load error:", err) - } -} - -func TestLoadFileWithSpaces(t *testing.T) { - if err := ioutil.WriteFile("testLoadFileWithSpaces.ini", []byte(" "), 0777); err != nil { - t.Error("Unable to write test file") - } - defer os.Remove("testLoadFileWithSpaces.ini") - - if _, err := Load("testLoadFileWithSpaces.ini"); err != nil { - t.Error("Load: Couldn't load ini file with line consisting only of spaces.") - } -} - -func TestWrite(t *testing.T) { - d, err := Load("empty.ini") - if err != nil { - t.Error("Example: load error:", err) - } - d.SetString("", "key", "value") - tempFile, err := ioutil.TempFile("", "") - if err != nil { - t.Error("Write: Couldn't create temp file.", err) - } - err = Write(tempFile.Name(), &d) - if err != nil { - t.Error("Write: Couldn't write to temp config file.", err) - } - contents, err := ioutil.ReadFile(tempFile.Name()) - if err != nil { - t.Error("Write: Couldn't read from the temp config file.", err) - } - if string(contents) != "key = value\n\n" { - t.Error("Write: Contents of the config file doesn't match the expected.") - } -} - -func TestGetBool(t *testing.T) { - b, found := dict.GetBool("pizza", "ham") - if !found || !b { - t.Error("Example: parse error for key ham of section pizza.") - } - b, found = dict.GetBool("pizza", "mushrooms") - if !found || !b { - t.Error("Example: parse error for key mushrooms of section pizza.") - } - b, found = dict.GetBool("pizza", "capres") - if !found || b { - t.Error("Example: parse error for key capres of section pizza.") - } - b, found = dict.GetBool("pizza", "cheese") - if !found || b { - t.Error("Example: parse error for key cheese of section pizza.") - } -} - -func TestGetStringIntAndDouble(t *testing.T) { - str, found := dict.GetString("wine", "grape") - if !found || str != "Cabernet Sauvignon" { - t.Error("Example: parse error for key grape of section wine.") - } - i, found := dict.GetInt("wine", "year") - if !found || i != 1989 { - t.Error("Example: parse error for key year of section wine.") - } - str, found = dict.GetString("wine", "country") - if !found || str != "Spain" { - t.Error("Example: parse error for key grape of section wine.") - } - d, found := dict.GetDouble("wine", "alcohol") - if !found || d != 12.5 { - t.Error("Example: parse error for key grape of section wine.") - } -} - -func TestSetBoolAndStringAndIntAndDouble(t *testing.T) { - dict.SetBool("pizza", "ham", false) - b, found := dict.GetBool("pizza", "ham") - if !found || b { - t.Error("Example: bool set error for key ham of section pizza.") - } - dict.SetString("pizza", "ham", "no") - n, found := dict.GetString("pizza", "ham") - if !found || n != "no" { - t.Error("Example: string set error for key ham of section pizza.") - } - dict.SetInt("wine", "year", 1978) - i, found := dict.GetInt("wine", "year") - if !found || i != 1978 { - t.Error("Example: int set error for key year of section wine.") - } - dict.SetDouble("wine", "not-exists", 5.6) - d, found := dict.GetDouble("wine", "not-exists") - if !found || d != 5.6 { - t.Error("Example: float set error for not existing key for wine.") - } -} - -func TestDelete(t *testing.T) { - d, err := Load("empty.ini") - if err != nil { - t.Error("Example: load error:", err) - } - d.SetString("pizza", "ham", "yes") - d.Delete("pizza", "ham") - _, found := d.GetString("pizza", "ham") - if found { - t.Error("Example: delete error for key ham of section pizza.") - } - if len(d.GetSections()) > 1 { - t.Error("Only a single section should exist after deletion.") - } -} - -func TestGetNotExist(t *testing.T) { - _, found := dict.GetString("not", "exist") - if found { - t.Error("There is no key exist of section not.") - } -} - -func TestGetSections(t *testing.T) { - sections := dict.GetSections() - if len(sections) != 3 { - t.Error("The number of sections is wrong:", len(sections)) - } - for _, section := range sections { - if section != "" && section != "pizza" && section != "wine" { - t.Errorf("Section '%s' should not be exist.", section) - } - } -} - -func TestString(t *testing.T) { - d, err := Load("empty.ini") - if err != nil { - t.Error("Example: load error:", err) - } - d.SetBool("", "key1", true) - d.SetString("section1", "key1", "value2") - d.SetInt("section1", "key2", 5) - d.SetDouble("section1", "key3", 1.3) - d.SetDouble("section2", "key1", 5.0) - reader := strings.NewReader(d.String()) - d2, err := LoadReader(bufio.NewReader(reader)) - if err != nil { - t.Error("Example: load error:", err) - } - b, found := d2.GetBool("", "key1") - if !found || !b { - t.Errorf("Stringify failed for key1") - } - s, found := d2.GetString("section1", "key1") - if !found || s != "value2" { - t.Error("Stringify failed for section1, key1") - } - i, found := d2.GetInt("section1", "key2") - if !found || i != 5 { - t.Error("Stringify failed for section1, key2") - } - db, found := d2.GetDouble("section1", "key3") - if !found || db != 1.3 { - t.Error("Stringify failed for section1, key3") - } - db, found = d2.GetDouble("section2", "key1") - if !found || db != 5.0 { - t.Error("Stringify failed for section2, key1") - } -} diff --git a/vendor/github.com/jessevdk/go-flags/.travis.yml b/vendor/github.com/jessevdk/go-flags/.travis.yml new file mode 100644 index 00000000..e7c4be05 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/.travis.yml @@ -0,0 +1,38 @@ +language: go + +go: + - 1.6.x + - 1.7.x + +install: + # go-flags + - go get -d -v ./... + - go build -v ./... + + # linting + - go get github.com/golang/lint + - go install github.com/golang/lint/golint + + # code coverage + - go get golang.org/x/tools/cmd/cover + - go get github.com/onsi/ginkgo/ginkgo + - go get github.com/modocache/gover + - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then go get github.com/mattn/goveralls; fi + +script: + # go-flags + - $(exit $(gofmt -l . | wc -l)) + - go test -v ./... + + # linting + - go tool vet -all=true -v=true . || true + - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/golint ./... + + # code coverage + - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/ginkgo -r -cover + - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/gover + - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/goveralls -coverprofile=gover.coverprofile -service=travis-ci -repotoken $COVERALLS_TOKEN; fi + +env: + # coveralls.io + secure: "RCYbiB4P0RjQRIoUx/vG/AjP3mmYCbzOmr86DCww1Z88yNcy3hYr3Cq8rpPtYU5v0g7wTpu4adaKIcqRE9xknYGbqj3YWZiCoBP1/n4Z+9sHW3Dsd9D/GRGeHUus0laJUGARjWoCTvoEtOgTdGQDoX7mH+pUUY0FBltNYUdOiiU=" diff --git a/vendor/github.com/spf13/pflag/LICENSE b/vendor/github.com/jessevdk/go-flags/LICENSE similarity index 70% rename from vendor/github.com/spf13/pflag/LICENSE rename to vendor/github.com/jessevdk/go-flags/LICENSE index 63ed1cfe..bcca0d52 100644 --- a/vendor/github.com/spf13/pflag/LICENSE +++ b/vendor/github.com/jessevdk/go-flags/LICENSE @@ -1,19 +1,17 @@ -Copyright (c) 2012 Alex Ogier. All rights reserved. -Copyright (c) 2012 The Go Authors. All rights reserved. - +Copyright (c) 2012 Jesse van den Kieboom. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. + 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. + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. + 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 diff --git a/vendor/github.com/jessevdk/go-flags/README.md b/vendor/github.com/jessevdk/go-flags/README.md new file mode 100644 index 00000000..9378b760 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/README.md @@ -0,0 +1,135 @@ +go-flags: a go library for parsing command line arguments +========================================================= + +[![GoDoc](https://godoc.org/github.com/jessevdk/go-flags?status.png)](https://godoc.org/github.com/jessevdk/go-flags) [![Build Status](https://travis-ci.org/jessevdk/go-flags.svg?branch=master)](https://travis-ci.org/jessevdk/go-flags) [![Coverage Status](https://img.shields.io/coveralls/jessevdk/go-flags.svg)](https://coveralls.io/r/jessevdk/go-flags?branch=master) + +This library provides similar functionality to the builtin flag library of +go, but provides much more functionality and nicer formatting. From the +documentation: + +Package flags provides an extensive command line option parser. +The flags package is similar in functionality to the go builtin flag package +but provides more options and uses reflection to provide a convenient and +succinct way of specifying command line options. + +Supported features: +* Options with short names (-v) +* Options with long names (--verbose) +* Options with and without arguments (bool v.s. other type) +* Options with optional arguments and default values +* Multiple option groups each containing a set of options +* Generate and print well-formatted help message +* Passing remaining command line arguments after -- (optional) +* Ignoring unknown command line options (optional) +* Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification +* Supports multiple short options -aux +* Supports all primitive go types (string, int{8..64}, uint{8..64}, float) +* Supports same option multiple times (can store in slice or last option counts) +* Supports maps +* Supports function callbacks +* Supports namespaces for (nested) option groups + +The flags package uses structs, reflection and struct field tags +to allow users to specify command line options. This results in very simple +and concise specification of your application options. For example: + +```go +type Options struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` +} +``` + +This specifies one option with a short name -v and a long name --verbose. +When either -v or --verbose is found on the command line, a 'true' value +will be appended to the Verbose field. e.g. when specifying -vvv, the +resulting value of Verbose will be {[true, true, true]}. + +Example: +-------- +```go +var opts struct { + // Slice of bool will append 'true' each time the option + // is encountered (can be set multiple times, like -vvv) + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + + // Example of automatic marshalling to desired type (uint) + Offset uint `long:"offset" description:"Offset"` + + // Example of a callback, called each time the option is found. + Call func(string) `short:"c" description:"Call phone number"` + + // Example of a required flag + Name string `short:"n" long:"name" description:"A name" required:"true"` + + // Example of a value name + File string `short:"f" long:"file" description:"A file" value-name:"FILE"` + + // Example of a pointer + Ptr *int `short:"p" description:"A pointer to an integer"` + + // Example of a slice of strings + StringSlice []string `short:"s" description:"A slice of strings"` + + // Example of a slice of pointers + PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + + // Example of a map + IntMap map[string]int `long:"intmap" description:"A map from string to int"` +} + +// Callback which will invoke callto: to call a number. +// Note that this works just on OS X (and probably only with +// Skype) but it shows the idea. +opts.Call = func(num string) { + cmd := exec.Command("open", "callto:"+num) + cmd.Start() + cmd.Process.Release() +} + +// Make some fake arguments to parse. +args := []string{ + "-vv", + "--offset=5", + "-n", "Me", + "-p", "3", + "-s", "hello", + "-s", "world", + "--ptrslice", "hello", + "--ptrslice", "world", + "--intmap", "a:1", + "--intmap", "b:5", + "arg1", + "arg2", + "arg3", +} + +// Parse flags from `args'. Note that here we use flags.ParseArgs for +// the sake of making a working example. Normally, you would simply use +// flags.Parse(&opts) which uses os.Args +args, err := flags.ParseArgs(&opts, args) + +if err != nil { + panic(err) + os.Exit(1) +} + +fmt.Printf("Verbosity: %v\n", opts.Verbose) +fmt.Printf("Offset: %d\n", opts.Offset) +fmt.Printf("Name: %s\n", opts.Name) +fmt.Printf("Ptr: %d\n", *opts.Ptr) +fmt.Printf("StringSlice: %v\n", opts.StringSlice) +fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) +fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) +fmt.Printf("Remaining args: %s\n", strings.Join(args, " ")) + +// Output: Verbosity: [true true] +// Offset: 5 +// Name: Me +// Ptr: 3 +// StringSlice: [hello world] +// PtrSlice: [hello world] +// IntMap: [a:1 b:5] +// Remaining args: arg1 arg2 arg3 +``` + +More information can be found in the godocs: diff --git a/vendor/github.com/jessevdk/go-flags/arg.go b/vendor/github.com/jessevdk/go-flags/arg.go new file mode 100644 index 00000000..8ec62048 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/arg.go @@ -0,0 +1,27 @@ +package flags + +import ( + "reflect" +) + +// Arg represents a positional argument on the command line. +type Arg struct { + // The name of the positional argument (used in the help) + Name string + + // A description of the positional argument (used in the help) + Description string + + // The minimal number of required positional arguments + Required int + + // The maximum number of required positional arguments + RequiredMaximum int + + value reflect.Value + tag multiTag +} + +func (a *Arg) isRemaining() bool { + return a.value.Type().Kind() == reflect.Slice +} diff --git a/vendor/github.com/jessevdk/go-flags/arg_test.go b/vendor/github.com/jessevdk/go-flags/arg_test.go new file mode 100644 index 00000000..c7c0a612 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/arg_test.go @@ -0,0 +1,163 @@ +package flags + +import ( + "testing" +) + +func TestPositional(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Command int + Filename string + Rest []string + } `positional-args:"yes" required:"yes"` + }{} + + p := NewParser(&opts, Default) + ret, err := p.ParseArgs([]string{"10", "arg_test.go", "a", "b"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if opts.Positional.Command != 10 { + t.Fatalf("Expected opts.Positional.Command to be 10, but got %v", opts.Positional.Command) + } + + if opts.Positional.Filename != "arg_test.go" { + t.Fatalf("Expected opts.Positional.Filename to be \"arg_test.go\", but got %v", opts.Positional.Filename) + } + + assertStringArray(t, opts.Positional.Rest, []string{"a", "b"}) + assertStringArray(t, ret, []string{}) +} + +func TestPositionalRequired(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Command int + Filename string + Rest []string + } `positional-args:"yes" required:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"10"}) + + assertError(t, err, ErrRequired, "the required argument `Filename` was not provided") +} + +func TestPositionalRequiredRest1Fail(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"yes"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{}) + + assertError(t, err, ErrRequired, "the required argument `Rest (at least 1 argument)` was not provided") +} + +func TestPositionalRequiredRest1Pass(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"yes"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if len(opts.Positional.Rest) != 1 { + t.Fatalf("Expected 1 positional rest argument") + } + + assertString(t, opts.Positional.Rest[0], "rest1") +} + +func TestPositionalRequiredRest2Fail(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"2"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1"}) + + assertError(t, err, ErrRequired, "the required argument `Rest (at least 2 arguments, but got only 1)` was not provided") +} + +func TestPositionalRequiredRest2Pass(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"2"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if len(opts.Positional.Rest) != 3 { + t.Fatalf("Expected 3 positional rest argument") + } + + assertString(t, opts.Positional.Rest[0], "rest1") + assertString(t, opts.Positional.Rest[1], "rest2") + assertString(t, opts.Positional.Rest[2], "rest3") +} + +func TestPositionalRequiredRestRangeFail(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"1-2"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rest1", "rest2", "rest3"}) + + assertError(t, err, ErrRequired, "the required argument `Rest (at most 2 arguments, but got 3)` was not provided") +} + +func TestPositionalRequiredRestRangeEmptyFail(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Positional struct { + Rest []string `required:"0-0"` + } `positional-args:"yes"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"some", "thing"}) + + assertError(t, err, ErrRequired, "the required argument `Rest (zero arguments)` was not provided") +} diff --git a/vendor/github.com/jessevdk/go-flags/assert_test.go b/vendor/github.com/jessevdk/go-flags/assert_test.go new file mode 100644 index 00000000..8e06636b --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/assert_test.go @@ -0,0 +1,177 @@ +package flags + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path" + "runtime" + "testing" +) + +func assertCallerInfo() (string, int) { + ptr := make([]uintptr, 15) + n := runtime.Callers(1, ptr) + + if n == 0 { + return "", 0 + } + + mef := runtime.FuncForPC(ptr[0]) + mefile, meline := mef.FileLine(ptr[0]) + + for i := 2; i < n; i++ { + f := runtime.FuncForPC(ptr[i]) + file, line := f.FileLine(ptr[i]) + + if file != mefile { + return file, line + } + } + + return mefile, meline +} + +func assertErrorf(t *testing.T, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + + file, line := assertCallerInfo() + + t.Errorf("%s:%d: %s", path.Base(file), line, msg) +} + +func assertFatalf(t *testing.T, format string, args ...interface{}) { + msg := fmt.Sprintf(format, args...) + + file, line := assertCallerInfo() + + t.Fatalf("%s:%d: %s", path.Base(file), line, msg) +} + +func assertString(t *testing.T, a string, b string) { + if a != b { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + } +} + +func assertStringArray(t *testing.T, a []string, b []string) { + if len(a) != len(b) { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + + for i, v := range a { + if b[i] != v { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + } +} + +func assertBoolArray(t *testing.T, a []bool, b []bool) { + if len(a) != len(b) { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + + for i, v := range a { + if b[i] != v { + assertErrorf(t, "Expected %#v, but got %#v", b, a) + return + } + } +} + +func assertParserSuccess(t *testing.T, data interface{}, args ...string) (*Parser, []string) { + parser := NewParser(data, Default&^PrintErrors) + ret, err := parser.ParseArgs(args) + + if err != nil { + t.Fatalf("Unexpected parse error: %s", err) + return nil, nil + } + + return parser, ret +} + +func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string { + _, ret := assertParserSuccess(t, data, args...) + return ret +} + +func assertError(t *testing.T, err error, typ ErrorType, msg string) { + if err == nil { + assertFatalf(t, "Expected error: %s", msg) + return + } + + if e, ok := err.(*Error); !ok { + assertFatalf(t, "Expected Error type, but got %#v", err) + } else { + if e.Type != typ { + assertErrorf(t, "Expected error type {%s}, but got {%s}", typ, e.Type) + } + + if e.Message != msg { + assertErrorf(t, "Expected error message %#v, but got %#v", msg, e.Message) + } + } +} + +func assertParseFail(t *testing.T, typ ErrorType, msg string, data interface{}, args ...string) []string { + parser := NewParser(data, Default&^PrintErrors) + ret, err := parser.ParseArgs(args) + + assertError(t, err, typ, msg) + return ret +} + +func diff(a, b string) (string, error) { + atmp, err := ioutil.TempFile("", "help-diff") + + if err != nil { + return "", err + } + + btmp, err := ioutil.TempFile("", "help-diff") + + if err != nil { + return "", err + } + + if _, err := io.WriteString(atmp, a); err != nil { + return "", err + } + + if _, err := io.WriteString(btmp, b); err != nil { + return "", err + } + + ret, err := exec.Command("diff", "-u", "-d", "--label", "got", atmp.Name(), "--label", "expected", btmp.Name()).Output() + + os.Remove(atmp.Name()) + os.Remove(btmp.Name()) + + if err.Error() == "exit status 1" { + return string(ret), nil + } + + return string(ret), err +} + +func assertDiff(t *testing.T, actual, expected, msg string) { + if actual == expected { + return + } + + ret, err := diff(actual, expected) + + if err != nil { + assertErrorf(t, "Unexpected diff error: %s", err) + assertErrorf(t, "Unexpected %s, expected:\n\n%s\n\nbut got\n\n%s", msg, expected, actual) + } else { + assertErrorf(t, "Unexpected %s:\n\n%s", msg, ret) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh new file mode 100755 index 00000000..c494f611 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +echo '# linux arm7' +GOARM=7 GOARCH=arm GOOS=linux go build +echo '# linux arm5' +GOARM=5 GOARCH=arm GOOS=linux go build +echo '# windows 386' +GOARCH=386 GOOS=windows go build +echo '# windows amd64' +GOARCH=amd64 GOOS=windows go build +echo '# darwin' +GOARCH=amd64 GOOS=darwin go build +echo '# freebsd' +GOARCH=amd64 GOOS=freebsd go build diff --git a/vendor/github.com/jessevdk/go-flags/closest.go b/vendor/github.com/jessevdk/go-flags/closest.go new file mode 100644 index 00000000..3b518757 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/closest.go @@ -0,0 +1,59 @@ +package flags + +func levenshtein(s string, t string) int { + if len(s) == 0 { + return len(t) + } + + if len(t) == 0 { + return len(s) + } + + dists := make([][]int, len(s)+1) + for i := range dists { + dists[i] = make([]int, len(t)+1) + dists[i][0] = i + } + + for j := range t { + dists[0][j] = j + } + + for i, sc := range s { + for j, tc := range t { + if sc == tc { + dists[i+1][j+1] = dists[i][j] + } else { + dists[i+1][j+1] = dists[i][j] + 1 + if dists[i+1][j] < dists[i+1][j+1] { + dists[i+1][j+1] = dists[i+1][j] + 1 + } + if dists[i][j+1] < dists[i+1][j+1] { + dists[i+1][j+1] = dists[i][j+1] + 1 + } + } + } + } + + return dists[len(s)][len(t)] +} + +func closestChoice(cmd string, choices []string) (string, int) { + if len(choices) == 0 { + return "", 0 + } + + mincmd := -1 + mindist := -1 + + for i, c := range choices { + l := levenshtein(cmd, c) + + if mincmd < 0 || l < mindist { + mindist = l + mincmd = i + } + } + + return choices[mincmd], mindist +} diff --git a/vendor/github.com/jessevdk/go-flags/command.go b/vendor/github.com/jessevdk/go-flags/command.go new file mode 100644 index 00000000..26628436 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/command.go @@ -0,0 +1,455 @@ +package flags + +import ( + "reflect" + "sort" + "strconv" + "strings" + "unsafe" +) + +// Command represents an application command. Commands can be added to the +// parser (which itself is a command) and are selected/executed when its name +// is specified on the command line. The Command type embeds a Group and +// therefore also carries a set of command specific options. +type Command struct { + // Embedded, see Group for more information + *Group + + // The name by which the command can be invoked + Name string + + // The active sub command (set by parsing) or nil + Active *Command + + // Whether subcommands are optional + SubcommandsOptional bool + + // Aliases for the command + Aliases []string + + // Whether positional arguments are required + ArgsRequired bool + + commands []*Command + hasBuiltinHelpGroup bool + args []*Arg +} + +// Commander is an interface which can be implemented by any command added in +// the options. When implemented, the Execute method will be called for the last +// specified (sub)command providing the remaining command line arguments. +type Commander interface { + // Execute will be called for the last active (sub)command. The + // args argument contains the remaining command line arguments. The + // error that Execute returns will be eventually passed out of the + // Parse method of the Parser. + Execute(args []string) error +} + +// Usage is an interface which can be implemented to show a custom usage string +// in the help message shown for a command. +type Usage interface { + // Usage is called for commands to allow customized printing of command + // usage in the generated help message. + Usage() string +} + +type lookup struct { + shortNames map[string]*Option + longNames map[string]*Option + + commands map[string]*Command +} + +// AddCommand adds a new command to the parser with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the command. The provided data can implement the Command and +// Usage interfaces. +func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) { + cmd := newCommand(command, shortDescription, longDescription, data) + + cmd.parent = c + + if err := cmd.scan(); err != nil { + return nil, err + } + + c.commands = append(c.commands, cmd) + return cmd, nil +} + +// AddGroup adds a new group to the command with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the group. +func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { + group := newGroup(shortDescription, longDescription, data) + + group.parent = c + + if err := group.scanType(c.scanSubcommandHandler(group)); err != nil { + return nil, err + } + + c.groups = append(c.groups, group) + return group, nil +} + +// Commands returns a list of subcommands of this command. +func (c *Command) Commands() []*Command { + return c.commands +} + +// Find locates the subcommand with the given name and returns it. If no such +// command can be found Find will return nil. +func (c *Command) Find(name string) *Command { + for _, cc := range c.commands { + if cc.match(name) { + return cc + } + } + + return nil +} + +// FindOptionByLongName finds an option that is part of the command, or any of +// its parent commands, by matching its long name (including the option +// namespace). +func (c *Command) FindOptionByLongName(longName string) (option *Option) { + for option == nil && c != nil { + option = c.Group.FindOptionByLongName(longName) + + c, _ = c.parent.(*Command) + } + + return option +} + +// FindOptionByShortName finds an option that is part of the command, or any of +// its parent commands, by matching its long name (including the option +// namespace). +func (c *Command) FindOptionByShortName(shortName rune) (option *Option) { + for option == nil && c != nil { + option = c.Group.FindOptionByShortName(shortName) + + c, _ = c.parent.(*Command) + } + + return option +} + +// Args returns a list of positional arguments associated with this command. +func (c *Command) Args() []*Arg { + ret := make([]*Arg, len(c.args)) + copy(ret, c.args) + + return ret +} + +func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command { + return &Command{ + Group: newGroup(shortDescription, longDescription, data), + Name: name, + } +} + +func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler { + f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) { + mtag := newMultiTag(string(sfield.Tag)) + + if err := mtag.Parse(); err != nil { + return true, err + } + + positional := mtag.Get("positional-args") + + if len(positional) != 0 { + stype := realval.Type() + + for i := 0; i < stype.NumField(); i++ { + field := stype.Field(i) + + m := newMultiTag((string(field.Tag))) + + if err := m.Parse(); err != nil { + return true, err + } + + name := m.Get("positional-arg-name") + + if len(name) == 0 { + name = field.Name + } + + required := -1 + requiredMaximum := -1 + + sreq := m.Get("required") + + if sreq != "" { + required = 1 + + rng := strings.SplitN(sreq, "-", 2) + + if len(rng) > 1 { + if preq, err := strconv.ParseInt(rng[0], 10, 32); err == nil { + required = int(preq) + } + + if preq, err := strconv.ParseInt(rng[1], 10, 32); err == nil { + requiredMaximum = int(preq) + } + } else { + if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil { + required = int(preq) + } + } + } + + arg := &Arg{ + Name: name, + Description: m.Get("description"), + Required: required, + RequiredMaximum: requiredMaximum, + + value: realval.Field(i), + tag: m, + } + + c.args = append(c.args, arg) + + if len(mtag.Get("required")) != 0 { + c.ArgsRequired = true + } + } + + return true, nil + } + + subcommand := mtag.Get("command") + + if len(subcommand) != 0 { + ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr())) + + shortDescription := mtag.Get("description") + longDescription := mtag.Get("long-description") + subcommandsOptional := mtag.Get("subcommands-optional") + aliases := mtag.GetMany("alias") + + subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface()) + if err != nil { + return true, err + } + + subc.Hidden = mtag.Get("hidden") != "" + + if len(subcommandsOptional) > 0 { + subc.SubcommandsOptional = true + } + + if len(aliases) > 0 { + subc.Aliases = aliases + } + + return true, nil + } + + return parentg.scanSubGroupHandler(realval, sfield) + } + + return f +} + +func (c *Command) scan() error { + return c.scanType(c.scanSubcommandHandler(c.Group)) +} + +func (c *Command) eachOption(f func(*Command, *Group, *Option)) { + c.eachCommand(func(c *Command) { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + f(c, g, option) + } + }) + }, true) +} + +func (c *Command) eachCommand(f func(*Command), recurse bool) { + f(c) + + for _, cc := range c.commands { + if recurse { + cc.eachCommand(f, true) + } else { + f(cc) + } + } +} + +func (c *Command) eachActiveGroup(f func(cc *Command, g *Group)) { + c.eachGroup(func(g *Group) { + f(c, g) + }) + + if c.Active != nil { + c.Active.eachActiveGroup(f) + } +} + +func (c *Command) addHelpGroups(showHelp func() error) { + if !c.hasBuiltinHelpGroup { + c.addHelpGroup(showHelp) + c.hasBuiltinHelpGroup = true + } + + for _, cc := range c.commands { + cc.addHelpGroups(showHelp) + } +} + +func (c *Command) makeLookup() lookup { + ret := lookup{ + shortNames: make(map[string]*Option), + longNames: make(map[string]*Option), + commands: make(map[string]*Command), + } + + parent := c.parent + + var parents []*Command + + for parent != nil { + if cmd, ok := parent.(*Command); ok { + parents = append(parents, cmd) + parent = cmd.parent + } else { + parent = nil + } + } + + for i := len(parents) - 1; i >= 0; i-- { + parents[i].fillLookup(&ret, true) + } + + c.fillLookup(&ret, false) + return ret +} + +func (c *Command) fillLookup(ret *lookup, onlyOptions bool) { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + if option.ShortName != 0 { + ret.shortNames[string(option.ShortName)] = option + } + + if len(option.LongName) > 0 { + ret.longNames[option.LongNameWithNamespace()] = option + } + } + }) + + if onlyOptions { + return + } + + for _, subcommand := range c.commands { + ret.commands[subcommand.Name] = subcommand + + for _, a := range subcommand.Aliases { + ret.commands[a] = subcommand + } + } +} + +func (c *Command) groupByName(name string) *Group { + if grp := c.Group.groupByName(name); grp != nil { + return grp + } + + for _, subc := range c.commands { + prefix := subc.Name + "." + + if strings.HasPrefix(name, prefix) { + if grp := subc.groupByName(name[len(prefix):]); grp != nil { + return grp + } + } else if name == subc.Name { + return subc.Group + } + } + + return nil +} + +type commandList []*Command + +func (c commandList) Less(i, j int) bool { + return c[i].Name < c[j].Name +} + +func (c commandList) Len() int { + return len(c) +} + +func (c commandList) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +func (c *Command) sortedVisibleCommands() []*Command { + ret := commandList(c.visibleCommands()) + sort.Sort(ret) + + return []*Command(ret) +} + +func (c *Command) visibleCommands() []*Command { + ret := make([]*Command, 0, len(c.commands)) + + for _, cmd := range c.commands { + if !cmd.Hidden { + ret = append(ret, cmd) + } + } + + return ret +} + +func (c *Command) match(name string) bool { + if c.Name == name { + return true + } + + for _, v := range c.Aliases { + if v == name { + return true + } + } + + return false +} + +func (c *Command) hasCliOptions() bool { + ret := false + + c.eachGroup(func(g *Group) { + if g.isBuiltinHelp { + return + } + + for _, opt := range g.options { + if opt.canCli() { + ret = true + } + } + }) + + return ret +} + +func (c *Command) fillParseState(s *parseState) { + s.positional = make([]*Arg, len(c.args)) + copy(s.positional, c.args) + + s.lookup = c.makeLookup() + s.command = c +} diff --git a/vendor/github.com/jessevdk/go-flags/command_test.go b/vendor/github.com/jessevdk/go-flags/command_test.go new file mode 100644 index 00000000..dc04b66c --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/command_test.go @@ -0,0 +1,582 @@ +package flags + +import ( + "fmt" + "testing" +) + +func TestCommandInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g") + + assertStringArray(t, ret, []string{}) + + if p.Active == nil { + t.Errorf("Expected active command") + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } + + if p.Command.Find("cmd") != p.Active { + t.Errorf("Expected to find command `cmd' to be active") + } +} + +func TestCommandInlineMulti(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + C1 struct { + } `command:"c1"` + + C2 struct { + G bool `short:"g"` + } `command:"c2"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "c2", "-g") + + assertStringArray(t, ret, []string{}) + + if p.Active == nil { + t.Errorf("Expected active command") + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.C2.G { + t.Errorf("Expected C2.G to be true") + } + + if p.Command.Find("c1") == nil { + t.Errorf("Expected to find command `c1'") + } + + if c2 := p.Command.Find("c2"); c2 == nil { + t.Errorf("Expected to find command `c2'") + } else if c2 != p.Active { + t.Errorf("Expected to find command `c2' to be active") + } +} + +func TestCommandFlagOrder1(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseFail(t, ErrUnknownFlag, "unknown flag `g'", &opts, "-v", "-g", "cmd") +} + +func TestCommandFlagOrder2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "-v", "-g") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } +} + +func TestCommandFlagOrderSub(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + + SubCommand struct { + B bool `short:"b"` + } `command:"sub"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "sub", "-v", "-g", "-b") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } + + if !opts.Command.SubCommand.B { + t.Errorf("Expected Command.SubCommand.B to be true") + } +} + +func TestCommandFlagOverride1(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "-v", "cmd") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if opts.Command.Value { + t.Errorf("Expected Command.Value to be false") + } +} + +func TestCommandFlagOverride2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "-v") + + if opts.Value { + t.Errorf("Expected Value to be false") + } + + if !opts.Command.Value { + t.Errorf("Expected Command.Value to be true") + } +} + +func TestCommandFlagOverrideSub(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + + SubCommand struct { + Value bool `short:"v"` + } `command:"sub"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "sub", "-v") + + if opts.Value { + t.Errorf("Expected Value to be false") + } + + if opts.Command.Value { + t.Errorf("Expected Command.Value to be false") + } + + if !opts.Command.SubCommand.Value { + t.Errorf("Expected Command.Value to be true") + } +} + +func TestCommandFlagOverrideSub2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + Value bool `short:"v"` + + SubCommand struct { + G bool `short:"g"` + } `command:"sub"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd", "sub", "-v") + + if opts.Value { + t.Errorf("Expected Value to be false") + } + + if !opts.Command.Value { + t.Errorf("Expected Command.Value to be true") + } +} + +func TestCommandEstimate(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{}) + + assertError(t, err, ErrCommandRequired, "Please specify one command of: add or remove") +} + +func TestCommandEstimate2(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + _, err := p.ParseArgs([]string{"rmive"}) + + assertError(t, err, ErrUnknownCommand, "Unknown command `rmive', did you mean `remove'?") +} + +type testCommand struct { + G bool `short:"g"` + Executed bool + EArgs []string +} + +func (c *testCommand) Execute(args []string) error { + c.Executed = true + c.EArgs = args + + return nil +} + +func TestCommandExecute(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command testCommand `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "-v", "cmd", "-g", "a", "b") + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.Executed { + t.Errorf("Did not execute command") + } + + if !opts.Command.G { + t.Errorf("Expected Command.C to be true") + } + + assertStringArray(t, opts.Command.EArgs, []string{"a", "b"}) +} + +func TestCommandClosest(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + args := assertParseFail(t, ErrUnknownCommand, "Unknown command `addd', did you mean `add'?", &opts, "-v", "addd") + + assertStringArray(t, args, []string{"addd"}) +} + +func TestCommandAdd(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + var cmd = struct { + G bool `short:"g"` + }{} + + p := NewParser(&opts, Default) + c, err := p.AddCommand("cmd", "", "", &cmd) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + ret, err := p.ParseArgs([]string{"-v", "cmd", "-g", "rest"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !cmd.G { + t.Errorf("Expected Command.G to be true") + } + + if p.Command.Find("cmd") != c { + t.Errorf("Expected to find command `cmd'") + } + + if p.Commands()[0] != c { + t.Errorf("Expected command %#v, but got %#v", c, p.Commands()[0]) + } + + if c.Options()[0].ShortName != 'g' { + t.Errorf("Expected short name `g' but got %v", c.Options()[0].ShortName) + } +} + +func TestCommandNestedInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command struct { + G bool `short:"g"` + + Nested struct { + N string `long:"n"` + } `command:"nested"` + } `command:"cmd"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "cmd", "-g", "nested", "--n", "n", "rest") + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Command.G { + t.Errorf("Expected Command.G to be true") + } + + assertString(t, opts.Command.Nested.N, "n") + + if c := p.Command.Find("cmd"); c == nil { + t.Errorf("Expected to find command `cmd'") + } else { + if c != p.Active { + t.Errorf("Expected `cmd' to be the active parser command") + } + + if nested := c.Find("nested"); nested == nil { + t.Errorf("Expected to find command `nested'") + } else if nested != c.Active { + t.Errorf("Expected to find command `nested' to be the active `cmd' command") + } + } +} + +func TestRequiredOnCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"true"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts, "cmd") +} + +func TestRequiredAllOnCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"true"` + Missing bool `long:"missing" required:"true"` + + Command struct { + G bool `short:"g"` + } `command:"cmd"` + }{} + + assertParseFail(t, ErrRequired, fmt.Sprintf("the required flags `%smissing' and `%cv' were not specified", defaultLongOptDelimiter, defaultShortOptDelimiter), &opts, "cmd") +} + +func TestDefaultOnCommand(t *testing.T) { + var opts = struct { + Command struct { + G string `short:"g" default:"value"` + } `command:"cmd"` + }{} + + assertParseSuccess(t, &opts, "cmd") + + if opts.Command.G != "value" { + t.Errorf("Expected G to be \"value\"") + } +} + +func TestAfterNonCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + assertParseFail(t, ErrUnknownCommand, "Unknown command `nocmd'. Please specify one command of: add or remove", &opts, "nocmd", "remove") +} + +func TestSubcommandsOptional(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + p.SubcommandsOptional = true + + _, err := p.ParseArgs([]string{"-v"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestSubcommandsOptionalAfterNonCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Cmd1 struct { + } `command:"remove"` + + Cmd2 struct { + } `command:"add"` + }{} + + p := NewParser(&opts, None) + p.SubcommandsOptional = true + + retargs, err := p.ParseArgs([]string{"nocmd", "remove"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + assertStringArray(t, retargs, []string{"nocmd", "remove"}) +} + +func TestCommandAlias(t *testing.T) { + var opts = struct { + Command struct { + G string `short:"g" default:"value"` + } `command:"cmd" alias:"cm"` + }{} + + assertParseSuccess(t, &opts, "cm") + + if opts.Command.G != "value" { + t.Errorf("Expected G to be \"value\"") + } +} + +func TestSubCommandFindOptionByLongFlag(t *testing.T) { + var opts struct { + Testing bool `long:"testing" description:"Testing"` + } + + var cmd struct { + Other bool `long:"other" description:"Other"` + } + + p := NewParser(&opts, Default) + c, _ := p.AddCommand("command", "Short", "Long", &cmd) + + opt := c.FindOptionByLongName("other") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "other") + + opt = c.FindOptionByLongName("testing") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "testing") +} + +func TestSubCommandFindOptionByShortFlag(t *testing.T) { + var opts struct { + Testing bool `short:"t" description:"Testing"` + } + + var cmd struct { + Other bool `short:"o" description:"Other"` + } + + p := NewParser(&opts, Default) + c, _ := p.AddCommand("command", "Short", "Long", &cmd) + + opt := c.FindOptionByShortName('o') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 'o' { + t.Errorf("Expected 'o', but got %v", opt.ShortName) + } + + opt = c.FindOptionByShortName('t') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 't' { + t.Errorf("Expected 'o', but got %v", opt.ShortName) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/completion.go b/vendor/github.com/jessevdk/go-flags/completion.go new file mode 100644 index 00000000..7a7a08b9 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/completion.go @@ -0,0 +1,309 @@ +package flags + +import ( + "fmt" + "path/filepath" + "reflect" + "sort" + "strings" + "unicode/utf8" +) + +// Completion is a type containing information of a completion. +type Completion struct { + // The completed item + Item string + + // A description of the completed item (optional) + Description string +} + +type completions []Completion + +func (c completions) Len() int { + return len(c) +} + +func (c completions) Less(i, j int) bool { + return c[i].Item < c[j].Item +} + +func (c completions) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +// Completer is an interface which can be implemented by types +// to provide custom command line argument completion. +type Completer interface { + // Complete receives a prefix representing a (partial) value + // for its type and should provide a list of possible valid + // completions. + Complete(match string) []Completion +} + +type completion struct { + parser *Parser +} + +// Filename is a string alias which provides filename completion. +type Filename string + +func completionsWithoutDescriptions(items []string) []Completion { + ret := make([]Completion, len(items)) + + for i, v := range items { + ret[i].Item = v + } + + return ret +} + +// Complete returns a list of existing files with the given +// prefix. +func (f *Filename) Complete(match string) []Completion { + ret, _ := filepath.Glob(match + "*") + return completionsWithoutDescriptions(ret) +} + +func (c *completion) skipPositional(s *parseState, n int) { + if n >= len(s.positional) { + s.positional = nil + } else { + s.positional = s.positional[n:] + } +} + +func (c *completion) completeOptionNames(s *parseState, prefix string, match string, short bool) []Completion { + if short && len(match) != 0 { + return []Completion{ + Completion{ + Item: prefix + match, + }, + } + } + + var results []Completion + repeats := map[string]bool{} + + for name, opt := range s.lookup.longNames { + if strings.HasPrefix(name, match) && !opt.Hidden { + results = append(results, Completion{ + Item: defaultLongOptDelimiter + name, + Description: opt.Description, + }) + + if short { + repeats[string(opt.ShortName)] = true + } + } + } + + if short { + for name, opt := range s.lookup.shortNames { + if _, exist := repeats[name]; !exist && strings.HasPrefix(name, match) && !opt.Hidden { + results = append(results, Completion{ + Item: string(defaultShortOptDelimiter) + name, + Description: opt.Description, + }) + } + } + } + + return results +} + +func (c *completion) completeNamesForLongPrefix(s *parseState, prefix string, match string) []Completion { + return c.completeOptionNames(s, prefix, match, false) +} + +func (c *completion) completeNamesForShortPrefix(s *parseState, prefix string, match string) []Completion { + return c.completeOptionNames(s, prefix, match, true) +} + +func (c *completion) completeCommands(s *parseState, match string) []Completion { + n := make([]Completion, 0, len(s.command.commands)) + + for _, cmd := range s.command.commands { + if cmd.data != c && strings.HasPrefix(cmd.Name, match) { + n = append(n, Completion{ + Item: cmd.Name, + Description: cmd.ShortDescription, + }) + } + } + + return n +} + +func (c *completion) completeValue(value reflect.Value, prefix string, match string) []Completion { + if value.Kind() == reflect.Slice { + value = reflect.New(value.Type().Elem()) + } + i := value.Interface() + + var ret []Completion + + if cmp, ok := i.(Completer); ok { + ret = cmp.Complete(match) + } else if value.CanAddr() { + if cmp, ok = value.Addr().Interface().(Completer); ok { + ret = cmp.Complete(match) + } + } + + for i, v := range ret { + ret[i].Item = prefix + v.Item + } + + return ret +} + +func (c *completion) complete(args []string) []Completion { + if len(args) == 0 { + args = []string{""} + } + + s := &parseState{ + args: args, + } + + c.parser.fillParseState(s) + + var opt *Option + + for len(s.args) > 1 { + arg := s.pop() + + if (c.parser.Options&PassDoubleDash) != None && arg == "--" { + opt = nil + c.skipPositional(s, len(s.args)-1) + + break + } + + if argumentIsOption(arg) { + prefix, optname, islong := stripOptionPrefix(arg) + optname, _, argument := splitOption(prefix, optname, islong) + + if argument == nil { + var o *Option + canarg := true + + if islong { + o = s.lookup.longNames[optname] + } else { + for i, r := range optname { + sname := string(r) + o = s.lookup.shortNames[sname] + + if o == nil { + break + } + + if i == 0 && o.canArgument() && len(optname) != len(sname) { + canarg = false + break + } + } + } + + if o == nil && (c.parser.Options&PassAfterNonOption) != None { + opt = nil + c.skipPositional(s, len(s.args)-1) + + break + } else if o != nil && o.canArgument() && !o.OptionalArgument && canarg { + if len(s.args) > 1 { + s.pop() + } else { + opt = o + } + } + } + } else { + if len(s.positional) > 0 { + if !s.positional[0].isRemaining() { + // Don't advance beyond a remaining positional arg (because + // it consumes all subsequent args). + s.positional = s.positional[1:] + } + } else if cmd, ok := s.lookup.commands[arg]; ok { + cmd.fillParseState(s) + } + + opt = nil + } + } + + lastarg := s.args[len(s.args)-1] + var ret []Completion + + if opt != nil { + // Completion for the argument of 'opt' + ret = c.completeValue(opt.value, "", lastarg) + } else if argumentStartsOption(lastarg) { + // Complete the option + prefix, optname, islong := stripOptionPrefix(lastarg) + optname, split, argument := splitOption(prefix, optname, islong) + + if argument == nil && !islong { + rname, n := utf8.DecodeRuneInString(optname) + sname := string(rname) + + if opt := s.lookup.shortNames[sname]; opt != nil && opt.canArgument() { + ret = c.completeValue(opt.value, prefix+sname, optname[n:]) + } else { + ret = c.completeNamesForShortPrefix(s, prefix, optname) + } + } else if argument != nil { + if islong { + opt = s.lookup.longNames[optname] + } else { + opt = s.lookup.shortNames[optname] + } + + if opt != nil { + ret = c.completeValue(opt.value, prefix+optname+split, *argument) + } + } else if islong { + ret = c.completeNamesForLongPrefix(s, prefix, optname) + } else { + ret = c.completeNamesForShortPrefix(s, prefix, optname) + } + } else if len(s.positional) > 0 { + // Complete for positional argument + ret = c.completeValue(s.positional[0].value, "", lastarg) + } else if len(s.command.commands) > 0 { + // Complete for command + ret = c.completeCommands(s, lastarg) + } + + sort.Sort(completions(ret)) + return ret +} + +func (c *completion) print(items []Completion, showDescriptions bool) { + if showDescriptions && len(items) > 1 { + maxl := 0 + + for _, v := range items { + if len(v.Item) > maxl { + maxl = len(v.Item) + } + } + + for _, v := range items { + fmt.Printf("%s", v.Item) + + if len(v.Description) > 0 { + fmt.Printf("%s # %s", strings.Repeat(" ", maxl-len(v.Item)), v.Description) + } + + fmt.Printf("\n") + } + } else { + for _, v := range items { + fmt.Println(v.Item) + } + } +} diff --git a/vendor/github.com/jessevdk/go-flags/completion_test.go b/vendor/github.com/jessevdk/go-flags/completion_test.go new file mode 100644 index 00000000..26f70e42 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/completion_test.go @@ -0,0 +1,315 @@ +package flags + +import ( + "bytes" + "io" + "os" + "path" + "path/filepath" + "reflect" + "runtime" + "strings" + "testing" +) + +type TestComplete struct { +} + +func (t *TestComplete) Complete(match string) []Completion { + options := []string{ + "hello world", + "hello universe", + "hello multiverse", + } + + ret := make([]Completion, 0, len(options)) + + for _, o := range options { + if strings.HasPrefix(o, match) { + ret = append(ret, Completion{ + Item: o, + }) + } + } + + return ret +} + +var completionTestOptions struct { + Verbose bool `short:"v" long:"verbose" description:"Verbose messages"` + Debug bool `short:"d" long:"debug" description:"Enable debug"` + Info bool `short:"i" description:"Display info"` + Version bool `long:"version" description:"Show version"` + Required bool `long:"required" required:"true" description:"This is required"` + Hidden bool `long:"hidden" hidden:"true" description:"This is hidden"` + + AddCommand struct { + Positional struct { + Filename Filename + } `positional-args:"yes"` + } `command:"add" description:"add an item"` + + AddMultiCommand struct { + Positional struct { + Filename []Filename + } `positional-args:"yes"` + Extra []Filename `short:"f"` + } `command:"add-multi" description:"add multiple items"` + + AddMultiCommandFlag struct { + Files []Filename `short:"f"` + } `command:"add-multi-flag" description:"add multiple items via flags"` + + RemoveCommand struct { + Other bool `short:"o"` + File Filename `short:"f" long:"filename"` + } `command:"rm" description:"remove an item"` + + RenameCommand struct { + Completed TestComplete `short:"c" long:"completed"` + } `command:"rename" description:"rename an item"` +} + +type completionTest struct { + Args []string + Completed []string + ShowDescriptions bool +} + +var completionTests []completionTest + +func init() { + _, sourcefile, _, _ := runtime.Caller(0) + completionTestSourcedir := filepath.Join(filepath.SplitList(path.Dir(sourcefile))...) + + completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")} + + completionTests = []completionTest{ + { + // Short names + []string{"-"}, + []string{"--debug", "--required", "--verbose", "--version", "-i"}, + false, + }, + + { + // Short names full + []string{"-i"}, + []string{"-i"}, + false, + }, + + { + // Short names concatenated + []string{"-dv"}, + []string{"-dv"}, + false, + }, + + { + // Long names + []string{"--"}, + []string{"--debug", "--required", "--verbose", "--version"}, + false, + }, + + { + // Long names with descriptions + []string{"--"}, + []string{ + "--debug # Enable debug", + "--required # This is required", + "--verbose # Verbose messages", + "--version # Show version", + }, + true, + }, + + { + // Long names partial + []string{"--ver"}, + []string{"--verbose", "--version"}, + false, + }, + + { + // Commands + []string{""}, + []string{"add", "add-multi", "add-multi-flag", "rename", "rm"}, + false, + }, + + { + // Commands with descriptions + []string{""}, + []string{ + "add # add an item", + "add-multi # add multiple items", + "add-multi-flag # add multiple items via flags", + "rename # rename an item", + "rm # remove an item", + }, + true, + }, + + { + // Commands partial + []string{"r"}, + []string{"rename", "rm"}, + false, + }, + + { + // Positional filename + []string{"add", filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Multiple positional filename (1 arg) + []string{"add-multi", filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + { + // Multiple positional filename (2 args) + []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + { + // Multiple positional filename (3 args) + []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag filename + []string{"rm", "-f", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag short concat last filename + []string{"rm", "-of", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Flag concat filename + []string{"rm", "-f" + path.Join(completionTestSourcedir, "completion")}, + []string{"-f" + completionTestFilename[0], "-f" + completionTestFilename[1]}, + false, + }, + + { + // Flag equal concat filename + []string{"rm", "-f=" + path.Join(completionTestSourcedir, "completion")}, + []string{"-f=" + completionTestFilename[0], "-f=" + completionTestFilename[1]}, + false, + }, + + { + // Flag concat long filename + []string{"rm", "--filename=" + path.Join(completionTestSourcedir, "completion")}, + []string{"--filename=" + completionTestFilename[0], "--filename=" + completionTestFilename[1]}, + false, + }, + + { + // Flag long filename + []string{"rm", "--filename", path.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + + { + // Custom completed + []string{"rename", "-c", "hello un"}, + []string{"hello universe"}, + false, + }, + { + // Multiple flag filename + []string{"add-multi-flag", "-f", filepath.Join(completionTestSourcedir, "completion")}, + completionTestFilename, + false, + }, + } +} + +func TestCompletion(t *testing.T) { + p := NewParser(&completionTestOptions, Default) + c := &completion{parser: p} + + for _, test := range completionTests { + if test.ShowDescriptions { + continue + } + + ret := c.complete(test.Args) + items := make([]string, len(ret)) + + for i, v := range ret { + items[i] = v.Item + } + + if !reflect.DeepEqual(items, test.Completed) { + t.Errorf("Args: %#v, %#v\n Expected: %#v\n Got: %#v", test.Args, test.ShowDescriptions, test.Completed, items) + } + } +} + +func TestParserCompletion(t *testing.T) { + for _, test := range completionTests { + if test.ShowDescriptions { + os.Setenv("GO_FLAGS_COMPLETION", "verbose") + } else { + os.Setenv("GO_FLAGS_COMPLETION", "1") + } + + tmp := os.Stdout + + r, w, _ := os.Pipe() + os.Stdout = w + + out := make(chan string) + + go func() { + var buf bytes.Buffer + + io.Copy(&buf, r) + + out <- buf.String() + }() + + p := NewParser(&completionTestOptions, None) + + p.CompletionHandler = func(items []Completion) { + comp := &completion{parser: p} + comp.print(items, test.ShowDescriptions) + } + + _, err := p.ParseArgs(test.Args) + + w.Close() + + os.Stdout = tmp + + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + got := strings.Split(strings.Trim(<-out, "\n"), "\n") + + if !reflect.DeepEqual(got, test.Completed) { + t.Errorf("Expected: %#v\nGot: %#v", test.Completed, got) + } + } + + os.Setenv("GO_FLAGS_COMPLETION", "") +} diff --git a/vendor/github.com/jessevdk/go-flags/convert.go b/vendor/github.com/jessevdk/go-flags/convert.go new file mode 100644 index 00000000..984aac89 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/convert.go @@ -0,0 +1,348 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "time" +) + +// Marshaler is the interface implemented by types that can marshal themselves +// to a string representation of the flag. +type Marshaler interface { + // MarshalFlag marshals a flag value to its string representation. + MarshalFlag() (string, error) +} + +// Unmarshaler is the interface implemented by types that can unmarshal a flag +// argument to themselves. The provided value is directly passed from the +// command line. +type Unmarshaler interface { + // UnmarshalFlag unmarshals a string value representation to the flag + // value (which therefore needs to be a pointer receiver). + UnmarshalFlag(value string) error +} + +func getBase(options multiTag, base int) (int, error) { + sbase := options.Get("base") + + var err error + var ivbase int64 + + if sbase != "" { + ivbase, err = strconv.ParseInt(sbase, 10, 32) + base = int(ivbase) + } + + return base, err +} + +func convertMarshal(val reflect.Value) (bool, string, error) { + // Check first for the Marshaler interface + if val.Type().NumMethod() > 0 && val.CanInterface() { + if marshaler, ok := val.Interface().(Marshaler); ok { + ret, err := marshaler.MarshalFlag() + return true, ret, err + } + } + + return false, "", nil +} + +func convertToString(val reflect.Value, options multiTag) (string, error) { + if ok, ret, err := convertMarshal(val); ok { + return ret, err + } + + tp := val.Type() + + // Support for time.Duration + if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() { + stringer := val.Interface().(fmt.Stringer) + return stringer.String(), nil + } + + switch tp.Kind() { + case reflect.String: + return val.String(), nil + case reflect.Bool: + if val.Bool() { + return "true", nil + } + + return "false", nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + base, err := getBase(options, 10) + + if err != nil { + return "", err + } + + return strconv.FormatInt(val.Int(), base), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + base, err := getBase(options, 10) + + if err != nil { + return "", err + } + + return strconv.FormatUint(val.Uint(), base), nil + case reflect.Float32, reflect.Float64: + return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil + case reflect.Slice: + if val.Len() == 0 { + return "", nil + } + + ret := "[" + + for i := 0; i < val.Len(); i++ { + if i != 0 { + ret += ", " + } + + item, err := convertToString(val.Index(i), options) + + if err != nil { + return "", err + } + + ret += item + } + + return ret + "]", nil + case reflect.Map: + ret := "{" + + for i, key := range val.MapKeys() { + if i != 0 { + ret += ", " + } + + keyitem, err := convertToString(key, options) + + if err != nil { + return "", err + } + + item, err := convertToString(val.MapIndex(key), options) + + if err != nil { + return "", err + } + + ret += keyitem + ":" + item + } + + return ret + "}", nil + case reflect.Ptr: + return convertToString(reflect.Indirect(val), options) + case reflect.Interface: + if !val.IsNil() { + return convertToString(val.Elem(), options) + } + } + + return "", nil +} + +func convertUnmarshal(val string, retval reflect.Value) (bool, error) { + if retval.Type().NumMethod() > 0 && retval.CanInterface() { + if unmarshaler, ok := retval.Interface().(Unmarshaler); ok { + if retval.IsNil() { + retval.Set(reflect.New(retval.Type().Elem())) + + // Re-assign from the new value + unmarshaler = retval.Interface().(Unmarshaler) + } + + return true, unmarshaler.UnmarshalFlag(val) + } + } + + if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() { + return convertUnmarshal(val, retval.Addr()) + } + + if retval.Type().Kind() == reflect.Interface && !retval.IsNil() { + return convertUnmarshal(val, retval.Elem()) + } + + return false, nil +} + +func convert(val string, retval reflect.Value, options multiTag) error { + if ok, err := convertUnmarshal(val, retval); ok { + return err + } + + tp := retval.Type() + + // Support for time.Duration + if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() { + parsed, err := time.ParseDuration(val) + + if err != nil { + return err + } + + retval.SetInt(int64(parsed)) + return nil + } + + switch tp.Kind() { + case reflect.String: + retval.SetString(val) + case reflect.Bool: + if val == "" { + retval.SetBool(true) + } else { + b, err := strconv.ParseBool(val) + + if err != nil { + return err + } + + retval.SetBool(b) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + base, err := getBase(options, 10) + + if err != nil { + return err + } + + parsed, err := strconv.ParseInt(val, base, tp.Bits()) + + if err != nil { + return err + } + + retval.SetInt(parsed) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + base, err := getBase(options, 10) + + if err != nil { + return err + } + + parsed, err := strconv.ParseUint(val, base, tp.Bits()) + + if err != nil { + return err + } + + retval.SetUint(parsed) + case reflect.Float32, reflect.Float64: + parsed, err := strconv.ParseFloat(val, tp.Bits()) + + if err != nil { + return err + } + + retval.SetFloat(parsed) + case reflect.Slice: + elemtp := tp.Elem() + + elemvalptr := reflect.New(elemtp) + elemval := reflect.Indirect(elemvalptr) + + if err := convert(val, elemval, options); err != nil { + return err + } + + retval.Set(reflect.Append(retval, elemval)) + case reflect.Map: + parts := strings.SplitN(val, ":", 2) + + key := parts[0] + var value string + + if len(parts) == 2 { + value = parts[1] + } + + keytp := tp.Key() + keyval := reflect.New(keytp) + + if err := convert(key, keyval, options); err != nil { + return err + } + + valuetp := tp.Elem() + valueval := reflect.New(valuetp) + + if err := convert(value, valueval, options); err != nil { + return err + } + + if retval.IsNil() { + retval.Set(reflect.MakeMap(tp)) + } + + retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval)) + case reflect.Ptr: + if retval.IsNil() { + retval.Set(reflect.New(retval.Type().Elem())) + } + + return convert(val, reflect.Indirect(retval), options) + case reflect.Interface: + if !retval.IsNil() { + return convert(val, retval.Elem(), options) + } + } + + return nil +} + +func isPrint(s string) bool { + for _, c := range s { + if !strconv.IsPrint(c) { + return false + } + } + + return true +} + +func quoteIfNeeded(s string) string { + if !isPrint(s) { + return strconv.Quote(s) + } + + return s +} + +func quoteIfNeededV(s []string) []string { + ret := make([]string, len(s)) + + for i, v := range s { + ret[i] = quoteIfNeeded(v) + } + + return ret +} + +func quoteV(s []string) []string { + ret := make([]string, len(s)) + + for i, v := range s { + ret[i] = strconv.Quote(v) + } + + return ret +} + +func unquoteIfPossible(s string) (string, error) { + if len(s) == 0 || s[0] != '"' { + return s, nil + } + + return strconv.Unquote(s) +} diff --git a/vendor/github.com/jessevdk/go-flags/convert_test.go b/vendor/github.com/jessevdk/go-flags/convert_test.go new file mode 100644 index 00000000..ef131dc8 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/convert_test.go @@ -0,0 +1,159 @@ +package flags + +import ( + "testing" + "time" +) + +func expectConvert(t *testing.T, o *Option, expected string) { + s, err := convertToString(o.value, o.tag) + + if err != nil { + t.Errorf("Unexpected error: %v", err) + return + } + + assertString(t, s, expected) +} + +func TestConvertToString(t *testing.T) { + d, _ := time.ParseDuration("1h2m4s") + + var opts = struct { + String string `long:"string"` + + Int int `long:"int"` + Int8 int8 `long:"int8"` + Int16 int16 `long:"int16"` + Int32 int32 `long:"int32"` + Int64 int64 `long:"int64"` + + Uint uint `long:"uint"` + Uint8 uint8 `long:"uint8"` + Uint16 uint16 `long:"uint16"` + Uint32 uint32 `long:"uint32"` + Uint64 uint64 `long:"uint64"` + + Float32 float32 `long:"float32"` + Float64 float64 `long:"float64"` + + Duration time.Duration `long:"duration"` + + Bool bool `long:"bool"` + + IntSlice []int `long:"int-slice"` + IntFloatMap map[int]float64 `long:"int-float-map"` + + PtrBool *bool `long:"ptr-bool"` + Interface interface{} `long:"interface"` + + Int32Base int32 `long:"int32-base" base:"16"` + Uint32Base uint32 `long:"uint32-base" base:"16"` + }{ + "string", + + -2, + -1, + 0, + 1, + 2, + + 1, + 2, + 3, + 4, + 5, + + 1.2, + -3.4, + + d, + true, + + []int{-3, 4, -2}, + map[int]float64{-2: 4.5}, + + new(bool), + float32(5.2), + + -5823, + 4232, + } + + p := NewNamedParser("test", Default) + grp, _ := p.AddGroup("test group", "", &opts) + + expects := []string{ + "string", + "-2", + "-1", + "0", + "1", + "2", + + "1", + "2", + "3", + "4", + "5", + + "1.2", + "-3.4", + + "1h2m4s", + "true", + + "[-3, 4, -2]", + "{-2:4.5}", + + "false", + "5.2", + + "-16bf", + "1088", + } + + for i, v := range grp.Options() { + expectConvert(t, v, expects[i]) + } +} + +func TestConvertToStringInvalidIntBase(t *testing.T) { + var opts = struct { + Int int `long:"int" base:"no"` + }{ + 2, + } + + p := NewNamedParser("test", Default) + grp, _ := p.AddGroup("test group", "", &opts) + o := grp.Options()[0] + + _, err := convertToString(o.value, o.tag) + + if err != nil { + err = newErrorf(ErrMarshal, "%v", err) + } + + assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax") +} + +func TestConvertToStringInvalidUintBase(t *testing.T) { + var opts = struct { + Uint uint `long:"uint" base:"no"` + }{ + 2, + } + + p := NewNamedParser("test", Default) + grp, _ := p.AddGroup("test group", "", &opts) + o := grp.Options()[0] + + _, err := convertToString(o.value, o.tag) + + if err != nil { + err = newErrorf(ErrMarshal, "%v", err) + } + + assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax") +} diff --git a/vendor/github.com/jessevdk/go-flags/error.go b/vendor/github.com/jessevdk/go-flags/error.go new file mode 100644 index 00000000..05528d8d --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/error.go @@ -0,0 +1,134 @@ +package flags + +import ( + "fmt" +) + +// ErrorType represents the type of error. +type ErrorType uint + +const ( + // ErrUnknown indicates a generic error. + ErrUnknown ErrorType = iota + + // ErrExpectedArgument indicates that an argument was expected. + ErrExpectedArgument + + // ErrUnknownFlag indicates an unknown flag. + ErrUnknownFlag + + // ErrUnknownGroup indicates an unknown group. + ErrUnknownGroup + + // ErrMarshal indicates a marshalling error while converting values. + ErrMarshal + + // ErrHelp indicates that the built-in help was shown (the error + // contains the help message). + ErrHelp + + // ErrNoArgumentForBool indicates that an argument was given for a + // boolean flag (which don't not take any arguments). + ErrNoArgumentForBool + + // ErrRequired indicates that a required flag was not provided. + ErrRequired + + // ErrShortNameTooLong indicates that a short flag name was specified, + // longer than one character. + ErrShortNameTooLong + + // ErrDuplicatedFlag indicates that a short or long flag has been + // defined more than once + ErrDuplicatedFlag + + // ErrTag indicates an error while parsing flag tags. + ErrTag + + // ErrCommandRequired indicates that a command was required but not + // specified + ErrCommandRequired + + // ErrUnknownCommand indicates that an unknown command was specified. + ErrUnknownCommand + + // ErrInvalidChoice indicates an invalid option value which only allows + // a certain number of choices. + ErrInvalidChoice + + // ErrInvalidTag indicates an invalid tag or invalid use of an existing tag + ErrInvalidTag +) + +func (e ErrorType) String() string { + switch e { + case ErrUnknown: + return "unknown" + case ErrExpectedArgument: + return "expected argument" + case ErrUnknownFlag: + return "unknown flag" + case ErrUnknownGroup: + return "unknown group" + case ErrMarshal: + return "marshal" + case ErrHelp: + return "help" + case ErrNoArgumentForBool: + return "no argument for bool" + case ErrRequired: + return "required" + case ErrShortNameTooLong: + return "short name too long" + case ErrDuplicatedFlag: + return "duplicated flag" + case ErrTag: + return "tag" + case ErrCommandRequired: + return "command required" + case ErrUnknownCommand: + return "unknown command" + case ErrInvalidChoice: + return "invalid choice" + case ErrInvalidTag: + return "invalid tag" + } + + return "unrecognized error type" +} + +// Error represents a parser error. The error returned from Parse is of this +// type. The error contains both a Type and Message. +type Error struct { + // The type of error + Type ErrorType + + // The error message + Message string +} + +// Error returns the error's message +func (e *Error) Error() string { + return e.Message +} + +func newError(tp ErrorType, message string) *Error { + return &Error{ + Type: tp, + Message: message, + } +} + +func newErrorf(tp ErrorType, format string, args ...interface{}) *Error { + return newError(tp, fmt.Sprintf(format, args...)) +} + +func wrapError(err error) *Error { + ret, ok := err.(*Error) + + if !ok { + return newError(ErrUnknown, err.Error()) + } + + return ret +} diff --git a/vendor/github.com/jessevdk/go-flags/example_test.go b/vendor/github.com/jessevdk/go-flags/example_test.go new file mode 100644 index 00000000..4321ed8e --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/example_test.go @@ -0,0 +1,110 @@ +// Example of use of the flags package. +package flags + +import ( + "fmt" + "os/exec" +) + +func Example() { + var opts struct { + // Slice of bool will append 'true' each time the option + // is encountered (can be set multiple times, like -vvv) + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + + // Example of automatic marshalling to desired type (uint) + Offset uint `long:"offset" description:"Offset"` + + // Example of a callback, called each time the option is found. + Call func(string) `short:"c" description:"Call phone number"` + + // Example of a required flag + Name string `short:"n" long:"name" description:"A name" required:"true"` + + // Example of a value name + File string `short:"f" long:"file" description:"A file" value-name:"FILE"` + + // Example of a pointer + Ptr *int `short:"p" description:"A pointer to an integer"` + + // Example of a slice of strings + StringSlice []string `short:"s" description:"A slice of strings"` + + // Example of a slice of pointers + PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + + // Example of a map + IntMap map[string]int `long:"intmap" description:"A map from string to int"` + + // Example of a filename (useful for completion) + Filename Filename `long:"filename" description:"A filename"` + + // Example of positional arguments + Args struct { + ID string + Num int + Rest []string + } `positional-args:"yes" required:"yes"` + } + + // Callback which will invoke callto: to call a number. + // Note that this works just on OS X (and probably only with + // Skype) but it shows the idea. + opts.Call = func(num string) { + cmd := exec.Command("open", "callto:"+num) + cmd.Start() + cmd.Process.Release() + } + + // Make some fake arguments to parse. + args := []string{ + "-vv", + "--offset=5", + "-n", "Me", + "-p", "3", + "-s", "hello", + "-s", "world", + "--ptrslice", "hello", + "--ptrslice", "world", + "--intmap", "a:1", + "--intmap", "b:5", + "--filename", "hello.go", + "id", + "10", + "remaining1", + "remaining2", + } + + // Parse flags from `args'. Note that here we use flags.ParseArgs for + // the sake of making a working example. Normally, you would simply use + // flags.Parse(&opts) which uses os.Args + _, err := ParseArgs(&opts, args) + + if err != nil { + panic(err) + } + + fmt.Printf("Verbosity: %v\n", opts.Verbose) + fmt.Printf("Offset: %d\n", opts.Offset) + fmt.Printf("Name: %s\n", opts.Name) + fmt.Printf("Ptr: %d\n", *opts.Ptr) + fmt.Printf("StringSlice: %v\n", opts.StringSlice) + fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) + fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) + fmt.Printf("Filename: %v\n", opts.Filename) + fmt.Printf("Args.ID: %s\n", opts.Args.ID) + fmt.Printf("Args.Num: %d\n", opts.Args.Num) + fmt.Printf("Args.Rest: %v\n", opts.Args.Rest) + + // Output: Verbosity: [true true] + // Offset: 5 + // Name: Me + // Ptr: 3 + // StringSlice: [hello world] + // PtrSlice: [hello world] + // IntMap: [a:1 b:5] + // Filename: hello.go + // Args.ID: id + // Args.Num: 10 + // Args.Rest: [remaining1 remaining2] +} diff --git a/vendor/github.com/jessevdk/go-flags/examples/add.go b/vendor/github.com/jessevdk/go-flags/examples/add.go new file mode 100644 index 00000000..57d8f232 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/examples/add.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +type AddCommand struct { + All bool `short:"a" long:"all" description:"Add all files"` +} + +var addCommand AddCommand + +func (x *AddCommand) Execute(args []string) error { + fmt.Printf("Adding (all=%v): %#v\n", x.All, args) + return nil +} + +func init() { + parser.AddCommand("add", + "Add a file", + "The add command adds a file to the repository. Use -a to add all files.", + &addCommand) +} diff --git a/vendor/github.com/jessevdk/go-flags/examples/bash-completion b/vendor/github.com/jessevdk/go-flags/examples/bash-completion new file mode 100644 index 00000000..974f52ad --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/examples/bash-completion @@ -0,0 +1,9 @@ +_examples() { + args=("${COMP_WORDS[@]:1:$COMP_CWORD}") + + local IFS=$'\n' + COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}")) + return 1 +} + +complete -F _examples examples diff --git a/vendor/github.com/jessevdk/go-flags/examples/main.go b/vendor/github.com/jessevdk/go-flags/examples/main.go new file mode 100644 index 00000000..632c3315 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/examples/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "errors" + "fmt" + "github.com/jessevdk/go-flags" + "os" + "strconv" + "strings" +) + +type EditorOptions struct { + Input flags.Filename `short:"i" long:"input" description:"Input file" default:"-"` + Output flags.Filename `short:"o" long:"output" description:"Output file" default:"-"` +} + +type Point struct { + X, Y int +} + +func (p *Point) UnmarshalFlag(value string) error { + parts := strings.Split(value, ",") + + if len(parts) != 2 { + return errors.New("expected two numbers separated by a ,") + } + + x, err := strconv.ParseInt(parts[0], 10, 32) + + if err != nil { + return err + } + + y, err := strconv.ParseInt(parts[1], 10, 32) + + if err != nil { + return err + } + + p.X = int(x) + p.Y = int(y) + + return nil +} + +func (p Point) MarshalFlag() (string, error) { + return fmt.Sprintf("%d,%d", p.X, p.Y), nil +} + +type Options struct { + // Example of verbosity with level + Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` + + // Example of optional value + User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"` + + // Example of map with multiple default values + Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"` + + // Example of option group + Editor EditorOptions `group:"Editor Options"` + + // Example of custom type Marshal/Unmarshal + Point Point `long:"point" description:"A x,y point" default:"1,2"` +} + +var options Options + +var parser = flags.NewParser(&options, flags.Default) + +func main() { + if _, err := parser.Parse(); err != nil { + if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp { + os.Exit(0) + } else { + os.Exit(1) + } + } +} diff --git a/vendor/github.com/jessevdk/go-flags/examples/rm.go b/vendor/github.com/jessevdk/go-flags/examples/rm.go new file mode 100644 index 00000000..c9c1dd03 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/examples/rm.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" +) + +type RmCommand struct { + Force bool `short:"f" long:"force" description:"Force removal of files"` +} + +var rmCommand RmCommand + +func (x *RmCommand) Execute(args []string) error { + fmt.Printf("Removing (force=%v): %#v\n", x.Force, args) + return nil +} + +func init() { + parser.AddCommand("rm", + "Remove a file", + "The rm command removes a file to the repository. Use -f to force removal of files.", + &rmCommand) +} diff --git a/vendor/github.com/jessevdk/go-flags/flags.go b/vendor/github.com/jessevdk/go-flags/flags.go new file mode 100644 index 00000000..889762d1 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/flags.go @@ -0,0 +1,258 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package flags provides an extensive command line option parser. +The flags package is similar in functionality to the go built-in flag package +but provides more options and uses reflection to provide a convenient and +succinct way of specifying command line options. + + +Supported features + +The following features are supported in go-flags: + + Options with short names (-v) + Options with long names (--verbose) + Options with and without arguments (bool v.s. other type) + Options with optional arguments and default values + Option default values from ENVIRONMENT_VARIABLES, including slice and map values + Multiple option groups each containing a set of options + Generate and print well-formatted help message + Passing remaining command line arguments after -- (optional) + Ignoring unknown command line options (optional) + Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification + Supports multiple short options -aux + Supports all primitive go types (string, int{8..64}, uint{8..64}, float) + Supports same option multiple times (can store in slice or last option counts) + Supports maps + Supports function callbacks + Supports namespaces for (nested) option groups + +Additional features specific to Windows: + Options with short names (/v) + Options with long names (/verbose) + Windows-style options with arguments use a colon as the delimiter + Modify generated help message with Windows-style / options + Windows style options can be disabled at build time using the "forceposix" + build tag + + +Basic usage + +The flags package uses structs, reflection and struct field tags +to allow users to specify command line options. This results in very simple +and concise specification of your application options. For example: + + type Options struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + } + +This specifies one option with a short name -v and a long name --verbose. +When either -v or --verbose is found on the command line, a 'true' value +will be appended to the Verbose field. e.g. when specifying -vvv, the +resulting value of Verbose will be {[true, true, true]}. + +Slice options work exactly the same as primitive type options, except that +whenever the option is encountered, a value is appended to the slice. + +Map options from string to primitive type are also supported. On the command +line, you specify the value for such an option as key:value. For example + + type Options struct { + AuthorInfo string[string] `short:"a"` + } + +Then, the AuthorInfo map can be filled with something like +-a name:Jesse -a "surname:van den Kieboom". + +Finally, for full control over the conversion between command line argument +values and options, user defined types can choose to implement the Marshaler +and Unmarshaler interfaces. + + +Available field tags + +The following is a list of tags for struct fields supported by go-flags: + + short: the short name of the option (single character) + long: the long name of the option + required: if non empty, makes the option required to appear on the command + line. If a required option is not present, the parser will + return ErrRequired (optional) + description: the description of the option (optional) + long-description: the long description of the option. Currently only + displayed in generated man pages (optional) + no-flag: if non-empty, this field is ignored as an option (optional) + + optional: if non-empty, makes the argument of the option optional. When an + argument is optional it can only be specified using + --option=argument (optional) + optional-value: the value of an optional option when the option occurs + without an argument. This tag can be specified multiple + times in the case of maps or slices (optional) + default: the default value of an option. This tag can be specified + multiple times in the case of slices or maps (optional) + default-mask: when specified, this value will be displayed in the help + instead of the actual default value. This is useful + mostly for hiding otherwise sensitive information from + showing up in the help. If default-mask takes the special + value "-", then no default value will be shown at all + (optional) + env: the default value of the option is overridden from the + specified environment variable, if one has been defined. + (optional) + env-delim: the 'env' default value from environment is split into + multiple values with the given delimiter string, use with + slices and maps (optional) + value-name: the name of the argument value (to be shown in the help) + (optional) + choice: limits the values for an option to a set of values. + This tag can be specified multiple times (optional) + hidden: if non-empty, the option is not visible in the help or man page. + + base: a base (radix) used to convert strings to integer values, the + default base is 10 (i.e. decimal) (optional) + + ini-name: the explicit ini option name (optional) + no-ini: if non-empty this field is ignored as an ini option + (optional) + + group: when specified on a struct field, makes the struct + field a separate group with the given name (optional) + namespace: when specified on a group struct field, the namespace + gets prepended to every option's long name and + subgroup's namespace of this group, separated by + the parser's namespace delimiter (optional) + command: when specified on a struct field, makes the struct + field a (sub)command with the given name (optional) + subcommands-optional: when specified on a command struct field, makes + any subcommands of that command optional (optional) + alias: when specified on a command struct field, adds the + specified name as an alias for the command. Can be + be specified multiple times to add more than one + alias (optional) + positional-args: when specified on a field with a struct type, + uses the fields of that struct to parse remaining + positional command line arguments into (in order + of the fields). If a field has a slice type, + then all remaining arguments will be added to it. + Positional arguments are optional by default, + unless the "required" tag is specified together + with the "positional-args" tag. The "required" tag + can also be set on the individual rest argument + fields, to require only the first N positional + arguments. If the "required" tag is set on the + rest arguments slice, then its value determines + the minimum amount of rest arguments that needs to + be provided (e.g. `required:"2"`) (optional) + positional-arg-name: used on a field in a positional argument struct; name + of the positional argument placeholder to be shown in + the help (optional) + +Either the `short:` tag or the `long:` must be specified to make the field eligible as an +option. + + +Option groups + +Option groups are a simple way to semantically separate your options. All +options in a particular group are shown together in the help under the name +of the group. Namespaces can be used to specify option long names more +precisely and emphasize the options affiliation to their group. + +There are currently three ways to specify option groups. + + 1. Use NewNamedParser specifying the various option groups. + 2. Use AddGroup to add a group to an existing parser. + 3. Add a struct field to the top-level options annotated with the + group:"group-name" tag. + + + +Commands + +The flags package also has basic support for commands. Commands are often +used in monolithic applications that support various commands or actions. +Take git for example, all of the add, commit, checkout, etc. are called +commands. Using commands you can easily separate multiple functions of your +application. + +There are currently two ways to specify a command. + + 1. Use AddCommand on an existing parser. + 2. Add a struct field to your options struct annotated with the + command:"command-name" tag. + +The most common, idiomatic way to implement commands is to define a global +parser instance and implement each command in a separate file. These +command files should define a go init function which calls AddCommand on +the global parser. + +When parsing ends and there is an active command and that command implements +the Commander interface, then its Execute method will be run with the +remaining command line arguments. + +Command structs can have options which become valid to parse after the +command has been specified on the command line, in addition to the options +of all the parent commands. I.e. considering a -v flag on the parser and an +add command, the following are equivalent: + + ./app -v add + ./app add -v + +However, if the -v flag is defined on the add command, then the first of +the two examples above would fail since the -v flag is not defined before +the add command. + + +Completion + +go-flags has builtin support to provide bash completion of flags, commands +and argument values. To use completion, the binary which uses go-flags +can be invoked in a special environment to list completion of the current +command line argument. It should be noted that this `executes` your application, +and it is up to the user to make sure there are no negative side effects (for +example from init functions). + +Setting the environment variable `GO_FLAGS_COMPLETION=1` enables completion +by replacing the argument parsing routine with the completion routine which +outputs completions for the passed arguments. The basic invocation to +complete a set of arguments is therefore: + + GO_FLAGS_COMPLETION=1 ./completion-example arg1 arg2 arg3 + +where `completion-example` is the binary, `arg1` and `arg2` are +the current arguments, and `arg3` (the last argument) is the argument +to be completed. If the GO_FLAGS_COMPLETION is set to "verbose", then +descriptions of possible completion items will also be shown, if there +are more than 1 completion items. + +To use this with bash completion, a simple file can be written which +calls the binary which supports go-flags completion: + + _completion_example() { + # All arguments except the first one + args=("${COMP_WORDS[@]:1:$COMP_CWORD}") + + # Only split on newlines + local IFS=$'\n' + + # Call completion (note that the first element of COMP_WORDS is + # the executable itself) + COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}")) + return 0 + } + + complete -F _completion_example completion-example + +Completion requires the parser option PassDoubleDash and is therefore enforced if the environment variable GO_FLAGS_COMPLETION is set. + +Customized completion for argument values is supported by implementing +the flags.Completer interface for the argument value type. An example +of a type which does so is the flags.Filename type, an alias of string +allowing simple filename completion. A slice or array argument value +whose element type implements flags.Completer will also be completed. +*/ +package flags diff --git a/vendor/github.com/jessevdk/go-flags/group.go b/vendor/github.com/jessevdk/go-flags/group.go new file mode 100644 index 00000000..6133a718 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/group.go @@ -0,0 +1,395 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "errors" + "reflect" + "strings" + "unicode/utf8" + "unsafe" +) + +// ErrNotPointerToStruct indicates that a provided data container is not +// a pointer to a struct. Only pointers to structs are valid data containers +// for options. +var ErrNotPointerToStruct = errors.New("provided data is not a pointer to struct") + +// Group represents an option group. Option groups can be used to logically +// group options together under a description. Groups are only used to provide +// more structure to options both for the user (as displayed in the help message) +// and for you, since groups can be nested. +type Group struct { + // A short description of the group. The + // short description is primarily used in the built-in generated help + // message + ShortDescription string + + // A long description of the group. The long + // description is primarily used to present information on commands + // (Command embeds Group) in the built-in generated help and man pages. + LongDescription string + + // The namespace of the group + Namespace string + + // If true, the group is not displayed in the help or man page + Hidden bool + + // The parent of the group or nil if it has no parent + parent interface{} + + // All the options in the group + options []*Option + + // All the subgroups + groups []*Group + + // Whether the group represents the built-in help group + isBuiltinHelp bool + + data interface{} +} + +type scanHandler func(reflect.Value, *reflect.StructField) (bool, error) + +// AddGroup adds a new group to the command with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the group. +func (g *Group) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { + group := newGroup(shortDescription, longDescription, data) + + group.parent = g + + if err := group.scan(); err != nil { + return nil, err + } + + g.groups = append(g.groups, group) + return group, nil +} + +// Groups returns the list of groups embedded in this group. +func (g *Group) Groups() []*Group { + return g.groups +} + +// Options returns the list of options in this group. +func (g *Group) Options() []*Option { + return g.options +} + +// Find locates the subgroup with the given short description and returns it. +// If no such group can be found Find will return nil. Note that the description +// is matched case insensitively. +func (g *Group) Find(shortDescription string) *Group { + lshortDescription := strings.ToLower(shortDescription) + + var ret *Group + + g.eachGroup(func(gg *Group) { + if gg != g && strings.ToLower(gg.ShortDescription) == lshortDescription { + ret = gg + } + }) + + return ret +} + +func (g *Group) findOption(matcher func(*Option) bool) (option *Option) { + g.eachGroup(func(g *Group) { + for _, opt := range g.options { + if option == nil && matcher(opt) { + option = opt + } + } + }) + + return option +} + +// FindOptionByLongName finds an option that is part of the group, or any of its +// subgroups, by matching its long name (including the option namespace). +func (g *Group) FindOptionByLongName(longName string) *Option { + return g.findOption(func(option *Option) bool { + return option.LongNameWithNamespace() == longName + }) +} + +// FindOptionByShortName finds an option that is part of the group, or any of +// its subgroups, by matching its short name. +func (g *Group) FindOptionByShortName(shortName rune) *Option { + return g.findOption(func(option *Option) bool { + return option.ShortName == shortName + }) +} + +func newGroup(shortDescription string, longDescription string, data interface{}) *Group { + return &Group{ + ShortDescription: shortDescription, + LongDescription: longDescription, + + data: data, + } +} + +func (g *Group) optionByName(name string, namematch func(*Option, string) bool) *Option { + prio := 0 + var retopt *Option + + g.eachGroup(func(g *Group) { + for _, opt := range g.options { + if namematch != nil && namematch(opt, name) && prio < 4 { + retopt = opt + prio = 4 + } + + if name == opt.field.Name && prio < 3 { + retopt = opt + prio = 3 + } + + if name == opt.LongNameWithNamespace() && prio < 2 { + retopt = opt + prio = 2 + } + + if opt.ShortName != 0 && name == string(opt.ShortName) && prio < 1 { + retopt = opt + prio = 1 + } + } + }) + + return retopt +} + +func (g *Group) eachGroup(f func(*Group)) { + f(g) + + for _, gg := range g.groups { + gg.eachGroup(f) + } +} + +func isStringFalsy(s string) bool { + return s == "" || s == "false" || s == "no" || s == "0" +} + +func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error { + stype := realval.Type() + + if sfield != nil { + if ok, err := handler(realval, sfield); err != nil { + return err + } else if ok { + return nil + } + } + + for i := 0; i < stype.NumField(); i++ { + field := stype.Field(i) + + // PkgName is set only for non-exported fields, which we ignore + if field.PkgPath != "" && !field.Anonymous { + continue + } + + mtag := newMultiTag(string(field.Tag)) + + if err := mtag.Parse(); err != nil { + return err + } + + // Skip fields with the no-flag tag + if mtag.Get("no-flag") != "" { + continue + } + + // Dive deep into structs or pointers to structs + kind := field.Type.Kind() + fld := realval.Field(i) + + if kind == reflect.Struct { + if err := g.scanStruct(fld, &field, handler); err != nil { + return err + } + } else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { + flagCountBefore := len(g.options) + len(g.groups) + + if fld.IsNil() { + fld = reflect.New(fld.Type().Elem()) + } + + if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil { + return err + } + + if len(g.options)+len(g.groups) != flagCountBefore { + realval.Field(i).Set(fld) + } + } + + longname := mtag.Get("long") + shortname := mtag.Get("short") + + // Need at least either a short or long name + if longname == "" && shortname == "" && mtag.Get("ini-name") == "" { + continue + } + + short := rune(0) + rc := utf8.RuneCountInString(shortname) + + if rc > 1 { + return newErrorf(ErrShortNameTooLong, + "short names can only be 1 character long, not `%s'", + shortname) + + } else if rc == 1 { + short, _ = utf8.DecodeRuneInString(shortname) + } + + description := mtag.Get("description") + def := mtag.GetMany("default") + + optionalValue := mtag.GetMany("optional-value") + valueName := mtag.Get("value-name") + defaultMask := mtag.Get("default-mask") + + optional := !isStringFalsy(mtag.Get("optional")) + required := !isStringFalsy(mtag.Get("required")) + choices := mtag.GetMany("choice") + hidden := !isStringFalsy(mtag.Get("hidden")) + + option := &Option{ + Description: description, + ShortName: short, + LongName: longname, + Default: def, + EnvDefaultKey: mtag.Get("env"), + EnvDefaultDelim: mtag.Get("env-delim"), + OptionalArgument: optional, + OptionalValue: optionalValue, + Required: required, + ValueName: valueName, + DefaultMask: defaultMask, + Choices: choices, + Hidden: hidden, + + group: g, + + field: field, + value: realval.Field(i), + tag: mtag, + } + + if option.isBool() && option.Default != nil { + return newErrorf(ErrInvalidTag, + "boolean flag `%s' may not have default values, they always default to `false' and can only be turned on", + option.shortAndLongName()) + } + + g.options = append(g.options, option) + } + + return nil +} + +func (g *Group) checkForDuplicateFlags() *Error { + shortNames := make(map[rune]*Option) + longNames := make(map[string]*Option) + + var duplicateError *Error + + g.eachGroup(func(g *Group) { + for _, option := range g.options { + if option.LongName != "" { + longName := option.LongNameWithNamespace() + + if otherOption, ok := longNames[longName]; ok { + duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption) + return + } + longNames[longName] = option + } + if option.ShortName != 0 { + if otherOption, ok := shortNames[option.ShortName]; ok { + duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption) + return + } + shortNames[option.ShortName] = option + } + } + }) + + return duplicateError +} + +func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) { + mtag := newMultiTag(string(sfield.Tag)) + + if err := mtag.Parse(); err != nil { + return true, err + } + + subgroup := mtag.Get("group") + + if len(subgroup) != 0 { + ptrval := reflect.NewAt(realval.Type(), unsafe.Pointer(realval.UnsafeAddr())) + description := mtag.Get("description") + + group, err := g.AddGroup(subgroup, description, ptrval.Interface()) + if err != nil { + return true, err + } + + group.Namespace = mtag.Get("namespace") + group.Hidden = mtag.Get("hidden") != "" + + return true, nil + } + + return false, nil +} + +func (g *Group) scanType(handler scanHandler) error { + // Get all the public fields in the data struct + ptrval := reflect.ValueOf(g.data) + + if ptrval.Type().Kind() != reflect.Ptr { + panic(ErrNotPointerToStruct) + } + + stype := ptrval.Type().Elem() + + if stype.Kind() != reflect.Struct { + panic(ErrNotPointerToStruct) + } + + realval := reflect.Indirect(ptrval) + + if err := g.scanStruct(realval, nil, handler); err != nil { + return err + } + + if err := g.checkForDuplicateFlags(); err != nil { + return err + } + + return nil +} + +func (g *Group) scan() error { + return g.scanType(g.scanSubGroupHandler) +} + +func (g *Group) groupByName(name string) *Group { + if len(name) == 0 { + return g + } + + return g.Find(name) +} diff --git a/vendor/github.com/jessevdk/go-flags/group_test.go b/vendor/github.com/jessevdk/go-flags/group_test.go new file mode 100644 index 00000000..18cd6c17 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/group_test.go @@ -0,0 +1,255 @@ +package flags + +import ( + "testing" +) + +func TestGroupInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Group struct { + G bool `short:"g"` + } `group:"Grouped Options"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "-g") + + assertStringArray(t, ret, []string{}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Group.G { + t.Errorf("Expected Group.G to be true") + } + + if p.Command.Group.Find("Grouped Options") == nil { + t.Errorf("Expected to find group `Grouped Options'") + } +} + +func TestGroupAdd(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + var grp = struct { + G bool `short:"g"` + }{} + + p := NewParser(&opts, Default) + g, err := p.AddGroup("Grouped Options", "", &grp) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + ret, err := p.ParseArgs([]string{"-v", "-g", "rest"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !grp.G { + t.Errorf("Expected Group.G to be true") + } + + if p.Command.Group.Find("Grouped Options") != g { + t.Errorf("Expected to find group `Grouped Options'") + } + + if p.Groups()[1] != g { + t.Errorf("Expected group %#v, but got %#v", g, p.Groups()[0]) + } + + if g.Options()[0].ShortName != 'g' { + t.Errorf("Expected short name `g' but got %v", g.Options()[0].ShortName) + } +} + +func TestGroupNestedInline(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Group struct { + G bool `short:"g"` + + Nested struct { + N string `long:"n"` + } `group:"Nested Options"` + } `group:"Grouped Options"` + }{} + + p, ret := assertParserSuccess(t, &opts, "-v", "-g", "--n", "n", "rest") + + assertStringArray(t, ret, []string{"rest"}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Group.G { + t.Errorf("Expected Group.G to be true") + } + + assertString(t, opts.Group.Nested.N, "n") + + if p.Command.Group.Find("Grouped Options") == nil { + t.Errorf("Expected to find group `Grouped Options'") + } + + if p.Command.Group.Find("Nested Options") == nil { + t.Errorf("Expected to find group `Nested Options'") + } +} + +func TestGroupNestedInlineNamespace(t *testing.T) { + var opts = struct { + Opt string `long:"opt"` + + Group struct { + Opt string `long:"opt"` + Group struct { + Opt string `long:"opt"` + } `group:"Subsubgroup" namespace:"sap"` + } `group:"Subgroup" namespace:"sip"` + }{} + + p, ret := assertParserSuccess(t, &opts, "--opt", "a", "--sip.opt", "b", "--sip.sap.opt", "c", "rest") + + assertStringArray(t, ret, []string{"rest"}) + + assertString(t, opts.Opt, "a") + assertString(t, opts.Group.Opt, "b") + assertString(t, opts.Group.Group.Opt, "c") + + for _, name := range []string{"Subgroup", "Subsubgroup"} { + if p.Command.Group.Find(name) == nil { + t.Errorf("Expected to find group '%s'", name) + } + } +} + +func TestDuplicateShortFlags(t *testing.T) { + var opts struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + Variables []string `short:"v" long:"variable" description:"Set a variable value."` + } + + args := []string{ + "--verbose", + "-v", "123", + "-v", "456", + } + + _, err := ParseArgs(&opts, args) + + if err == nil { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } else { + err2 := err.(*Error) + if err2.Type != ErrDuplicatedFlag { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } + } +} + +func TestDuplicateLongFlags(t *testing.T) { + var opts struct { + Test1 []bool `short:"a" long:"testing" description:"Test 1"` + Test2 []string `short:"b" long:"testing" description:"Test 2."` + } + + args := []string{ + "--testing", + } + + _, err := ParseArgs(&opts, args) + + if err == nil { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } else { + err2 := err.(*Error) + if err2.Type != ErrDuplicatedFlag { + t.Errorf("Expected an error with type ErrDuplicatedFlag") + } + } +} + +func TestFindOptionByLongFlag(t *testing.T) { + var opts struct { + Testing bool `long:"testing" description:"Testing"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByLongName("testing") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "testing") +} + +func TestFindOptionByShortFlag(t *testing.T) { + var opts struct { + Testing bool `short:"t" description:"Testing"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByShortName('t') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 't' { + t.Errorf("Expected 't', but got %v", opt.ShortName) + } +} + +func TestFindOptionByLongFlagInSubGroup(t *testing.T) { + var opts struct { + Group struct { + Testing bool `long:"testing" description:"Testing"` + } `group:"sub-group"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByLongName("testing") + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + assertString(t, opt.LongName, "testing") +} + +func TestFindOptionByShortFlagInSubGroup(t *testing.T) { + var opts struct { + Group struct { + Testing bool `short:"t" description:"Testing"` + } `group:"sub-group"` + } + + p := NewParser(&opts, Default) + opt := p.FindOptionByShortName('t') + + if opt == nil { + t.Errorf("Expected option, but found none") + } + + if opt.ShortName != 't' { + t.Errorf("Expected 't', but got %v", opt.ShortName) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/help.go b/vendor/github.com/jessevdk/go-flags/help.go new file mode 100644 index 00000000..d3803050 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/help.go @@ -0,0 +1,491 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "bufio" + "bytes" + "fmt" + "io" + "runtime" + "strings" + "unicode/utf8" +) + +type alignmentInfo struct { + maxLongLen int + hasShort bool + hasValueName bool + terminalColumns int + indent bool +} + +const ( + paddingBeforeOption = 2 + distanceBetweenOptionAndDescription = 2 +) + +func (a *alignmentInfo) descriptionStart() int { + ret := a.maxLongLen + distanceBetweenOptionAndDescription + + if a.hasShort { + ret += 2 + } + + if a.maxLongLen > 0 { + ret += 4 + } + + if a.hasValueName { + ret += 3 + } + + return ret +} + +func (a *alignmentInfo) updateLen(name string, indent bool) { + l := utf8.RuneCountInString(name) + + if indent { + l = l + 4 + } + + if l > a.maxLongLen { + a.maxLongLen = l + } +} + +func (p *Parser) getAlignmentInfo() alignmentInfo { + ret := alignmentInfo{ + maxLongLen: 0, + hasShort: false, + hasValueName: false, + terminalColumns: getTerminalColumns(), + } + + if ret.terminalColumns <= 0 { + ret.terminalColumns = 80 + } + + var prevcmd *Command + + p.eachActiveGroup(func(c *Command, grp *Group) { + if c != prevcmd { + for _, arg := range c.args { + ret.updateLen(arg.Name, c != p.Command) + } + } + + for _, info := range grp.options { + if !info.canCli() { + continue + } + + if info.ShortName != 0 { + ret.hasShort = true + } + + if len(info.ValueName) > 0 { + ret.hasValueName = true + } + + l := info.LongNameWithNamespace() + info.ValueName + + if len(info.Choices) != 0 { + l += "[" + strings.Join(info.Choices, "|") + "]" + } + + ret.updateLen(l, c != p.Command) + } + }) + + return ret +} + +func wrapText(s string, l int, prefix string) string { + var ret string + + if l < 10 { + l = 10 + } + + // Basic text wrapping of s at spaces to fit in l + lines := strings.Split(s, "\n") + + for _, line := range lines { + var retline string + + line = strings.TrimSpace(line) + + for len(line) > l { + // Try to split on space + suffix := "" + + pos := strings.LastIndex(line[:l], " ") + + if pos < 0 { + pos = l - 1 + suffix = "-\n" + } + + if len(retline) != 0 { + retline += "\n" + prefix + } + + retline += strings.TrimSpace(line[:pos]) + suffix + line = strings.TrimSpace(line[pos:]) + } + + if len(line) > 0 { + if len(retline) != 0 { + retline += "\n" + prefix + } + + retline += line + } + + if len(ret) > 0 { + ret += "\n" + + if len(retline) > 0 { + ret += prefix + } + } + + ret += retline + } + + return ret +} + +func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alignmentInfo) { + line := &bytes.Buffer{} + + prefix := paddingBeforeOption + + if info.indent { + prefix += 4 + } + + if option.Hidden { + return + } + + line.WriteString(strings.Repeat(" ", prefix)) + + if option.ShortName != 0 { + line.WriteRune(defaultShortOptDelimiter) + line.WriteRune(option.ShortName) + } else if info.hasShort { + line.WriteString(" ") + } + + descstart := info.descriptionStart() + paddingBeforeOption + + if len(option.LongName) > 0 { + if option.ShortName != 0 { + line.WriteString(", ") + } else if info.hasShort { + line.WriteString(" ") + } + + line.WriteString(defaultLongOptDelimiter) + line.WriteString(option.LongNameWithNamespace()) + } + + if option.canArgument() { + line.WriteRune(defaultNameArgDelimiter) + + if len(option.ValueName) > 0 { + line.WriteString(option.ValueName) + } + + if len(option.Choices) > 0 { + line.WriteString("[" + strings.Join(option.Choices, "|") + "]") + } + } + + written := line.Len() + line.WriteTo(writer) + + if option.Description != "" { + dw := descstart - written + writer.WriteString(strings.Repeat(" ", dw)) + + var def string + + if len(option.DefaultMask) != 0 { + if option.DefaultMask != "-" { + def = option.DefaultMask + } + } else { + def = option.defaultLiteral + } + + var envDef string + if option.EnvDefaultKey != "" { + var envPrintable string + if runtime.GOOS == "windows" { + envPrintable = "%" + option.EnvDefaultKey + "%" + } else { + envPrintable = "$" + option.EnvDefaultKey + } + envDef = fmt.Sprintf(" [%s]", envPrintable) + } + + var desc string + + if def != "" { + desc = fmt.Sprintf("%s (default: %v)%s", option.Description, def, envDef) + } else { + desc = option.Description + envDef + } + + writer.WriteString(wrapText(desc, + info.terminalColumns-descstart, + strings.Repeat(" ", descstart))) + } + + writer.WriteString("\n") +} + +func maxCommandLength(s []*Command) int { + if len(s) == 0 { + return 0 + } + + ret := len(s[0].Name) + + for _, v := range s[1:] { + l := len(v.Name) + + if l > ret { + ret = l + } + } + + return ret +} + +// WriteHelp writes a help message containing all the possible options and +// their descriptions to the provided writer. Note that the HelpFlag parser +// option provides a convenient way to add a -h/--help option group to the +// command line parser which will automatically show the help messages using +// this method. +func (p *Parser) WriteHelp(writer io.Writer) { + if writer == nil { + return + } + + wr := bufio.NewWriter(writer) + aligninfo := p.getAlignmentInfo() + + cmd := p.Command + + for cmd.Active != nil { + cmd = cmd.Active + } + + if p.Name != "" { + wr.WriteString("Usage:\n") + wr.WriteString(" ") + + allcmd := p.Command + + for allcmd != nil { + var usage string + + if allcmd == p.Command { + if len(p.Usage) != 0 { + usage = p.Usage + } else if p.Options&HelpFlag != 0 { + usage = "[OPTIONS]" + } + } else if us, ok := allcmd.data.(Usage); ok { + usage = us.Usage() + } else if allcmd.hasCliOptions() { + usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name) + } + + if len(usage) != 0 { + fmt.Fprintf(wr, " %s %s", allcmd.Name, usage) + } else { + fmt.Fprintf(wr, " %s", allcmd.Name) + } + + if len(allcmd.args) > 0 { + fmt.Fprintf(wr, " ") + } + + for i, arg := range allcmd.args { + if i != 0 { + fmt.Fprintf(wr, " ") + } + + name := arg.Name + + if arg.isRemaining() { + name = name + "..." + } + + if !allcmd.ArgsRequired { + fmt.Fprintf(wr, "[%s]", name) + } else { + fmt.Fprintf(wr, "%s", name) + } + } + + if allcmd.Active == nil && len(allcmd.commands) > 0 { + var co, cc string + + if allcmd.SubcommandsOptional { + co, cc = "[", "]" + } else { + co, cc = "<", ">" + } + + visibleCommands := allcmd.visibleCommands() + + if len(visibleCommands) > 3 { + fmt.Fprintf(wr, " %scommand%s", co, cc) + } else { + subcommands := allcmd.sortedVisibleCommands() + names := make([]string, len(subcommands)) + + for i, subc := range subcommands { + names[i] = subc.Name + } + + fmt.Fprintf(wr, " %s%s%s", co, strings.Join(names, " | "), cc) + } + } + + allcmd = allcmd.Active + } + + fmt.Fprintln(wr) + + if len(cmd.LongDescription) != 0 { + fmt.Fprintln(wr) + + t := wrapText(cmd.LongDescription, + aligninfo.terminalColumns, + "") + + fmt.Fprintln(wr, t) + } + } + + c := p.Command + + for c != nil { + printcmd := c != p.Command + + c.eachGroup(func(grp *Group) { + first := true + + // Skip built-in help group for all commands except the top-level + // parser + if grp.Hidden || (grp.isBuiltinHelp && c != p.Command) { + return + } + + for _, info := range grp.options { + if !info.canCli() || info.Hidden { + continue + } + + if printcmd { + fmt.Fprintf(wr, "\n[%s command options]\n", c.Name) + aligninfo.indent = true + printcmd = false + } + + if first && cmd.Group != grp { + fmt.Fprintln(wr) + + if aligninfo.indent { + wr.WriteString(" ") + } + + fmt.Fprintf(wr, "%s:\n", grp.ShortDescription) + first = false + } + + p.writeHelpOption(wr, info, aligninfo) + } + }) + + var args []*Arg + for _, arg := range c.args { + if arg.Description != "" { + args = append(args, arg) + } + } + + if len(args) > 0 { + if c == p.Command { + fmt.Fprintf(wr, "\nArguments:\n") + } else { + fmt.Fprintf(wr, "\n[%s command arguments]\n", c.Name) + } + + descStart := aligninfo.descriptionStart() + paddingBeforeOption + + for _, arg := range args { + argPrefix := strings.Repeat(" ", paddingBeforeOption) + argPrefix += arg.Name + + if len(arg.Description) > 0 { + argPrefix += ":" + wr.WriteString(argPrefix) + + // Space between "arg:" and the description start + descPadding := strings.Repeat(" ", descStart-len(argPrefix)) + // How much space the description gets before wrapping + descWidth := aligninfo.terminalColumns - 1 - descStart + // Whitespace to which we can indent new description lines + descPrefix := strings.Repeat(" ", descStart) + + wr.WriteString(descPadding) + wr.WriteString(wrapText(arg.Description, descWidth, descPrefix)) + } else { + wr.WriteString(argPrefix) + } + + fmt.Fprintln(wr) + } + } + + c = c.Active + } + + scommands := cmd.sortedVisibleCommands() + + if len(scommands) > 0 { + maxnamelen := maxCommandLength(scommands) + + fmt.Fprintln(wr) + fmt.Fprintln(wr, "Available commands:") + + for _, c := range scommands { + fmt.Fprintf(wr, " %s", c.Name) + + if len(c.ShortDescription) > 0 { + pad := strings.Repeat(" ", maxnamelen-len(c.Name)) + fmt.Fprintf(wr, "%s %s", pad, c.ShortDescription) + + if len(c.Aliases) > 0 { + fmt.Fprintf(wr, " (aliases: %s)", strings.Join(c.Aliases, ", ")) + } + + } + + fmt.Fprintln(wr) + } + } + + wr.Flush() +} diff --git a/vendor/github.com/jessevdk/go-flags/help_test.go b/vendor/github.com/jessevdk/go-flags/help_test.go new file mode 100644 index 00000000..bb766405 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/help_test.go @@ -0,0 +1,538 @@ +package flags + +import ( + "bufio" + "bytes" + "fmt" + "os" + "runtime" + "strings" + "testing" + "time" +) + +type helpOptions struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information" ini-name:"verbose"` + Call func(string) `short:"c" description:"Call phone number" ini-name:"call"` + PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + EmptyDescription bool `long:"empty-description"` + + Default string `long:"default" default:"Some\nvalue" description:"Test default value"` + DefaultArray []string `long:"default-array" default:"Some value" default:"Other\tvalue" description:"Test default array value"` + DefaultMap map[string]string `long:"default-map" default:"some:value" default:"another:value" description:"Testdefault map value"` + EnvDefault1 string `long:"env-default1" default:"Some value" env:"ENV_DEFAULT" description:"Test env-default1 value"` + EnvDefault2 string `long:"env-default2" env:"ENV_DEFAULT" description:"Test env-default2 value"` + OptionWithArgName string `long:"opt-with-arg-name" value-name:"something" description:"Option with named argument"` + OptionWithChoices string `long:"opt-with-choices" value-name:"choice" choice:"dog" choice:"cat" description:"Option with choices"` + Hidden string `long:"hidden" description:"Hidden option" hidden:"yes"` + + OnlyIni string `ini-name:"only-ini" description:"Option only available in ini"` + + Other struct { + StringSlice []string `short:"s" default:"some" default:"value" description:"A slice of strings"` + IntMap map[string]int `long:"intmap" default:"a:1" description:"A map from string to int" ini-name:"int-map"` + } `group:"Other Options"` + + HiddenGroup struct { + InsideHiddenGroup string `long:"inside-hidden-group" description:"Inside hidden group"` + } `group:"Hidden group" hidden:"yes"` + + Group struct { + Opt string `long:"opt" description:"This is a subgroup option"` + HiddenInsideGroup string `long:"hidden-inside-group" description:"Hidden inside group" hidden:"yes"` + NotHiddenInsideGroup string `long:"not-hidden-inside-group" description:"Not hidden inside group" hidden:"false"` + + Group struct { + Opt string `long:"opt" description:"This is a subsubgroup option"` + } `group:"Subsubgroup" namespace:"sap"` + } `group:"Subgroup" namespace:"sip"` + + Command struct { + ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"` + } `command:"command" alias:"cm" alias:"cmd" description:"A command"` + + HiddenCommand struct { + ExtraVerbose []bool `long:"extra-verbose" description:"Use for extra verbosity"` + } `command:"hidden-command" description:"A hidden command" hidden:"yes"` + + Args struct { + Filename string `positional-arg-name:"filename" description:"A filename with a long description to trigger line wrapping"` + Number int `positional-arg-name:"num" description:"A number"` + HiddenInHelp float32 `positional-arg-name:"hidden-in-help" required:"yes"` + } `positional-args:"yes"` +} + +func TestHelp(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var opts helpOptions + p := NewNamedParser("TestHelp", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs([]string{"--help"}) + + if err == nil { + t.Fatalf("Expected help error") + } + + if e, ok := err.(*Error); !ok { + t.Fatalf("Expected flags.Error, but got %T", err) + } else { + if e.Type != ErrHelp { + t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) + } + + var expected string + + if runtime.GOOS == "windows" { + expected = `Usage: + TestHelp [OPTIONS] [filename] [num] [hidden-in-help] + +Application Options: + /v, /verbose Show verbose debug information + /c: Call phone number + /ptrslice: A slice of pointers to string + /empty-description + /default: Test default value (default: + "Some\nvalue") + /default-array: Test default array value (default: + Some value, "Other\tvalue") + /default-map: Testdefault map value (default: + some:value, another:value) + /env-default1: Test env-default1 value (default: + Some value) [%ENV_DEFAULT%] + /env-default2: Test env-default2 value + [%ENV_DEFAULT%] + /opt-with-arg-name:something Option with named argument + /opt-with-choices:choice[dog|cat] Option with choices + +Other Options: + /s: A slice of strings (default: some, + value) + /intmap: A map from string to int (default: + a:1) + +Subgroup: + /sip.opt: This is a subgroup option + /sip.not-hidden-inside-group: Not hidden inside group + +Subsubgroup: + /sip.sap.opt: This is a subsubgroup option + +Help Options: + /? Show this help message + /h, /help Show this help message + +Arguments: + filename: A filename with a long description + to trigger line wrapping + num: A number + +Available commands: + command A command (aliases: cm, cmd) +` + } else { + expected = `Usage: + TestHelp [OPTIONS] [filename] [num] [hidden-in-help] + +Application Options: + -v, --verbose Show verbose debug information + -c= Call phone number + --ptrslice= A slice of pointers to string + --empty-description + --default= Test default value (default: + "Some\nvalue") + --default-array= Test default array value (default: + Some value, "Other\tvalue") + --default-map= Testdefault map value (default: + some:value, another:value) + --env-default1= Test env-default1 value (default: + Some value) [$ENV_DEFAULT] + --env-default2= Test env-default2 value + [$ENV_DEFAULT] + --opt-with-arg-name=something Option with named argument + --opt-with-choices=choice[dog|cat] Option with choices + +Other Options: + -s= A slice of strings (default: some, + value) + --intmap= A map from string to int (default: + a:1) + +Subgroup: + --sip.opt= This is a subgroup option + --sip.not-hidden-inside-group= Not hidden inside group + +Subsubgroup: + --sip.sap.opt= This is a subsubgroup option + +Help Options: + -h, --help Show this help message + +Arguments: + filename: A filename with a long description + to trigger line wrapping + num: A number + +Available commands: + command A command (aliases: cm, cmd) +` + } + + assertDiff(t, e.Message, expected, "help message") + } +} + +func TestMan(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var opts helpOptions + p := NewNamedParser("TestMan", HelpFlag) + p.ShortDescription = "Test manpage generation" + p.LongDescription = "This is a somewhat `longer' description of what this does" + p.AddGroup("Application Options", "The application options", &opts) + + p.Commands()[0].LongDescription = "Longer `command' description" + + var buf bytes.Buffer + p.WriteManPage(&buf) + + got := buf.String() + + tt := time.Now() + + var envDefaultName string + + if runtime.GOOS == "windows" { + envDefaultName = "%ENV_DEFAULT%" + } else { + envDefaultName = "$ENV_DEFAULT" + } + + expected := fmt.Sprintf(`.TH TestMan 1 "%s" +.SH NAME +TestMan \- Test manpage generation +.SH SYNOPSIS +\fBTestMan\fP [OPTIONS] +.SH DESCRIPTION +This is a somewhat \fBlonger\fP description of what this does +.SH OPTIONS +.SS Application Options +The application options +.TP +\fB\fB\-v\fR, \fB\-\-verbose\fR\fP +Show verbose debug information +.TP +\fB\fB\-c\fR\fP +Call phone number +.TP +\fB\fB\-\-ptrslice\fR\fP +A slice of pointers to string +.TP +\fB\fB\-\-empty-description\fR\fP +.TP +\fB\fB\-\-default\fR \fP +Test default value +.TP +\fB\fB\-\-default-array\fR \fP +Test default array value +.TP +\fB\fB\-\-default-map\fR \fP +Testdefault map value +.TP +\fB\fB\-\-env-default1\fR \fP +Test env-default1 value +.TP +\fB\fB\-\-env-default2\fR \fP +Test env-default2 value +.TP +\fB\fB\-\-opt-with-arg-name\fR \fIsomething\fR\fP +Option with named argument +.TP +\fB\fB\-\-opt-with-choices\fR \fIchoice\fR\fP +Option with choices +.SS Other Options +.TP +\fB\fB\-s\fR \fP +A slice of strings +.TP +\fB\fB\-\-intmap\fR \fP +A map from string to int +.SS Subgroup +.TP +\fB\fB\-\-sip.opt\fR\fP +This is a subgroup option +.TP +\fB\fB\-\-sip.not-hidden-inside-group\fR\fP +Not hidden inside group +.SS Subsubgroup +.TP +\fB\fB\-\-sip.sap.opt\fR\fP +This is a subsubgroup option +.SH COMMANDS +.SS command +A command + +Longer \fBcommand\fP description + +\fBUsage\fP: TestMan [OPTIONS] command [command-OPTIONS] +.TP + +\fBAliases\fP: cm, cmd + +.TP +\fB\fB\-\-extra-verbose\fR\fP +Use for extra verbosity +`, tt.Format("2 January 2006"), envDefaultName) + + assertDiff(t, got, expected, "man page") +} + +type helpCommandNoOptions struct { + Command struct { + } `command:"command" description:"A command"` +} + +func TestHelpCommand(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var opts helpCommandNoOptions + p := NewNamedParser("TestHelpCommand", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs([]string{"command", "--help"}) + + if err == nil { + t.Fatalf("Expected help error") + } + + if e, ok := err.(*Error); !ok { + t.Fatalf("Expected flags.Error, but got %T", err) + } else { + if e.Type != ErrHelp { + t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) + } + + var expected string + + if runtime.GOOS == "windows" { + expected = `Usage: + TestHelpCommand [OPTIONS] command + +Help Options: + /? Show this help message + /h, /help Show this help message +` + } else { + expected = `Usage: + TestHelpCommand [OPTIONS] command + +Help Options: + -h, --help Show this help message +` + } + + assertDiff(t, e.Message, expected, "help message") + } +} + +func TestHelpDefaults(t *testing.T) { + var expected string + + if runtime.GOOS == "windows" { + expected = `Usage: + TestHelpDefaults [OPTIONS] + +Application Options: + /with-default: With default (default: default-value) + /without-default: Without default + /with-programmatic-default: With programmatic default (default: + default-value) + +Help Options: + /? Show this help message + /h, /help Show this help message +` + } else { + expected = `Usage: + TestHelpDefaults [OPTIONS] + +Application Options: + --with-default= With default (default: default-value) + --without-default= Without default + --with-programmatic-default= With programmatic default (default: + default-value) + +Help Options: + -h, --help Show this help message +` + } + + tests := []struct { + Args []string + Output string + }{ + { + Args: []string{"-h"}, + Output: expected, + }, + { + Args: []string{"--with-default", "other-value", "--with-programmatic-default", "other-value", "-h"}, + Output: expected, + }, + } + + for _, test := range tests { + var opts struct { + WithDefault string `long:"with-default" default:"default-value" description:"With default"` + WithoutDefault string `long:"without-default" description:"Without default"` + WithProgrammaticDefault string `long:"with-programmatic-default" description:"With programmatic default"` + } + + opts.WithProgrammaticDefault = "default-value" + + p := NewNamedParser("TestHelpDefaults", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs(test.Args) + + if err == nil { + t.Fatalf("Expected help error") + } + + if e, ok := err.(*Error); !ok { + t.Fatalf("Expected flags.Error, but got %T", err) + } else { + if e.Type != ErrHelp { + t.Errorf("Expected flags.ErrHelp type, but got %s", e.Type) + } + + assertDiff(t, e.Message, test.Output, "help message") + } + } +} + +func TestHelpRestArgs(t *testing.T) { + opts := struct { + Verbose bool `short:"v"` + }{} + + p := NewNamedParser("TestHelpDefaults", HelpFlag) + p.AddGroup("Application Options", "The application options", &opts) + + retargs, err := p.ParseArgs([]string{"-h", "-v", "rest"}) + + if err == nil { + t.Fatalf("Expected help error") + } + + assertStringArray(t, retargs, []string{"-v", "rest"}) +} + +func TestWrapText(t *testing.T) { + s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + + got := wrapText(s, 60, " ") + expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam, quis nostrud exercitation + ullamco laboris nisi ut aliquip ex ea commodo consequat. + Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + occaecat cupidatat non proident, sunt in culpa qui officia + deserunt mollit anim id est laborum.` + + assertDiff(t, got, expected, "wrapped text") +} + +func TestWrapParagraph(t *testing.T) { + s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n" + s += "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n" + s += "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\n" + s += "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n" + + got := wrapText(s, 60, " ") + expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit, + sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. + + Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. + + Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. + + Excepteur sint occaecat cupidatat non proident, sunt in + culpa qui officia deserunt mollit anim id est laborum. +` + + assertDiff(t, got, expected, "wrapped paragraph") +} + +func TestHelpDefaultMask(t *testing.T) { + var tests = []struct { + opts interface{} + present string + }{ + { + opts: &struct { + Value string `short:"v" default:"123" description:"V"` + }{}, + present: "V (default: 123)\n", + }, + { + opts: &struct { + Value string `short:"v" default:"123" default-mask:"abc" description:"V"` + }{}, + present: "V (default: abc)\n", + }, + { + opts: &struct { + Value string `short:"v" default:"123" default-mask:"-" description:"V"` + }{}, + present: "V\n", + }, + { + opts: &struct { + Value string `short:"v" description:"V"` + }{Value: "123"}, + present: "V (default: 123)\n", + }, + { + opts: &struct { + Value string `short:"v" default-mask:"abc" description:"V"` + }{Value: "123"}, + present: "V (default: abc)\n", + }, + { + opts: &struct { + Value string `short:"v" default-mask:"-" description:"V"` + }{Value: "123"}, + present: "V\n", + }, + } + + for _, test := range tests { + p := NewParser(test.opts, HelpFlag) + _, err := p.ParseArgs([]string{"-h"}) + if flagsErr, ok := err.(*Error); ok && flagsErr.Type == ErrHelp { + err = nil + } + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + h := &bytes.Buffer{} + w := bufio.NewWriter(h) + p.writeHelpOption(w, p.FindOptionByShortName('v'), p.getAlignmentInfo()) + w.Flush() + if strings.Index(h.String(), test.present) < 0 { + t.Errorf("Not present %q\n%s", test.present, h.String()) + } + } +} diff --git a/vendor/github.com/jessevdk/go-flags/ini.go b/vendor/github.com/jessevdk/go-flags/ini.go new file mode 100644 index 00000000..e714d3d3 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/ini.go @@ -0,0 +1,597 @@ +package flags + +import ( + "bufio" + "fmt" + "io" + "os" + "reflect" + "sort" + "strconv" + "strings" +) + +// IniError contains location information on where an error occurred. +type IniError struct { + // The error message. + Message string + + // The filename of the file in which the error occurred. + File string + + // The line number at which the error occurred. + LineNumber uint +} + +// Error provides a "file:line: message" formatted message of the ini error. +func (x *IniError) Error() string { + return fmt.Sprintf( + "%s:%d: %s", + x.File, + x.LineNumber, + x.Message, + ) +} + +// IniOptions for writing +type IniOptions uint + +const ( + // IniNone indicates no options. + IniNone IniOptions = 0 + + // IniIncludeDefaults indicates that default values should be written. + IniIncludeDefaults = 1 << iota + + // IniCommentDefaults indicates that if IniIncludeDefaults is used + // options with default values are written but commented out. + IniCommentDefaults + + // IniIncludeComments indicates that comments containing the description + // of an option should be written. + IniIncludeComments + + // IniDefault provides a default set of options. + IniDefault = IniIncludeComments +) + +// IniParser is a utility to read and write flags options from and to ini +// formatted strings. +type IniParser struct { + ParseAsDefaults bool // override default flags + + parser *Parser +} + +type iniValue struct { + Name string + Value string + Quoted bool + LineNumber uint +} + +type iniSection []iniValue + +type ini struct { + File string + Sections map[string]iniSection +} + +// NewIniParser creates a new ini parser for a given Parser. +func NewIniParser(p *Parser) *IniParser { + return &IniParser{ + parser: p, + } +} + +// IniParse is a convenience function to parse command line options with default +// settings from an ini formatted file. The provided data is a pointer to a struct +// representing the default option group (named "Application Options"). For +// more control, use flags.NewParser. +func IniParse(filename string, data interface{}) error { + p := NewParser(data, Default) + + return NewIniParser(p).ParseFile(filename) +} + +// ParseFile parses flags from an ini formatted file. See Parse for more +// information on the ini file format. The returned errors can be of the type +// flags.Error or flags.IniError. +func (i *IniParser) ParseFile(filename string) error { + ini, err := readIniFromFile(filename) + + if err != nil { + return err + } + + return i.parse(ini) +} + +// Parse parses flags from an ini format. You can use ParseFile as a +// convenience function to parse from a filename instead of a general +// io.Reader. +// +// The format of the ini file is as follows: +// +// [Option group name] +// option = value +// +// Each section in the ini file represents an option group or command in the +// flags parser. The default flags parser option group (i.e. when using +// flags.Parse) is named 'Application Options'. The ini option name is matched +// in the following order: +// +// 1. Compared to the ini-name tag on the option struct field (if present) +// 2. Compared to the struct field name +// 3. Compared to the option long name (if present) +// 4. Compared to the option short name (if present) +// +// Sections for nested groups and commands can be addressed using a dot `.' +// namespacing notation (i.e [subcommand.Options]). Group section names are +// matched case insensitive. +// +// The returned errors can be of the type flags.Error or flags.IniError. +func (i *IniParser) Parse(reader io.Reader) error { + ini, err := readIni(reader, "") + + if err != nil { + return err + } + + return i.parse(ini) +} + +// WriteFile writes the flags as ini format into a file. See Write +// for more information. The returned error occurs when the specified file +// could not be opened for writing. +func (i *IniParser) WriteFile(filename string, options IniOptions) error { + return writeIniToFile(i, filename, options) +} + +// Write writes the current values of all the flags to an ini format. +// See Parse for more information on the ini file format. You typically +// call this only after settings have been parsed since the default values of each +// option are stored just before parsing the flags (this is only relevant when +// IniIncludeDefaults is _not_ set in options). +func (i *IniParser) Write(writer io.Writer, options IniOptions) { + writeIni(i, writer, options) +} + +func readFullLine(reader *bufio.Reader) (string, error) { + var line []byte + + for { + l, more, err := reader.ReadLine() + + if err != nil { + return "", err + } + + if line == nil && !more { + return string(l), nil + } + + line = append(line, l...) + + if !more { + break + } + } + + return string(line), nil +} + +func optionIniName(option *Option) string { + name := option.tag.Get("_read-ini-name") + + if len(name) != 0 { + return name + } + + name = option.tag.Get("ini-name") + + if len(name) != 0 { + return name + } + + return option.field.Name +} + +func writeGroupIni(cmd *Command, group *Group, namespace string, writer io.Writer, options IniOptions) { + var sname string + + if len(namespace) != 0 { + sname = namespace + } + + if cmd.Group != group && len(group.ShortDescription) != 0 { + if len(sname) != 0 { + sname += "." + } + + sname += group.ShortDescription + } + + sectionwritten := false + comments := (options & IniIncludeComments) != IniNone + + for _, option := range group.options { + if option.isFunc() || option.Hidden { + continue + } + + if len(option.tag.Get("no-ini")) != 0 { + continue + } + + val := option.value + + if (options&IniIncludeDefaults) == IniNone && option.valueIsDefault() { + continue + } + + if !sectionwritten { + fmt.Fprintf(writer, "[%s]\n", sname) + sectionwritten = true + } + + if comments && len(option.Description) != 0 { + fmt.Fprintf(writer, "; %s\n", option.Description) + } + + oname := optionIniName(option) + + commentOption := (options&(IniIncludeDefaults|IniCommentDefaults)) == IniIncludeDefaults|IniCommentDefaults && option.valueIsDefault() + + kind := val.Type().Kind() + switch kind { + case reflect.Slice: + kind = val.Type().Elem().Kind() + + if val.Len() == 0 { + writeOption(writer, oname, kind, "", "", true, option.iniQuote) + } else { + for idx := 0; idx < val.Len(); idx++ { + v, _ := convertToString(val.Index(idx), option.tag) + + writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote) + } + } + case reflect.Map: + kind = val.Type().Elem().Kind() + + if val.Len() == 0 { + writeOption(writer, oname, kind, "", "", true, option.iniQuote) + } else { + mkeys := val.MapKeys() + keys := make([]string, len(val.MapKeys())) + kkmap := make(map[string]reflect.Value) + + for i, k := range mkeys { + keys[i], _ = convertToString(k, option.tag) + kkmap[keys[i]] = k + } + + sort.Strings(keys) + + for _, k := range keys { + v, _ := convertToString(val.MapIndex(kkmap[k]), option.tag) + + writeOption(writer, oname, kind, k, v, commentOption, option.iniQuote) + } + } + default: + v, _ := convertToString(val, option.tag) + + writeOption(writer, oname, kind, "", v, commentOption, option.iniQuote) + } + + if comments { + fmt.Fprintln(writer) + } + } + + if sectionwritten && !comments { + fmt.Fprintln(writer) + } +} + +func writeOption(writer io.Writer, optionName string, optionType reflect.Kind, optionKey string, optionValue string, commentOption bool, forceQuote bool) { + if forceQuote || (optionType == reflect.String && !isPrint(optionValue)) { + optionValue = strconv.Quote(optionValue) + } + + comment := "" + if commentOption { + comment = "; " + } + + fmt.Fprintf(writer, "%s%s =", comment, optionName) + + if optionKey != "" { + fmt.Fprintf(writer, " %s:%s", optionKey, optionValue) + } else if optionValue != "" { + fmt.Fprintf(writer, " %s", optionValue) + } + + fmt.Fprintln(writer) +} + +func writeCommandIni(command *Command, namespace string, writer io.Writer, options IniOptions) { + command.eachGroup(func(group *Group) { + if !group.Hidden { + writeGroupIni(command, group, namespace, writer, options) + } + }) + + for _, c := range command.commands { + var nns string + + if c.Hidden { + continue + } + + if len(namespace) != 0 { + nns = c.Name + "." + nns + } else { + nns = c.Name + } + + writeCommandIni(c, nns, writer, options) + } +} + +func writeIni(parser *IniParser, writer io.Writer, options IniOptions) { + writeCommandIni(parser.parser.Command, "", writer, options) +} + +func writeIniToFile(parser *IniParser, filename string, options IniOptions) error { + file, err := os.Create(filename) + + if err != nil { + return err + } + + defer file.Close() + + writeIni(parser, file, options) + + return nil +} + +func readIniFromFile(filename string) (*ini, error) { + file, err := os.Open(filename) + + if err != nil { + return nil, err + } + + defer file.Close() + + return readIni(file, filename) +} + +func readIni(contents io.Reader, filename string) (*ini, error) { + ret := &ini{ + File: filename, + Sections: make(map[string]iniSection), + } + + reader := bufio.NewReader(contents) + + // Empty global section + section := make(iniSection, 0, 10) + sectionname := "" + + ret.Sections[sectionname] = section + + var lineno uint + + for { + line, err := readFullLine(reader) + + if err == io.EOF { + break + } else if err != nil { + return nil, err + } + + lineno++ + line = strings.TrimSpace(line) + + // Skip empty lines and lines starting with ; (comments) + if len(line) == 0 || line[0] == ';' || line[0] == '#' { + continue + } + + if line[0] == '[' { + if line[0] != '[' || line[len(line)-1] != ']' { + return nil, &IniError{ + Message: "malformed section header", + File: filename, + LineNumber: lineno, + } + } + + name := strings.TrimSpace(line[1 : len(line)-1]) + + if len(name) == 0 { + return nil, &IniError{ + Message: "empty section name", + File: filename, + LineNumber: lineno, + } + } + + sectionname = name + section = ret.Sections[name] + + if section == nil { + section = make(iniSection, 0, 10) + ret.Sections[name] = section + } + + continue + } + + // Parse option here + keyval := strings.SplitN(line, "=", 2) + + if len(keyval) != 2 { + return nil, &IniError{ + Message: fmt.Sprintf("malformed key=value (%s)", line), + File: filename, + LineNumber: lineno, + } + } + + name := strings.TrimSpace(keyval[0]) + value := strings.TrimSpace(keyval[1]) + quoted := false + + if len(value) != 0 && value[0] == '"' { + if v, err := strconv.Unquote(value); err == nil { + value = v + + quoted = true + } else { + return nil, &IniError{ + Message: err.Error(), + File: filename, + LineNumber: lineno, + } + } + } + + section = append(section, iniValue{ + Name: name, + Value: value, + Quoted: quoted, + LineNumber: lineno, + }) + + ret.Sections[sectionname] = section + } + + return ret, nil +} + +func (i *IniParser) matchingGroups(name string) []*Group { + if len(name) == 0 { + var ret []*Group + + i.parser.eachGroup(func(g *Group) { + ret = append(ret, g) + }) + + return ret + } + + g := i.parser.groupByName(name) + + if g != nil { + return []*Group{g} + } + + return nil +} + +func (i *IniParser) parse(ini *ini) error { + p := i.parser + + var quotesLookup = make(map[*Option]bool) + + for name, section := range ini.Sections { + groups := i.matchingGroups(name) + + if len(groups) == 0 { + return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name) + } + + for _, inival := range section { + var opt *Option + + for _, group := range groups { + opt = group.optionByName(inival.Name, func(o *Option, n string) bool { + return strings.ToLower(o.tag.Get("ini-name")) == strings.ToLower(n) + }) + + if opt != nil && len(opt.tag.Get("no-ini")) != 0 { + opt = nil + } + + if opt != nil { + break + } + } + + if opt == nil { + if (p.Options & IgnoreUnknown) == None { + return &IniError{ + Message: fmt.Sprintf("unknown option: %s", inival.Name), + File: ini.File, + LineNumber: inival.LineNumber, + } + } + + continue + } + + // ini value is ignored if override is set and + // value was previously set from non default + if i.ParseAsDefaults && !opt.isSetDefault { + continue + } + + pval := &inival.Value + + if !opt.canArgument() && len(inival.Value) == 0 { + pval = nil + } else { + if opt.value.Type().Kind() == reflect.Map { + parts := strings.SplitN(inival.Value, ":", 2) + + // only handle unquoting + if len(parts) == 2 && parts[1][0] == '"' { + if v, err := strconv.Unquote(parts[1]); err == nil { + parts[1] = v + + inival.Quoted = true + } else { + return &IniError{ + Message: err.Error(), + File: ini.File, + LineNumber: inival.LineNumber, + } + } + + s := parts[0] + ":" + parts[1] + + pval = &s + } + } + } + + if err := opt.set(pval); err != nil { + return &IniError{ + Message: err.Error(), + File: ini.File, + LineNumber: inival.LineNumber, + } + } + + // either all INI values are quoted or only values who need quoting + if _, ok := quotesLookup[opt]; !inival.Quoted || !ok { + quotesLookup[opt] = inival.Quoted + } + + opt.tag.Set("_read-ini-name", inival.Name) + } + } + + for opt, quoted := range quotesLookup { + opt.iniQuote = quoted + } + + return nil +} diff --git a/vendor/github.com/jessevdk/go-flags/ini_test.go b/vendor/github.com/jessevdk/go-flags/ini_test.go new file mode 100644 index 00000000..ad4852e8 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/ini_test.go @@ -0,0 +1,1053 @@ +package flags + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "reflect" + "strings" + "testing" +) + +func TestWriteIni(t *testing.T) { + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + os.Setenv("ENV_DEFAULT", "env-def") + + var tests = []struct { + args []string + options IniOptions + expected string + }{ + { + []string{"-vv", "--intmap=a:2", "--intmap", "b:3", "filename", "0", "3.14", "command"}, + IniDefault, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A map from string to int +int-map = a:2 +int-map = b:3 + +`, + }, + { + []string{"-vv", "--intmap=a:2", "--intmap", "b:3", "filename", "0", "3.14", "command"}, + IniDefault | IniIncludeDefaults, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; A slice of pointers to string +; PtrSlice = + +EmptyDescription = false + +; Test default value +Default = "Some\nvalue" + +; Test default array value +DefaultArray = Some value +DefaultArray = "Other\tvalue" + +; Testdefault map value +DefaultMap = another:value +DefaultMap = some:value + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +; Option with named argument +OptionWithArgName = + +; Option with choices +OptionWithChoices = + +; Option only available in ini +only-ini = + +[Other Options] +; A slice of strings +StringSlice = some +StringSlice = value + +; A map from string to int +int-map = a:2 +int-map = b:3 + +[Subgroup] +; This is a subgroup option +Opt = + +; Not hidden inside group +NotHiddenInsideGroup = + +[Subsubgroup] +; This is a subsubgroup option +Opt = + +[command] +; Use for extra verbosity +; ExtraVerbose = + +`, + }, + { + []string{"filename", "0", "3.14", "command"}, + IniDefault | IniIncludeDefaults | IniCommentDefaults, + `[Application Options] +; Show verbose debug information +; verbose = + +; A slice of pointers to string +; PtrSlice = + +; EmptyDescription = false + +; Test default value +; Default = "Some\nvalue" + +; Test default array value +; DefaultArray = Some value +; DefaultArray = "Other\tvalue" + +; Testdefault map value +; DefaultMap = another:value +; DefaultMap = some:value + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +; Option with named argument +; OptionWithArgName = + +; Option with choices +; OptionWithChoices = + +; Option only available in ini +; only-ini = + +[Other Options] +; A slice of strings +; StringSlice = some +; StringSlice = value + +; A map from string to int +; int-map = a:1 + +[Subgroup] +; This is a subgroup option +; Opt = + +; Not hidden inside group +; NotHiddenInsideGroup = + +[Subsubgroup] +; This is a subsubgroup option +; Opt = + +[command] +; Use for extra verbosity +; ExtraVerbose = + +`, + }, + { + []string{"--default=New value", "--default-array=New value", "--default-map=new:value", "filename", "0", "3.14", "command"}, + IniDefault | IniIncludeDefaults | IniCommentDefaults, + `[Application Options] +; Show verbose debug information +; verbose = + +; A slice of pointers to string +; PtrSlice = + +; EmptyDescription = false + +; Test default value +Default = New value + +; Test default array value +DefaultArray = New value + +; Testdefault map value +DefaultMap = new:value + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +; Option with named argument +; OptionWithArgName = + +; Option with choices +; OptionWithChoices = + +; Option only available in ini +; only-ini = + +[Other Options] +; A slice of strings +; StringSlice = some +; StringSlice = value + +; A map from string to int +; int-map = a:1 + +[Subgroup] +; This is a subgroup option +; Opt = + +; Not hidden inside group +; NotHiddenInsideGroup = + +[Subsubgroup] +; This is a subsubgroup option +; Opt = + +[command] +; Use for extra verbosity +; ExtraVerbose = + +`, + }, + } + + for _, test := range tests { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + _, err := p.ParseArgs(test.args) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + inip := NewIniParser(p) + + var b bytes.Buffer + inip.Write(&b, test.options) + + got := b.String() + expected := test.expected + + msg := fmt.Sprintf("with arguments %+v and ini options %b", test.args, test.options) + assertDiff(t, got, expected, msg) + } +} + +func TestReadIni_flagEquivalent(t *testing.T) { + type options struct { + Opt1 bool `long:"opt1"` + + Group1 struct { + Opt2 bool `long:"opt2"` + } `group:"group1"` + + Group2 struct { + Opt3 bool `long:"opt3"` + } `group:"group2" namespace:"ns1"` + + Cmd1 struct { + Opt4 bool `long:"opt4"` + Opt5 bool `long:"foo.opt5"` + + Group1 struct { + Opt6 bool `long:"opt6"` + Opt7 bool `long:"foo.opt7"` + } `group:"group1"` + + Group2 struct { + Opt8 bool `long:"opt8"` + } `group:"group2" namespace:"ns1"` + } `command:"cmd1"` + } + + a := ` +opt1=true + +[group1] +opt2=true + +[group2] +ns1.opt3=true + +[cmd1] +opt4=true +foo.opt5=true + +[cmd1.group1] +opt6=true +foo.opt7=true + +[cmd1.group2] +ns1.opt8=true +` + b := ` +opt1=true +opt2=true +ns1.opt3=true + +[cmd1] +opt4=true +foo.opt5=true +opt6=true +foo.opt7=true +ns1.opt8=true +` + + parse := func(readIni string) (opts options, writeIni string) { + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + err := inip.Parse(strings.NewReader(readIni)) + + if err != nil { + t.Fatalf("Unexpected error: %s\n\nFile:\n%s", err, readIni) + } + + var b bytes.Buffer + inip.Write(&b, Default) + + return opts, b.String() + } + + aOpt, aIni := parse(a) + bOpt, bIni := parse(b) + + assertDiff(t, aIni, bIni, "") + if !reflect.DeepEqual(aOpt, bOpt) { + t.Errorf("not equal") + } +} + +func TestReadIni(t *testing.T) { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + inic := ` +; Show verbose debug information +verbose = true +verbose = true + +DefaultMap = another:"value\n1" +DefaultMap = some:value 2 + +[Application Options] +; A slice of pointers to string +; PtrSlice = + +; Test default value +Default = "New\nvalue" + +; Test env-default1 value +EnvDefault1 = New value + +[Other Options] +# A slice of strings +StringSlice = "some\nvalue" +StringSlice = another value + +; A map from string to int +int-map = a:2 +int-map = b:3 + +` + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + assertBoolArray(t, opts.Verbose, []bool{true, true}) + + if v := map[string]string{"another": "value\n1", "some": "value 2"}; !reflect.DeepEqual(opts.DefaultMap, v) { + t.Fatalf("Expected %#v for DefaultMap but got %#v", v, opts.DefaultMap) + } + + assertString(t, opts.Default, "New\nvalue") + + assertString(t, opts.EnvDefault1, "New value") + + assertStringArray(t, opts.Other.StringSlice, []string{"some\nvalue", "another value"}) + + if v, ok := opts.Other.IntMap["a"]; !ok { + t.Errorf("Expected \"a\" in Other.IntMap") + } else if v != 2 { + t.Errorf("Expected Other.IntMap[\"a\"] = 2, but got %v", v) + } + + if v, ok := opts.Other.IntMap["b"]; !ok { + t.Errorf("Expected \"b\" in Other.IntMap") + } else if v != 3 { + t.Errorf("Expected Other.IntMap[\"b\"] = 3, but got %v", v) + } +} + +func TestReadAndWriteIni(t *testing.T) { + var tests = []struct { + options IniOptions + read string + write string + }{ + { + IniIncludeComments, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = 1 +DefaultArray = "2" +DefaultArray = 3 + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:2 +int-map = b:"3" + +`, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = 1 +DefaultArray = 2 +DefaultArray = 3 + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:2 +int-map = b:3 + +`, + }, + { + IniIncludeComments, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = "1" +DefaultArray = "2" +DefaultArray = "3" + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:"2" +int-map = b:"3" + +`, + `[Application Options] +; Show verbose debug information +verbose = true +verbose = true + +; Test default value +Default = "quote me" + +; Test default array value +DefaultArray = "1" +DefaultArray = "2" +DefaultArray = "3" + +; Testdefault map value +; DefaultMap = + +; Test env-default1 value +EnvDefault1 = env-def + +; Test env-default2 value +EnvDefault2 = env-def + +[Other Options] +; A slice of strings +; StringSlice = + +; A map from string to int +int-map = a:"2" +int-map = b:"3" + +`, + }, + } + + for _, test := range tests { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + read := strings.NewReader(test.read) + err := inip.Parse(read) + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + var write bytes.Buffer + inip.Write(&write, test.options) + + got := write.String() + + msg := fmt.Sprintf("with ini options %b", test.options) + assertDiff(t, got, test.write, msg) + } +} + +func TestReadIniWrongQuoting(t *testing.T) { + var tests = []struct { + iniFile string + lineNumber uint + }{ + { + iniFile: `Default = "New\nvalue`, + lineNumber: 1, + }, + { + iniFile: `StringSlice = "New\nvalue`, + lineNumber: 1, + }, + { + iniFile: `StringSlice = "New\nvalue" + StringSlice = "Second\nvalue`, + lineNumber: 2, + }, + { + iniFile: `DefaultMap = some:"value`, + lineNumber: 1, + }, + { + iniFile: `DefaultMap = some:value + DefaultMap = another:"value`, + lineNumber: 2, + }, + } + + for _, test := range tests { + var opts helpOptions + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + inic := test.iniFile + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err == nil { + t.Fatalf("Expect error") + } + + iniError := err.(*IniError) + + if iniError.LineNumber != test.lineNumber { + t.Fatalf("Expect error on line %d", test.lineNumber) + } + } +} + +func TestIniCommands(t *testing.T) { + var opts struct { + Value string `short:"v" long:"value"` + + Add struct { + Name int `short:"n" long:"name" ini-name:"AliasName"` + + Other struct { + O string `short:"o" long:"other"` + } `group:"Other Options"` + } `command:"add"` + } + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + inic := `[Application Options] +value = some value + +[add] +AliasName = 5 + +[add.Other Options] +other = subgroup + +` + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + assertString(t, opts.Value, "some value") + + if opts.Add.Name != 5 { + t.Errorf("Expected opts.Add.Name to be 5, but got %v", opts.Add.Name) + } + + assertString(t, opts.Add.Other.O, "subgroup") + + // Test writing it back + buf := &bytes.Buffer{} + + inip.Write(buf, IniDefault) + + assertDiff(t, buf.String(), inic, "ini contents") +} + +func TestIniNoIni(t *testing.T) { + var opts struct { + NoValue string `short:"n" long:"novalue" no-ini:"yes"` + Value string `short:"v" long:"value"` + } + + p := NewNamedParser("TestIni", Default) + p.AddGroup("Application Options", "The application options", &opts) + + inip := NewIniParser(p) + + // read INI + inic := `[Application Options] +novalue = some value +value = some other value +` + + b := strings.NewReader(inic) + err := inip.Parse(b) + + if err == nil { + t.Fatalf("Expected error") + } + + iniError := err.(*IniError) + + if v := uint(2); iniError.LineNumber != v { + t.Errorf("Expected opts.Add.Name to be %d, but got %d", v, iniError.LineNumber) + } + + if v := "unknown option: novalue"; iniError.Message != v { + t.Errorf("Expected opts.Add.Name to be %s, but got %s", v, iniError.Message) + } + + // write INI + opts.NoValue = "some value" + opts.Value = "some other value" + + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + defer os.Remove(file.Name()) + + err = inip.WriteFile(file.Name(), IniIncludeDefaults) + if err != nil { + t.Fatalf("Could not write ini file: %s", err) + } + + found, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatalf("Could not read written ini file: %s", err) + } + + expected := "[Application Options]\nValue = some other value\n\n" + + assertDiff(t, string(found), expected, "ini content") +} + +func TestIniParse(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + defer os.Remove(file.Name()) + + _, err = file.WriteString("value = 123") + if err != nil { + t.Fatalf("Cannot write to temporary file: %s", err) + } + + file.Close() + + var opts struct { + Value int `long:"value"` + } + + err = IniParse(file.Name(), &opts) + if err != nil { + t.Fatalf("Could not parse ini: %s", err) + } + + if opts.Value != 123 { + t.Fatalf("Expected Value to be \"123\" but was \"%d\"", opts.Value) + } +} + +func TestIniCliOverrides(t *testing.T) { + file, err := ioutil.TempFile("", "") + + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + + defer os.Remove(file.Name()) + + _, err = file.WriteString("values = 123\n") + _, err = file.WriteString("values = 456\n") + + if err != nil { + t.Fatalf("Cannot write to temporary file: %s", err) + } + + file.Close() + + var opts struct { + Values []int `long:"values"` + } + + p := NewParser(&opts, Default) + err = NewIniParser(p).ParseFile(file.Name()) + + if err != nil { + t.Fatalf("Could not parse ini: %s", err) + } + + _, err = p.ParseArgs([]string{"--values", "111", "--values", "222"}) + + if err != nil { + t.Fatalf("Failed to parse arguments: %s", err) + } + + if len(opts.Values) != 2 { + t.Fatalf("Expected Values to contain two elements, but got %d", len(opts.Values)) + } + + if opts.Values[0] != 111 { + t.Fatalf("Expected Values[0] to be 111, but got '%d'", opts.Values[0]) + } + + if opts.Values[1] != 222 { + t.Fatalf("Expected Values[1] to be 222, but got '%d'", opts.Values[1]) + } +} + +func TestIniOverrides(t *testing.T) { + file, err := ioutil.TempFile("", "") + + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + + defer os.Remove(file.Name()) + + _, err = file.WriteString("value-with-default = \"ini-value\"\n") + _, err = file.WriteString("value-with-default-override-cli = \"ini-value\"\n") + + if err != nil { + t.Fatalf("Cannot write to temporary file: %s", err) + } + + file.Close() + + var opts struct { + ValueWithDefault string `long:"value-with-default" default:"value"` + ValueWithDefaultOverrideCli string `long:"value-with-default-override-cli" default:"value"` + } + + p := NewParser(&opts, Default) + err = NewIniParser(p).ParseFile(file.Name()) + + if err != nil { + t.Fatalf("Could not parse ini: %s", err) + } + + _, err = p.ParseArgs([]string{"--value-with-default-override-cli", "cli-value"}) + + if err != nil { + t.Fatalf("Failed to parse arguments: %s", err) + } + + assertString(t, opts.ValueWithDefault, "ini-value") + assertString(t, opts.ValueWithDefaultOverrideCli, "cli-value") +} + +func TestIniRequired(t *testing.T) { + var opts struct { + Required string `short:"r" required:"yes" description:"required"` + Config func(s string) error `long:"config" default:"no-ini-file" no-ini:"true"` + } + + p := NewParser(&opts, Default) + + opts.Config = func(s string) error { + inip := NewIniParser(p) + inip.ParseAsDefaults = true + return inip.Parse(strings.NewReader("Required = ini-value\n")) + } + + _, err := p.ParseArgs([]string{"-r", "cli-value"}) + + if err != nil { + t.Fatalf("Failed to parse arguments: %s", err) + } + + assertString(t, opts.Required, "cli-value") +} + +func TestWriteFile(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Cannot create temporary file: %s", err) + } + defer os.Remove(file.Name()) + + var opts struct { + Value int `long:"value"` + } + + opts.Value = 123 + + p := NewParser(&opts, Default) + ini := NewIniParser(p) + + err = ini.WriteFile(file.Name(), IniIncludeDefaults) + if err != nil { + t.Fatalf("Could not write ini file: %s", err) + } + + found, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatalf("Could not read written ini file: %s", err) + } + + expected := "[Application Options]\nValue = 123\n\n" + + assertDiff(t, string(found), expected, "ini content") +} + +func TestOverwriteRequiredOptions(t *testing.T) { + var tests = []struct { + args []string + expected []string + }{ + { + args: []string{"--value", "from CLI"}, + expected: []string{ + "from CLI", + "from default", + }, + }, + { + args: []string{"--value", "from CLI", "--default", "from CLI"}, + expected: []string{ + "from CLI", + "from CLI", + }, + }, + { + args: []string{"--config", "no file name"}, + expected: []string{ + "from INI", + "from INI", + }, + }, + { + args: []string{"--value", "from CLI before", "--default", "from CLI before", "--config", "no file name"}, + expected: []string{ + "from INI", + "from INI", + }, + }, + { + args: []string{"--value", "from CLI before", "--default", "from CLI before", "--config", "no file name", "--value", "from CLI after", "--default", "from CLI after"}, + expected: []string{ + "from CLI after", + "from CLI after", + }, + }, + } + + for _, test := range tests { + var opts struct { + Config func(s string) error `long:"config" no-ini:"true"` + Value string `long:"value" required:"true"` + Default string `long:"default" required:"true" default:"from default"` + } + + p := NewParser(&opts, Default) + + opts.Config = func(s string) error { + ini := NewIniParser(p) + + return ini.Parse(bytes.NewBufferString("value = from INI\ndefault = from INI")) + } + + _, err := p.ParseArgs(test.args) + if err != nil { + t.Fatalf("Unexpected error %s with args %+v", err, test.args) + } + + if opts.Value != test.expected[0] { + t.Fatalf("Expected Value to be \"%s\" but was \"%s\" with args %+v", test.expected[0], opts.Value, test.args) + } + + if opts.Default != test.expected[1] { + t.Fatalf("Expected Default to be \"%s\" but was \"%s\" with args %+v", test.expected[1], opts.Default, test.args) + } + } +} + +func TestIniOverwriteOptions(t *testing.T) { + var tests = []struct { + args []string + expected string + toggled bool + }{ + { + args: []string{}, + expected: "from default", + }, + { + args: []string{"--value", "from CLI"}, + expected: "from CLI", + }, + { + args: []string{"--config", "no file name"}, + expected: "from INI", + toggled: true, + }, + { + args: []string{"--value", "from CLI before", "--config", "no file name"}, + expected: "from CLI before", + toggled: true, + }, + { + args: []string{"--config", "no file name", "--value", "from CLI after"}, + expected: "from CLI after", + toggled: true, + }, + { + args: []string{"--toggle"}, + toggled: true, + expected: "from default", + }, + } + + for _, test := range tests { + var opts struct { + Config string `long:"config" no-ini:"true"` + Value string `long:"value" default:"from default"` + Toggle bool `long:"toggle"` + } + + p := NewParser(&opts, Default) + + _, err := p.ParseArgs(test.args) + if err != nil { + t.Fatalf("Unexpected error %s with args %+v", err, test.args) + } + + if opts.Config != "" { + inip := NewIniParser(p) + inip.ParseAsDefaults = true + + err = inip.Parse(bytes.NewBufferString("value = from INI\ntoggle = true")) + if err != nil { + t.Fatalf("Unexpected error %s with args %+v", err, test.args) + } + } + + if opts.Value != test.expected { + t.Fatalf("Expected Value to be \"%s\" but was \"%s\" with args %+v", test.expected, opts.Value, test.args) + } + + if opts.Toggle != test.toggled { + t.Fatalf("Expected Toggle to be \"%v\" but was \"%v\" with args %+v", test.toggled, opts.Toggle, test.args) + } + + } +} diff --git a/vendor/github.com/jessevdk/go-flags/long_test.go b/vendor/github.com/jessevdk/go-flags/long_test.go new file mode 100644 index 00000000..02fc8c70 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/long_test.go @@ -0,0 +1,85 @@ +package flags + +import ( + "testing" +) + +func TestLong(t *testing.T) { + var opts = struct { + Value bool `long:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value") + + assertStringArray(t, ret, []string{}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestLongArg(t *testing.T) { + var opts = struct { + Value string `long:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value", "value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongArgEqual(t *testing.T) { + var opts = struct { + Value string `long:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value=value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongDefault(t *testing.T) { + var opts = struct { + Value string `long:"value" default:"value"` + }{} + + ret := assertParseSuccess(t, &opts) + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongOptional(t *testing.T) { + var opts = struct { + Value string `long:"value" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestLongOptionalArg(t *testing.T) { + var opts = struct { + Value string `long:"value" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value", "no") + + assertStringArray(t, ret, []string{"no"}) + assertString(t, opts.Value, "value") +} + +func TestLongOptionalArgEqual(t *testing.T) { + var opts = struct { + Value string `long:"value" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "--value=value", "no") + + assertStringArray(t, ret, []string{"no"}) + assertString(t, opts.Value, "value") +} diff --git a/vendor/github.com/jessevdk/go-flags/man.go b/vendor/github.com/jessevdk/go-flags/man.go new file mode 100644 index 00000000..0cb114e7 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/man.go @@ -0,0 +1,205 @@ +package flags + +import ( + "fmt" + "io" + "runtime" + "strings" + "time" +) + +func manQuote(s string) string { + return strings.Replace(s, "\\", "\\\\", -1) +} + +func formatForMan(wr io.Writer, s string) { + for { + idx := strings.IndexRune(s, '`') + + if idx < 0 { + fmt.Fprintf(wr, "%s", manQuote(s)) + break + } + + fmt.Fprintf(wr, "%s", manQuote(s[:idx])) + + s = s[idx+1:] + idx = strings.IndexRune(s, '\'') + + if idx < 0 { + fmt.Fprintf(wr, "%s", manQuote(s)) + break + } + + fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx])) + s = s[idx+1:] + } +} + +func writeManPageOptions(wr io.Writer, grp *Group) { + grp.eachGroup(func(group *Group) { + if group.Hidden || len(group.options) == 0 { + return + } + + // If the parent (grp) has any subgroups, display their descriptions as + // subsection headers similar to the output of --help. + if group.ShortDescription != "" && len(grp.groups) > 0 { + fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription) + + if group.LongDescription != "" { + formatForMan(wr, group.LongDescription) + fmt.Fprintln(wr, "") + } + } + + for _, opt := range group.options { + if !opt.canCli() || opt.Hidden { + continue + } + + fmt.Fprintln(wr, ".TP") + fmt.Fprintf(wr, "\\fB") + + if opt.ShortName != 0 { + fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName) + } + + if len(opt.LongName) != 0 { + if opt.ShortName != 0 { + fmt.Fprintf(wr, ", ") + } + + fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace())) + } + + if len(opt.ValueName) != 0 || opt.OptionalArgument { + if opt.OptionalArgument { + fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", "))) + } else { + fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName)) + } + } + + if len(opt.Default) != 0 { + fmt.Fprintf(wr, " ", manQuote(strings.Join(quoteV(opt.Default), ", "))) + } else if len(opt.EnvDefaultKey) != 0 { + if runtime.GOOS == "windows" { + fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + } else { + fmt.Fprintf(wr, " ", manQuote(opt.EnvDefaultKey)) + } + } + + if opt.Required { + fmt.Fprintf(wr, " (\\fIrequired\\fR)") + } + + fmt.Fprintln(wr, "\\fP") + + if len(opt.Description) != 0 { + formatForMan(wr, opt.Description) + fmt.Fprintln(wr, "") + } + } + }) +} + +func writeManPageSubcommands(wr io.Writer, name string, root *Command) { + commands := root.sortedVisibleCommands() + + for _, c := range commands { + var nn string + + if c.Hidden { + continue + } + + if len(name) != 0 { + nn = name + " " + c.Name + } else { + nn = c.Name + } + + writeManPageCommand(wr, nn, root, c) + } +} + +func writeManPageCommand(wr io.Writer, name string, root *Command, command *Command) { + fmt.Fprintf(wr, ".SS %s\n", name) + fmt.Fprintln(wr, command.ShortDescription) + + if len(command.LongDescription) > 0 { + fmt.Fprintln(wr, "") + + cmdstart := fmt.Sprintf("The %s command", manQuote(command.Name)) + + if strings.HasPrefix(command.LongDescription, cmdstart) { + fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name)) + + formatForMan(wr, command.LongDescription[len(cmdstart):]) + fmt.Fprintln(wr, "") + } else { + formatForMan(wr, command.LongDescription) + fmt.Fprintln(wr, "") + } + } + + var usage string + if us, ok := command.data.(Usage); ok { + usage = us.Usage() + } else if command.hasCliOptions() { + usage = fmt.Sprintf("[%s-OPTIONS]", command.Name) + } + + var pre string + if root.hasCliOptions() { + pre = fmt.Sprintf("%s [OPTIONS] %s", root.Name, command.Name) + } else { + pre = fmt.Sprintf("%s %s", root.Name, command.Name) + } + + if len(usage) > 0 { + fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage)) + } + + if len(command.Aliases) > 0 { + fmt.Fprintf(wr, "\n\\fBAliases\\fP: %s\n\n", manQuote(strings.Join(command.Aliases, ", "))) + } + + writeManPageOptions(wr, command.Group) + writeManPageSubcommands(wr, name, command) +} + +// WriteManPage writes a basic man page in groff format to the specified +// writer. +func (p *Parser) WriteManPage(wr io.Writer) { + t := time.Now() + + fmt.Fprintf(wr, ".TH %s 1 \"%s\"\n", manQuote(p.Name), t.Format("2 January 2006")) + fmt.Fprintln(wr, ".SH NAME") + fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuote(p.ShortDescription)) + fmt.Fprintln(wr, ".SH SYNOPSIS") + + usage := p.Usage + + if len(usage) == 0 { + usage = "[OPTIONS]" + } + + fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage)) + fmt.Fprintln(wr, ".SH DESCRIPTION") + + formatForMan(wr, p.LongDescription) + fmt.Fprintln(wr, "") + + fmt.Fprintln(wr, ".SH OPTIONS") + + writeManPageOptions(wr, p.Command.Group) + + if len(p.visibleCommands()) > 0 { + fmt.Fprintln(wr, ".SH COMMANDS") + + writeManPageSubcommands(wr, "", p.Command) + } +} diff --git a/vendor/github.com/jessevdk/go-flags/marshal_test.go b/vendor/github.com/jessevdk/go-flags/marshal_test.go new file mode 100644 index 00000000..4cfe8656 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/marshal_test.go @@ -0,0 +1,119 @@ +package flags + +import ( + "fmt" + "testing" +) + +type marshalled string + +func (m *marshalled) UnmarshalFlag(value string) error { + if value == "yes" { + *m = "true" + } else if value == "no" { + *m = "false" + } else { + return fmt.Errorf("`%s' is not a valid value, please specify `yes' or `no'", value) + } + + return nil +} + +func (m marshalled) MarshalFlag() (string, error) { + if m == "true" { + return "yes", nil + } + + return "no", nil +} + +type marshalledError bool + +func (m marshalledError) MarshalFlag() (string, error) { + return "", newErrorf(ErrMarshal, "Failed to marshal") +} + +func TestUnmarshal(t *testing.T) { + var opts = struct { + Value marshalled `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v=yes") + + assertStringArray(t, ret, []string{}) + + if opts.Value != "true" { + t.Errorf("Expected Value to be \"true\"") + } +} + +func TestUnmarshalDefault(t *testing.T) { + var opts = struct { + Value marshalled `short:"v" default:"yes"` + }{} + + ret := assertParseSuccess(t, &opts) + + assertStringArray(t, ret, []string{}) + + if opts.Value != "true" { + t.Errorf("Expected Value to be \"true\"") + } +} + +func TestUnmarshalOptional(t *testing.T) { + var opts = struct { + Value marshalled `short:"v" optional:"yes" optional-value:"yes"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if opts.Value != "true" { + t.Errorf("Expected Value to be \"true\"") + } +} + +func TestUnmarshalError(t *testing.T) { + var opts = struct { + Value marshalled `short:"v"` + }{} + + assertParseFail(t, ErrMarshal, fmt.Sprintf("invalid argument for flag `%cv' (expected flags.marshalled): `invalid' is not a valid value, please specify `yes' or `no'", defaultShortOptDelimiter), &opts, "-vinvalid") +} + +func TestUnmarshalPositionalError(t *testing.T) { + var opts = struct { + Args struct { + Value marshalled + } `positional-args:"yes"` + }{} + + parser := NewParser(&opts, Default&^PrintErrors) + _, err := parser.ParseArgs([]string{"invalid"}) + + msg := "`invalid' is not a valid value, please specify `yes' or `no'" + + if err == nil { + assertFatalf(t, "Expected error: %s", msg) + return + } + + if err.Error() != msg { + assertErrorf(t, "Expected error message %#v, but got %#v", msg, err.Error()) + } +} + +func TestMarshalError(t *testing.T) { + var opts = struct { + Value marshalledError `short:"v"` + }{} + + p := NewParser(&opts, Default) + o := p.Command.Groups()[0].Options()[0] + + _, err := convertToString(o.value, o.tag) + + assertError(t, err, ErrMarshal, "Failed to marshal") +} diff --git a/vendor/github.com/jessevdk/go-flags/multitag.go b/vendor/github.com/jessevdk/go-flags/multitag.go new file mode 100644 index 00000000..96bb1a31 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/multitag.go @@ -0,0 +1,140 @@ +package flags + +import ( + "strconv" +) + +type multiTag struct { + value string + cache map[string][]string +} + +func newMultiTag(v string) multiTag { + return multiTag{ + value: v, + } +} + +func (x *multiTag) scan() (map[string][]string, error) { + v := x.value + + ret := make(map[string][]string) + + // This is mostly copied from reflect.StructTag.Get + for v != "" { + i := 0 + + // Skip whitespace + for i < len(v) && v[i] == ' ' { + i++ + } + + v = v[i:] + + if v == "" { + break + } + + // Scan to colon to find key + i = 0 + + for i < len(v) && v[i] != ' ' && v[i] != ':' && v[i] != '"' { + i++ + } + + if i >= len(v) { + return nil, newErrorf(ErrTag, "expected `:' after key name, but got end of tag (in `%v`)", x.value) + } + + if v[i] != ':' { + return nil, newErrorf(ErrTag, "expected `:' after key name, but got `%v' (in `%v`)", v[i], x.value) + } + + if i+1 >= len(v) { + return nil, newErrorf(ErrTag, "expected `\"' to start tag value at end of tag (in `%v`)", x.value) + } + + if v[i+1] != '"' { + return nil, newErrorf(ErrTag, "expected `\"' to start tag value, but got `%v' (in `%v`)", v[i+1], x.value) + } + + name := v[:i] + v = v[i+1:] + + // Scan quoted string to find value + i = 1 + + for i < len(v) && v[i] != '"' { + if v[i] == '\n' { + return nil, newErrorf(ErrTag, "unexpected newline in tag value `%v' (in `%v`)", name, x.value) + } + + if v[i] == '\\' { + i++ + } + i++ + } + + if i >= len(v) { + return nil, newErrorf(ErrTag, "expected end of tag value `\"' at end of tag (in `%v`)", x.value) + } + + val, err := strconv.Unquote(v[:i+1]) + + if err != nil { + return nil, newErrorf(ErrTag, "Malformed value of tag `%v:%v` => %v (in `%v`)", name, v[:i+1], err, x.value) + } + + v = v[i+1:] + + ret[name] = append(ret[name], val) + } + + return ret, nil +} + +func (x *multiTag) Parse() error { + vals, err := x.scan() + x.cache = vals + + return err +} + +func (x *multiTag) cached() map[string][]string { + if x.cache == nil { + cache, _ := x.scan() + + if cache == nil { + cache = make(map[string][]string) + } + + x.cache = cache + } + + return x.cache +} + +func (x *multiTag) Get(key string) string { + c := x.cached() + + if v, ok := c[key]; ok { + return v[len(v)-1] + } + + return "" +} + +func (x *multiTag) GetMany(key string) []string { + c := x.cached() + return c[key] +} + +func (x *multiTag) Set(key string, value string) { + c := x.cached() + c[key] = []string{value} +} + +func (x *multiTag) SetMany(key string, value []string) { + c := x.cached() + c[key] = value +} diff --git a/vendor/github.com/jessevdk/go-flags/option.go b/vendor/github.com/jessevdk/go-flags/option.go new file mode 100644 index 00000000..ea09fb4a --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/option.go @@ -0,0 +1,461 @@ +package flags + +import ( + "bytes" + "fmt" + "reflect" + "strings" + "syscall" + "unicode/utf8" +) + +// Option flag information. Contains a description of the option, short and +// long name as well as a default value and whether an argument for this +// flag is optional. +type Option struct { + // The description of the option flag. This description is shown + // automatically in the built-in help. + Description string + + // The short name of the option (a single character). If not 0, the + // option flag can be 'activated' using -. Either ShortName + // or LongName needs to be non-empty. + ShortName rune + + // The long name of the option. If not "", the option flag can be + // activated using --. Either ShortName or LongName needs + // to be non-empty. + LongName string + + // The default value of the option. + Default []string + + // The optional environment default value key name. + EnvDefaultKey string + + // The optional delimiter string for EnvDefaultKey values. + EnvDefaultDelim string + + // If true, specifies that the argument to an option flag is optional. + // When no argument to the flag is specified on the command line, the + // value of OptionalValue will be set in the field this option represents. + // This is only valid for non-boolean options. + OptionalArgument bool + + // The optional value of the option. The optional value is used when + // the option flag is marked as having an OptionalArgument. This means + // that when the flag is specified, but no option argument is given, + // the value of the field this option represents will be set to + // OptionalValue. This is only valid for non-boolean options. + OptionalValue []string + + // If true, the option _must_ be specified on the command line. If the + // option is not specified, the parser will generate an ErrRequired type + // error. + Required bool + + // A name for the value of an option shown in the Help as --flag [ValueName] + ValueName string + + // A mask value to show in the help instead of the default value. This + // is useful for hiding sensitive information in the help, such as + // passwords. + DefaultMask string + + // If non empty, only a certain set of values is allowed for an option. + Choices []string + + // If true, the option is not displayed in the help or man page + Hidden bool + + // The group which the option belongs to + group *Group + + // The struct field which the option represents. + field reflect.StructField + + // The struct field value which the option represents. + value reflect.Value + + // Determines if the option will be always quoted in the INI output + iniQuote bool + + tag multiTag + isSet bool + isSetDefault bool + preventDefault bool + + defaultLiteral string +} + +// LongNameWithNamespace returns the option's long name with the group namespaces +// prepended by walking up the option's group tree. Namespaces and the long name +// itself are separated by the parser's namespace delimiter. If the long name is +// empty an empty string is returned. +func (option *Option) LongNameWithNamespace() string { + if len(option.LongName) == 0 { + return "" + } + + // fetch the namespace delimiter from the parser which is always at the + // end of the group hierarchy + namespaceDelimiter := "" + g := option.group + + for { + if p, ok := g.parent.(*Parser); ok { + namespaceDelimiter = p.NamespaceDelimiter + + break + } + + switch i := g.parent.(type) { + case *Command: + g = i.Group + case *Group: + g = i + } + } + + // concatenate long name with namespace + longName := option.LongName + g = option.group + + for g != nil { + if g.Namespace != "" { + longName = g.Namespace + namespaceDelimiter + longName + } + + switch i := g.parent.(type) { + case *Command: + g = i.Group + case *Group: + g = i + case *Parser: + g = nil + } + } + + return longName +} + +// String converts an option to a human friendly readable string describing the +// option. +func (option *Option) String() string { + var s string + var short string + + if option.ShortName != 0 { + data := make([]byte, utf8.RuneLen(option.ShortName)) + utf8.EncodeRune(data, option.ShortName) + short = string(data) + + if len(option.LongName) != 0 { + s = fmt.Sprintf("%s%s, %s%s", + string(defaultShortOptDelimiter), short, + defaultLongOptDelimiter, option.LongNameWithNamespace()) + } else { + s = fmt.Sprintf("%s%s", string(defaultShortOptDelimiter), short) + } + } else if len(option.LongName) != 0 { + s = fmt.Sprintf("%s%s", defaultLongOptDelimiter, option.LongNameWithNamespace()) + } + + return s +} + +// Value returns the option value as an interface{}. +func (option *Option) Value() interface{} { + return option.value.Interface() +} + +// Field returns the reflect struct field of the option. +func (option *Option) Field() reflect.StructField { + return option.field +} + +// IsSet returns true if option has been set +func (option *Option) IsSet() bool { + return option.isSet +} + +// IsSetDefault returns true if option has been set via the default option tag +func (option *Option) IsSetDefault() bool { + return option.isSetDefault +} + +// Set the value of an option to the specified value. An error will be returned +// if the specified value could not be converted to the corresponding option +// value type. +func (option *Option) set(value *string) error { + kind := option.value.Type().Kind() + + if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet { + option.empty() + } + + option.isSet = true + option.preventDefault = true + + if len(option.Choices) != 0 { + found := false + + for _, choice := range option.Choices { + if choice == *value { + found = true + break + } + } + + if !found { + allowed := strings.Join(option.Choices[0:len(option.Choices)-1], ", ") + + if len(option.Choices) > 1 { + allowed += " or " + option.Choices[len(option.Choices)-1] + } + + return newErrorf(ErrInvalidChoice, + "Invalid value `%s' for option `%s'. Allowed values are: %s", + *value, option, allowed) + } + } + + if option.isFunc() { + return option.call(value) + } else if value != nil { + return convert(*value, option.value, option.tag) + } + + return convert("", option.value, option.tag) +} + +func (option *Option) canCli() bool { + return option.ShortName != 0 || len(option.LongName) != 0 +} + +func (option *Option) canArgument() bool { + if u := option.isUnmarshaler(); u != nil { + return true + } + + return !option.isBool() +} + +func (option *Option) emptyValue() reflect.Value { + tp := option.value.Type() + + if tp.Kind() == reflect.Map { + return reflect.MakeMap(tp) + } + + return reflect.Zero(tp) +} + +func (option *Option) empty() { + if !option.isFunc() { + option.value.Set(option.emptyValue()) + } +} + +func (option *Option) clearDefault() { + usedDefault := option.Default + + if envKey := option.EnvDefaultKey; envKey != "" { + // os.Getenv() makes no distinction between undefined and + // empty values, so we use syscall.Getenv() + if value, ok := syscall.Getenv(envKey); ok { + if option.EnvDefaultDelim != "" { + usedDefault = strings.Split(value, + option.EnvDefaultDelim) + } else { + usedDefault = []string{value} + } + } + } + + option.isSetDefault = true + + if len(usedDefault) > 0 { + option.empty() + + for _, d := range usedDefault { + option.set(&d) + option.isSetDefault = true + } + } else { + tp := option.value.Type() + + switch tp.Kind() { + case reflect.Map: + if option.value.IsNil() { + option.empty() + } + case reflect.Slice: + if option.value.IsNil() { + option.empty() + } + } + } +} + +func (option *Option) valueIsDefault() bool { + // Check if the value of the option corresponds to its + // default value + emptyval := option.emptyValue() + + checkvalptr := reflect.New(emptyval.Type()) + checkval := reflect.Indirect(checkvalptr) + + checkval.Set(emptyval) + + if len(option.Default) != 0 { + for _, v := range option.Default { + convert(v, checkval, option.tag) + } + } + + return reflect.DeepEqual(option.value.Interface(), checkval.Interface()) +} + +func (option *Option) isUnmarshaler() Unmarshaler { + v := option.value + + for { + if !v.CanInterface() { + break + } + + i := v.Interface() + + if u, ok := i.(Unmarshaler); ok { + return u + } + + if !v.CanAddr() { + break + } + + v = v.Addr() + } + + return nil +} + +func (option *Option) isBool() bool { + tp := option.value.Type() + + for { + switch tp.Kind() { + case reflect.Slice, reflect.Ptr: + tp = tp.Elem() + case reflect.Bool: + return true + case reflect.Func: + return tp.NumIn() == 0 + default: + return false + } + } +} + +func (option *Option) isSignedNumber() bool { + tp := option.value.Type() + + for { + switch tp.Kind() { + case reflect.Slice, reflect.Ptr: + tp = tp.Elem() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64: + return true + default: + return false + } + } +} + +func (option *Option) isFunc() bool { + return option.value.Type().Kind() == reflect.Func +} + +func (option *Option) call(value *string) error { + var retval []reflect.Value + + if value == nil { + retval = option.value.Call(nil) + } else { + tp := option.value.Type().In(0) + + val := reflect.New(tp) + val = reflect.Indirect(val) + + if err := convert(*value, val, option.tag); err != nil { + return err + } + + retval = option.value.Call([]reflect.Value{val}) + } + + if len(retval) == 1 && retval[0].Type() == reflect.TypeOf((*error)(nil)).Elem() { + if retval[0].Interface() == nil { + return nil + } + + return retval[0].Interface().(error) + } + + return nil +} + +func (option *Option) updateDefaultLiteral() { + defs := option.Default + def := "" + + if len(defs) == 0 && option.canArgument() { + var showdef bool + + switch option.field.Type.Kind() { + case reflect.Func, reflect.Ptr: + showdef = !option.value.IsNil() + case reflect.Slice, reflect.String, reflect.Array: + showdef = option.value.Len() > 0 + case reflect.Map: + showdef = !option.value.IsNil() && option.value.Len() > 0 + default: + zeroval := reflect.Zero(option.field.Type) + showdef = !reflect.DeepEqual(zeroval.Interface(), option.value.Interface()) + } + + if showdef { + def, _ = convertToString(option.value, option.tag) + } + } else if len(defs) != 0 { + l := len(defs) - 1 + + for i := 0; i < l; i++ { + def += quoteIfNeeded(defs[i]) + ", " + } + + def += quoteIfNeeded(defs[l]) + } + + option.defaultLiteral = def +} + +func (option *Option) shortAndLongName() string { + ret := &bytes.Buffer{} + + if option.ShortName != 0 { + ret.WriteRune(defaultShortOptDelimiter) + ret.WriteRune(option.ShortName) + } + + if len(option.LongName) != 0 { + if option.ShortName != 0 { + ret.WriteRune('/') + } + + ret.WriteString(option.LongName) + } + + return ret.String() +} diff --git a/vendor/github.com/jessevdk/go-flags/options_test.go b/vendor/github.com/jessevdk/go-flags/options_test.go new file mode 100644 index 00000000..b0fe9f45 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/options_test.go @@ -0,0 +1,45 @@ +package flags + +import ( + "testing" +) + +func TestPassDoubleDash(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + p := NewParser(&opts, PassDoubleDash) + ret, err := p.ParseArgs([]string{"-v", "--", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + assertStringArray(t, ret, []string{"-v", "-g"}) +} + +func TestPassAfterNonOption(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + p := NewParser(&opts, PassAfterNonOption) + ret, err := p.ParseArgs([]string{"-v", "arg", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + assertStringArray(t, ret, []string{"arg", "-v", "-g"}) +} diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_other.go b/vendor/github.com/jessevdk/go-flags/optstyle_other.go new file mode 100644 index 00000000..56dfdae1 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/optstyle_other.go @@ -0,0 +1,67 @@ +// +build !windows forceposix + +package flags + +import ( + "strings" +) + +const ( + defaultShortOptDelimiter = '-' + defaultLongOptDelimiter = "--" + defaultNameArgDelimiter = '=' +) + +func argumentStartsOption(arg string) bool { + return len(arg) > 0 && arg[0] == '-' +} + +func argumentIsOption(arg string) bool { + if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' { + return true + } + + if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' { + return true + } + + return false +} + +// stripOptionPrefix returns the option without the prefix and whether or +// not the option is a long option or not. +func stripOptionPrefix(optname string) (prefix string, name string, islong bool) { + if strings.HasPrefix(optname, "--") { + return "--", optname[2:], true + } else if strings.HasPrefix(optname, "-") { + return "-", optname[1:], false + } + + return "", optname, false +} + +// splitOption attempts to split the passed option into a name and an argument. +// When there is no argument specified, nil will be returned for it. +func splitOption(prefix string, option string, islong bool) (string, string, *string) { + pos := strings.Index(option, "=") + + if (islong && pos >= 0) || (!islong && pos == 1) { + rest := option[pos+1:] + return option[:pos], "=", &rest + } + + return option, "", nil +} + +// addHelpGroup adds a new group that contains default help parameters. +func (c *Command) addHelpGroup(showHelp func() error) *Group { + var help struct { + ShowHelp func() error `short:"h" long:"help" description:"Show this help message"` + } + + help.ShowHelp = showHelp + ret, _ := c.AddGroup("Help Options", "", &help) + ret.isBuiltinHelp = true + + return ret +} diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_windows.go b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go new file mode 100644 index 00000000..f3f28aee --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go @@ -0,0 +1,108 @@ +// +build !forceposix + +package flags + +import ( + "strings" +) + +// Windows uses a front slash for both short and long options. Also it uses +// a colon for name/argument delimter. +const ( + defaultShortOptDelimiter = '/' + defaultLongOptDelimiter = "/" + defaultNameArgDelimiter = ':' +) + +func argumentStartsOption(arg string) bool { + return len(arg) > 0 && (arg[0] == '-' || arg[0] == '/') +} + +func argumentIsOption(arg string) bool { + // Windows-style options allow front slash for the option + // delimiter. + if len(arg) > 1 && arg[0] == '/' { + return true + } + + if len(arg) > 1 && arg[0] == '-' && arg[1] != '-' { + return true + } + + if len(arg) > 2 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-' { + return true + } + + return false +} + +// stripOptionPrefix returns the option without the prefix and whether or +// not the option is a long option or not. +func stripOptionPrefix(optname string) (prefix string, name string, islong bool) { + // Determine if the argument is a long option or not. Windows + // typically supports both long and short options with a single + // front slash as the option delimiter, so handle this situation + // nicely. + possplit := 0 + + if strings.HasPrefix(optname, "--") { + possplit = 2 + islong = true + } else if strings.HasPrefix(optname, "-") { + possplit = 1 + islong = false + } else if strings.HasPrefix(optname, "/") { + possplit = 1 + islong = len(optname) > 2 + } + + return optname[:possplit], optname[possplit:], islong +} + +// splitOption attempts to split the passed option into a name and an argument. +// When there is no argument specified, nil will be returned for it. +func splitOption(prefix string, option string, islong bool) (string, string, *string) { + if len(option) == 0 { + return option, "", nil + } + + // Windows typically uses a colon for the option name and argument + // delimiter while POSIX typically uses an equals. Support both styles, + // but don't allow the two to be mixed. That is to say /foo:bar and + // --foo=bar are acceptable, but /foo=bar and --foo:bar are not. + var pos int + var sp string + + if prefix == "/" { + sp = ":" + pos = strings.Index(option, sp) + } else if len(prefix) > 0 { + sp = "=" + pos = strings.Index(option, sp) + } + + if (islong && pos >= 0) || (!islong && pos == 1) { + rest := option[pos+1:] + return option[:pos], sp, &rest + } + + return option, "", nil +} + +// addHelpGroup adds a new group that contains default help parameters. +func (c *Command) addHelpGroup(showHelp func() error) *Group { + // Windows CLI applications typically use /? for help, so make both + // that available as well as the POSIX style h and help. + var help struct { + ShowHelpWindows func() error `short:"?" description:"Show this help message"` + ShowHelpPosix func() error `short:"h" long:"help" description:"Show this help message"` + } + + help.ShowHelpWindows = showHelp + help.ShowHelpPosix = showHelp + + ret, _ := c.AddGroup("Help Options", "", &help) + ret.isBuiltinHelp = true + + return ret +} diff --git a/vendor/github.com/jessevdk/go-flags/parser.go b/vendor/github.com/jessevdk/go-flags/parser.go new file mode 100644 index 00000000..0a7922a0 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/parser.go @@ -0,0 +1,700 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( + "bytes" + "fmt" + "os" + "path" + "sort" + "strings" + "unicode/utf8" +) + +// A Parser provides command line option parsing. It can contain several +// option groups each with their own set of options. +type Parser struct { + // Embedded, see Command for more information + *Command + + // A usage string to be displayed in the help message. + Usage string + + // Option flags changing the behavior of the parser. + Options Options + + // NamespaceDelimiter separates group namespaces and option long names + NamespaceDelimiter string + + // UnknownOptionsHandler is a function which gets called when the parser + // encounters an unknown option. The function receives the unknown option + // name, a SplitArgument which specifies its value if set with an argument + // separator, and the remaining command line arguments. + // It should return a new list of remaining arguments to continue parsing, + // or an error to indicate a parse failure. + UnknownOptionHandler func(option string, arg SplitArgument, args []string) ([]string, error) + + // CompletionHandler is a function gets called to handle the completion of + // items. By default, the items are printed and the application is exited. + // You can override this default behavior by specifying a custom CompletionHandler. + CompletionHandler func(items []Completion) + + // CommandHandler is a function that gets called to handle execution of a + // command. By default, the command will simply be executed. This can be + // overridden to perform certain actions (such as applying global flags) + // just before the command is executed. Note that if you override the + // handler it is your responsibility to call the command.Execute function. + // + // The command passed into CommandHandler may be nil in case there is no + // command to be executed when parsing has finished. + CommandHandler func(command Commander, args []string) error + + internalError error +} + +// SplitArgument represents the argument value of an option that was passed using +// an argument separator. +type SplitArgument interface { + // String returns the option's value as a string, and a boolean indicating + // if the option was present. + Value() (string, bool) +} + +type strArgument struct { + value *string +} + +func (s strArgument) Value() (string, bool) { + if s.value == nil { + return "", false + } + + return *s.value, true +} + +// Options provides parser options that change the behavior of the option +// parser. +type Options uint + +const ( + // None indicates no options. + None Options = 0 + + // HelpFlag adds a default Help Options group to the parser containing + // -h and --help options. When either -h or --help is specified on the + // command line, the parser will return the special error of type + // ErrHelp. When PrintErrors is also specified, then the help message + // will also be automatically printed to os.Stdout. + HelpFlag = 1 << iota + + // PassDoubleDash passes all arguments after a double dash, --, as + // remaining command line arguments (i.e. they will not be parsed for + // flags). + PassDoubleDash + + // IgnoreUnknown ignores any unknown options and passes them as + // remaining command line arguments instead of generating an error. + IgnoreUnknown + + // PrintErrors prints any errors which occurred during parsing to + // os.Stderr. In the special case of ErrHelp, the message will be printed + // to os.Stdout. + PrintErrors + + // PassAfterNonOption passes all arguments after the first non option + // as remaining command line arguments. This is equivalent to strict + // POSIX processing. + PassAfterNonOption + + // Default is a convenient default set of options which should cover + // most of the uses of the flags package. + Default = HelpFlag | PrintErrors | PassDoubleDash +) + +type parseState struct { + arg string + args []string + retargs []string + positional []*Arg + err error + + command *Command + lookup lookup +} + +// Parse is a convenience function to parse command line options with default +// settings. The provided data is a pointer to a struct representing the +// default option group (named "Application Options"). For more control, use +// flags.NewParser. +func Parse(data interface{}) ([]string, error) { + return NewParser(data, Default).Parse() +} + +// ParseArgs is a convenience function to parse command line options with default +// settings. The provided data is a pointer to a struct representing the +// default option group (named "Application Options"). The args argument is +// the list of command line arguments to parse. If you just want to parse the +// default program command line arguments (i.e. os.Args), then use flags.Parse +// instead. For more control, use flags.NewParser. +func ParseArgs(data interface{}, args []string) ([]string, error) { + return NewParser(data, Default).ParseArgs(args) +} + +// NewParser creates a new parser. It uses os.Args[0] as the application +// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for +// more details). The provided data is a pointer to a struct representing the +// default option group (named "Application Options"), or nil if the default +// group should not be added. The options parameter specifies a set of options +// for the parser. +func NewParser(data interface{}, options Options) *Parser { + p := NewNamedParser(path.Base(os.Args[0]), options) + + if data != nil { + g, err := p.AddGroup("Application Options", "", data) + + if err == nil { + g.parent = p + } + + p.internalError = err + } + + return p +} + +// NewNamedParser creates a new parser. The appname is used to display the +// executable name in the built-in help message. Option groups and commands can +// be added to this parser by using AddGroup and AddCommand. +func NewNamedParser(appname string, options Options) *Parser { + p := &Parser{ + Command: newCommand(appname, "", "", nil), + Options: options, + NamespaceDelimiter: ".", + } + + p.Command.parent = p + + return p +} + +// Parse parses the command line arguments from os.Args using Parser.ParseArgs. +// For more detailed information see ParseArgs. +func (p *Parser) Parse() ([]string, error) { + return p.ParseArgs(os.Args[1:]) +} + +// ParseArgs parses the command line arguments according to the option groups that +// were added to the parser. On successful parsing of the arguments, the +// remaining, non-option, arguments (if any) are returned. The returned error +// indicates a parsing error and can be used with PrintError to display +// contextual information on where the error occurred exactly. +// +// When the common help group has been added (AddHelp) and either -h or --help +// was specified in the command line arguments, a help message will be +// automatically printed if the PrintErrors option is enabled. +// Furthermore, the special error type ErrHelp is returned. +// It is up to the caller to exit the program if so desired. +func (p *Parser) ParseArgs(args []string) ([]string, error) { + if p.internalError != nil { + return nil, p.internalError + } + + p.eachOption(func(c *Command, g *Group, option *Option) { + option.isSet = false + option.isSetDefault = false + option.updateDefaultLiteral() + }) + + // Add built-in help group to all commands if necessary + if (p.Options & HelpFlag) != None { + p.addHelpGroups(p.showBuiltinHelp) + } + + compval := os.Getenv("GO_FLAGS_COMPLETION") + + if len(compval) != 0 { + comp := &completion{parser: p} + items := comp.complete(args) + + if p.CompletionHandler != nil { + p.CompletionHandler(items) + } else { + comp.print(items, compval == "verbose") + os.Exit(0) + } + + return nil, nil + } + + s := &parseState{ + args: args, + retargs: make([]string, 0, len(args)), + } + + p.fillParseState(s) + + for !s.eof() { + arg := s.pop() + + // When PassDoubleDash is set and we encounter a --, then + // simply append all the rest as arguments and break out + if (p.Options&PassDoubleDash) != None && arg == "--" { + s.addArgs(s.args...) + break + } + + if !argumentIsOption(arg) { + // Note: this also sets s.err, so we can just check for + // nil here and use s.err later + if p.parseNonOption(s) != nil { + break + } + + continue + } + + var err error + + prefix, optname, islong := stripOptionPrefix(arg) + optname, _, argument := splitOption(prefix, optname, islong) + + if islong { + err = p.parseLong(s, optname, argument) + } else { + err = p.parseShort(s, optname, argument) + } + + if err != nil { + ignoreUnknown := (p.Options & IgnoreUnknown) != None + parseErr := wrapError(err) + + if parseErr.Type != ErrUnknownFlag || (!ignoreUnknown && p.UnknownOptionHandler == nil) { + s.err = parseErr + break + } + + if ignoreUnknown { + s.addArgs(arg) + } else if p.UnknownOptionHandler != nil { + modifiedArgs, err := p.UnknownOptionHandler(optname, strArgument{argument}, s.args) + + if err != nil { + s.err = err + break + } + + s.args = modifiedArgs + } + } + } + + if s.err == nil { + p.eachOption(func(c *Command, g *Group, option *Option) { + if option.preventDefault { + return + } + + option.clearDefault() + }) + + s.checkRequired(p) + } + + var reterr error + + if s.err != nil { + reterr = s.err + } else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional { + reterr = s.estimateCommand() + } else if cmd, ok := s.command.data.(Commander); ok { + if p.CommandHandler != nil { + reterr = p.CommandHandler(cmd, s.retargs) + } else { + reterr = cmd.Execute(s.retargs) + } + } else if p.CommandHandler != nil { + reterr = p.CommandHandler(nil, s.retargs) + } + + if reterr != nil { + var retargs []string + + if ourErr, ok := reterr.(*Error); !ok || ourErr.Type != ErrHelp { + retargs = append([]string{s.arg}, s.args...) + } else { + retargs = s.args + } + + return retargs, p.printError(reterr) + } + + return s.retargs, nil +} + +func (p *parseState) eof() bool { + return len(p.args) == 0 +} + +func (p *parseState) pop() string { + if p.eof() { + return "" + } + + p.arg = p.args[0] + p.args = p.args[1:] + + return p.arg +} + +func (p *parseState) peek() string { + if p.eof() { + return "" + } + + return p.args[0] +} + +func (p *parseState) checkRequired(parser *Parser) error { + c := parser.Command + + var required []*Option + + for c != nil { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + if !option.isSet && option.Required { + required = append(required, option) + } + } + }) + + c = c.Active + } + + if len(required) == 0 { + if len(p.positional) > 0 { + var reqnames []string + + for _, arg := range p.positional { + argRequired := (!arg.isRemaining() && p.command.ArgsRequired) || arg.Required != -1 || arg.RequiredMaximum != -1 + + if !argRequired { + continue + } + + if arg.isRemaining() { + if arg.value.Len() < arg.Required { + var arguments string + + if arg.Required > 1 { + arguments = "arguments, but got only " + fmt.Sprintf("%d", arg.value.Len()) + } else { + arguments = "argument" + } + + reqnames = append(reqnames, "`"+arg.Name+" (at least "+fmt.Sprintf("%d", arg.Required)+" "+arguments+")`") + } else if arg.RequiredMaximum != -1 && arg.value.Len() > arg.RequiredMaximum { + if arg.RequiredMaximum == 0 { + reqnames = append(reqnames, "`"+arg.Name+" (zero arguments)`") + } else { + var arguments string + + if arg.RequiredMaximum > 1 { + arguments = "arguments, but got " + fmt.Sprintf("%d", arg.value.Len()) + } else { + arguments = "argument" + } + + reqnames = append(reqnames, "`"+arg.Name+" (at most "+fmt.Sprintf("%d", arg.RequiredMaximum)+" "+arguments+")`") + } + } + } else { + reqnames = append(reqnames, "`"+arg.Name+"`") + } + } + + if len(reqnames) == 0 { + return nil + } + + var msg string + + if len(reqnames) == 1 { + msg = fmt.Sprintf("the required argument %s was not provided", reqnames[0]) + } else { + msg = fmt.Sprintf("the required arguments %s and %s were not provided", + strings.Join(reqnames[:len(reqnames)-1], ", "), reqnames[len(reqnames)-1]) + } + + p.err = newError(ErrRequired, msg) + return p.err + } + + return nil + } + + names := make([]string, 0, len(required)) + + for _, k := range required { + names = append(names, "`"+k.String()+"'") + } + + sort.Strings(names) + + var msg string + + if len(names) == 1 { + msg = fmt.Sprintf("the required flag %s was not specified", names[0]) + } else { + msg = fmt.Sprintf("the required flags %s and %s were not specified", + strings.Join(names[:len(names)-1], ", "), names[len(names)-1]) + } + + p.err = newError(ErrRequired, msg) + return p.err +} + +func (p *parseState) estimateCommand() error { + commands := p.command.sortedVisibleCommands() + cmdnames := make([]string, len(commands)) + + for i, v := range commands { + cmdnames[i] = v.Name + } + + var msg string + var errtype ErrorType + + if len(p.retargs) != 0 { + c, l := closestChoice(p.retargs[0], cmdnames) + msg = fmt.Sprintf("Unknown command `%s'", p.retargs[0]) + errtype = ErrUnknownCommand + + if float32(l)/float32(len(c)) < 0.5 { + msg = fmt.Sprintf("%s, did you mean `%s'?", msg, c) + } else if len(cmdnames) == 1 { + msg = fmt.Sprintf("%s. You should use the %s command", + msg, + cmdnames[0]) + } else if len(cmdnames) > 1 { + msg = fmt.Sprintf("%s. Please specify one command of: %s or %s", + msg, + strings.Join(cmdnames[:len(cmdnames)-1], ", "), + cmdnames[len(cmdnames)-1]) + } + } else { + errtype = ErrCommandRequired + + if len(cmdnames) == 1 { + msg = fmt.Sprintf("Please specify the %s command", cmdnames[0]) + } else if len(cmdnames) > 1 { + msg = fmt.Sprintf("Please specify one command of: %s or %s", + strings.Join(cmdnames[:len(cmdnames)-1], ", "), + cmdnames[len(cmdnames)-1]) + } + } + + return newError(errtype, msg) +} + +func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) { + if !option.canArgument() { + if argument != nil { + return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option) + } + + err = option.set(nil) + } else if argument != nil || (canarg && !s.eof()) { + var arg string + + if argument != nil { + arg = *argument + } else { + arg = s.pop() + + if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') { + return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg) + } else if p.Options&PassDoubleDash != 0 && arg == "--" { + return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got double dash `--'", option) + } + } + + if option.tag.Get("unquote") != "false" { + arg, err = unquoteIfPossible(arg) + } + + if err == nil { + err = option.set(&arg) + } + } else if option.OptionalArgument { + option.empty() + + for _, v := range option.OptionalValue { + err = option.set(&v) + + if err != nil { + break + } + } + } else { + err = newErrorf(ErrExpectedArgument, "expected argument for flag `%s'", option) + } + + if err != nil { + if _, ok := err.(*Error); !ok { + err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s", + option, + option.value.Type(), + err.Error()) + } + } + + return err +} + +func (p *Parser) parseLong(s *parseState, name string, argument *string) error { + if option := s.lookup.longNames[name]; option != nil { + // Only long options that are required can consume an argument + // from the argument list + canarg := !option.OptionalArgument + + return p.parseOption(s, name, option, canarg, argument) + } + + return newErrorf(ErrUnknownFlag, "unknown flag `%s'", name) +} + +func (p *Parser) splitShortConcatArg(s *parseState, optname string) (string, *string) { + c, n := utf8.DecodeRuneInString(optname) + + if n == len(optname) { + return optname, nil + } + + first := string(c) + + if option := s.lookup.shortNames[first]; option != nil && option.canArgument() { + arg := optname[n:] + return first, &arg + } + + return optname, nil +} + +func (p *Parser) parseShort(s *parseState, optname string, argument *string) error { + if argument == nil { + optname, argument = p.splitShortConcatArg(s, optname) + } + + for i, c := range optname { + shortname := string(c) + + if option := s.lookup.shortNames[shortname]; option != nil { + // Only the last short argument can consume an argument from + // the arguments list, and only if it's non optional + canarg := (i+utf8.RuneLen(c) == len(optname)) && !option.OptionalArgument + + if err := p.parseOption(s, shortname, option, canarg, argument); err != nil { + return err + } + } else { + return newErrorf(ErrUnknownFlag, "unknown flag `%s'", shortname) + } + + // Only the first option can have a concatted argument, so just + // clear argument here + argument = nil + } + + return nil +} + +func (p *parseState) addArgs(args ...string) error { + for len(p.positional) > 0 && len(args) > 0 { + arg := p.positional[0] + + if err := convert(args[0], arg.value, arg.tag); err != nil { + p.err = err + return err + } + + if !arg.isRemaining() { + p.positional = p.positional[1:] + } + + args = args[1:] + } + + p.retargs = append(p.retargs, args...) + return nil +} + +func (p *Parser) parseNonOption(s *parseState) error { + if len(s.positional) > 0 { + return s.addArgs(s.arg) + } + + if len(s.command.commands) > 0 && len(s.retargs) == 0 { + if cmd := s.lookup.commands[s.arg]; cmd != nil { + s.command.Active = cmd + cmd.fillParseState(s) + + return nil + } else if !s.command.SubcommandsOptional { + s.addArgs(s.arg) + return newErrorf(ErrUnknownCommand, "Unknown command `%s'", s.arg) + } + } + + if (p.Options & PassAfterNonOption) != None { + // If PassAfterNonOption is set then all remaining arguments + // are considered positional + if err := s.addArgs(s.arg); err != nil { + return err + } + + if err := s.addArgs(s.args...); err != nil { + return err + } + + s.args = []string{} + } else { + return s.addArgs(s.arg) + } + + return nil +} + +func (p *Parser) showBuiltinHelp() error { + var b bytes.Buffer + + p.WriteHelp(&b) + return newError(ErrHelp, b.String()) +} + +func (p *Parser) printError(err error) error { + if err != nil && (p.Options&PrintErrors) != None { + flagsErr, ok := err.(*Error) + + if ok && flagsErr.Type == ErrHelp { + fmt.Fprintln(os.Stdout, err) + } else { + fmt.Fprintln(os.Stderr, err) + } + } + + return err +} + +func (p *Parser) clearIsSet() { + p.eachCommand(func(c *Command) { + c.eachGroup(func(g *Group) { + for _, option := range g.options { + option.isSet = false + } + }) + }, true) +} diff --git a/vendor/github.com/jessevdk/go-flags/parser_test.go b/vendor/github.com/jessevdk/go-flags/parser_test.go new file mode 100644 index 00000000..374f21cc --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/parser_test.go @@ -0,0 +1,612 @@ +package flags + +import ( + "fmt" + "os" + "reflect" + "runtime" + "strconv" + "strings" + "testing" + "time" +) + +type defaultOptions struct { + Int int `long:"i"` + IntDefault int `long:"id" default:"1"` + + Float64 float64 `long:"f"` + Float64Default float64 `long:"fd" default:"-3.14"` + + NumericFlag bool `short:"3"` + + String string `long:"str"` + StringDefault string `long:"strd" default:"abc"` + StringNotUnquoted string `long:"strnot" unquote:"false"` + + Time time.Duration `long:"t"` + TimeDefault time.Duration `long:"td" default:"1m"` + + Map map[string]int `long:"m"` + MapDefault map[string]int `long:"md" default:"a:1"` + + Slice []int `long:"s"` + SliceDefault []int `long:"sd" default:"1" default:"2"` +} + +func TestDefaults(t *testing.T) { + var tests = []struct { + msg string + args []string + expected defaultOptions + }{ + { + msg: "no arguments, expecting default values", + args: []string{}, + expected: defaultOptions{ + Int: 0, + IntDefault: 1, + + Float64: 0.0, + Float64Default: -3.14, + + NumericFlag: false, + + String: "", + StringDefault: "abc", + + Time: 0, + TimeDefault: time.Minute, + + Map: map[string]int{}, + MapDefault: map[string]int{"a": 1}, + + Slice: []int{}, + SliceDefault: []int{1, 2}, + }, + }, + { + msg: "non-zero value arguments, expecting overwritten arguments", + args: []string{"--i=3", "--id=3", "--f=-2.71", "--fd=2.71", "-3", "--str=def", "--strd=def", "--t=3ms", "--td=3ms", "--m=c:3", "--md=c:3", "--s=3", "--sd=3"}, + expected: defaultOptions{ + Int: 3, + IntDefault: 3, + + Float64: -2.71, + Float64Default: 2.71, + + NumericFlag: true, + + String: "def", + StringDefault: "def", + + Time: 3 * time.Millisecond, + TimeDefault: 3 * time.Millisecond, + + Map: map[string]int{"c": 3}, + MapDefault: map[string]int{"c": 3}, + + Slice: []int{3}, + SliceDefault: []int{3}, + }, + }, + { + msg: "zero value arguments, expecting overwritten arguments", + args: []string{"--i=0", "--id=0", "--f=0", "--fd=0", "--str", "", "--strd=\"\"", "--t=0ms", "--td=0s", "--m=:0", "--md=:0", "--s=0", "--sd=0"}, + expected: defaultOptions{ + Int: 0, + IntDefault: 0, + + Float64: 0, + Float64Default: 0, + + String: "", + StringDefault: "", + + Time: 0, + TimeDefault: 0, + + Map: map[string]int{"": 0}, + MapDefault: map[string]int{"": 0}, + + Slice: []int{0}, + SliceDefault: []int{0}, + }, + }, + } + + for _, test := range tests { + var opts defaultOptions + + _, err := ParseArgs(&opts, test.args) + if err != nil { + t.Fatalf("%s:\nUnexpected error: %v", test.msg, err) + } + + if opts.Slice == nil { + opts.Slice = []int{} + } + + if !reflect.DeepEqual(opts, test.expected) { + t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts) + } + } +} + +func TestNoDefaultsForBools(t *testing.T) { + var opts struct { + DefaultBool bool `short:"d" default:"true"` + } + + if runtime.GOOS == "windows" { + assertParseFail(t, ErrInvalidTag, "boolean flag `/d' may not have default values, they always default to `false' and can only be turned on", &opts) + } else { + assertParseFail(t, ErrInvalidTag, "boolean flag `-d' may not have default values, they always default to `false' and can only be turned on", &opts) + } +} + +func TestUnquoting(t *testing.T) { + var tests = []struct { + arg string + err error + value string + }{ + { + arg: "\"abc", + err: strconv.ErrSyntax, + value: "", + }, + { + arg: "\"\"abc\"", + err: strconv.ErrSyntax, + value: "", + }, + { + arg: "\"abc\"", + err: nil, + value: "abc", + }, + { + arg: "\"\\\"abc\\\"\"", + err: nil, + value: "\"abc\"", + }, + { + arg: "\"\\\"abc\"", + err: nil, + value: "\"abc", + }, + } + + for _, test := range tests { + var opts defaultOptions + + for _, delimiter := range []bool{false, true} { + p := NewParser(&opts, None) + + var err error + if delimiter { + _, err = p.ParseArgs([]string{"--str=" + test.arg, "--strnot=" + test.arg}) + } else { + _, err = p.ParseArgs([]string{"--str", test.arg, "--strnot", test.arg}) + } + + if test.err == nil { + if err != nil { + t.Fatalf("Expected no error but got: %v", err) + } + + if test.value != opts.String { + t.Fatalf("Expected String to be %q but got %q", test.value, opts.String) + } + if q := strconv.Quote(test.value); q != opts.StringNotUnquoted { + t.Fatalf("Expected StringDefault to be %q but got %q", q, opts.StringNotUnquoted) + } + } else { + if err == nil { + t.Fatalf("Expected error") + } else if e, ok := err.(*Error); ok { + if strings.HasPrefix(e.Message, test.err.Error()) { + t.Fatalf("Expected error message to end with %q but got %v", test.err.Error(), e.Message) + } + } + } + } + } +} + +// EnvRestorer keeps a copy of a set of env variables and can restore the env from them +type EnvRestorer struct { + env map[string]string +} + +func (r *EnvRestorer) Restore() { + os.Clearenv() + + for k, v := range r.env { + os.Setenv(k, v) + } +} + +// EnvSnapshot returns a snapshot of the currently set env variables +func EnvSnapshot() *EnvRestorer { + r := EnvRestorer{make(map[string]string)} + + for _, kv := range os.Environ() { + parts := strings.SplitN(kv, "=", 2) + + if len(parts) != 2 { + panic("got a weird env variable: " + kv) + } + + r.env[parts[0]] = parts[1] + } + + return &r +} + +type envDefaultOptions struct { + Int int `long:"i" default:"1" env:"TEST_I"` + Time time.Duration `long:"t" default:"1m" env:"TEST_T"` + Map map[string]int `long:"m" default:"a:1" env:"TEST_M" env-delim:";"` + Slice []int `long:"s" default:"1" default:"2" env:"TEST_S" env-delim:","` +} + +func TestEnvDefaults(t *testing.T) { + var tests = []struct { + msg string + args []string + expected envDefaultOptions + env map[string]string + }{ + { + msg: "no arguments, no env, expecting default values", + args: []string{}, + expected: envDefaultOptions{ + Int: 1, + Time: time.Minute, + Map: map[string]int{"a": 1}, + Slice: []int{1, 2}, + }, + }, + { + msg: "no arguments, env defaults, expecting env default values", + args: []string{}, + expected: envDefaultOptions{ + Int: 2, + Time: 2 * time.Minute, + Map: map[string]int{"a": 2, "b": 3}, + Slice: []int{4, 5, 6}, + }, + env: map[string]string{ + "TEST_I": "2", + "TEST_T": "2m", + "TEST_M": "a:2;b:3", + "TEST_S": "4,5,6", + }, + }, + { + msg: "non-zero value arguments, expecting overwritten arguments", + args: []string{"--i=3", "--t=3ms", "--m=c:3", "--s=3"}, + expected: envDefaultOptions{ + Int: 3, + Time: 3 * time.Millisecond, + Map: map[string]int{"c": 3}, + Slice: []int{3}, + }, + env: map[string]string{ + "TEST_I": "2", + "TEST_T": "2m", + "TEST_M": "a:2;b:3", + "TEST_S": "4,5,6", + }, + }, + { + msg: "zero value arguments, expecting overwritten arguments", + args: []string{"--i=0", "--t=0ms", "--m=:0", "--s=0"}, + expected: envDefaultOptions{ + Int: 0, + Time: 0, + Map: map[string]int{"": 0}, + Slice: []int{0}, + }, + env: map[string]string{ + "TEST_I": "2", + "TEST_T": "2m", + "TEST_M": "a:2;b:3", + "TEST_S": "4,5,6", + }, + }, + } + + oldEnv := EnvSnapshot() + defer oldEnv.Restore() + + for _, test := range tests { + var opts envDefaultOptions + oldEnv.Restore() + for envKey, envValue := range test.env { + os.Setenv(envKey, envValue) + } + _, err := ParseArgs(&opts, test.args) + if err != nil { + t.Fatalf("%s:\nUnexpected error: %v", test.msg, err) + } + + if opts.Slice == nil { + opts.Slice = []int{} + } + + if !reflect.DeepEqual(opts, test.expected) { + t.Errorf("%s:\nUnexpected options with arguments %+v\nexpected\n%+v\nbut got\n%+v\n", test.msg, test.args, test.expected, opts) + } + } +} + +func TestOptionAsArgument(t *testing.T) { + var tests = []struct { + args []string + expectError bool + errType ErrorType + errMsg string + rest []string + }{ + { + // short option must not be accepted as argument + args: []string{"--string-slice", "foobar", "--string-slice", "-o"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-o'", + }, + { + // long option must not be accepted as argument + args: []string{"--string-slice", "foobar", "--string-slice", "--other-option"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `--other-option'", + }, + { + // long option must not be accepted as argument + args: []string{"--string-slice", "--"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got double dash `--'", + }, + { + // quoted and appended option should be accepted as argument (even if it looks like an option) + args: []string{"--string-slice", "foobar", "--string-slice=\"--other-option\""}, + }, + { + // Accept any single character arguments including '-' + args: []string{"--string-slice", "-"}, + }, + { + // Do not accept arguments which start with '-' even if the next character is a digit + args: []string{"--string-slice", "-3.14"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-3.14'", + }, + { + // Do not accept arguments which start with '-' if the next character is not a digit + args: []string{"--string-slice", "-character"}, + expectError: true, + errType: ErrExpectedArgument, + errMsg: "expected argument for flag `" + defaultLongOptDelimiter + "string-slice', but got option `-character'", + }, + { + args: []string{"-o", "-", "-"}, + rest: []string{"-", "-"}, + }, + { + // Accept arguments which start with '-' if the next character is a digit, for number options only + args: []string{"--int-slice", "-3"}, + }, + { + // Accept arguments which start with '-' if the next character is a digit, for number options only + args: []string{"--int16", "-3"}, + }, + { + // Accept arguments which start with '-' if the next character is a digit, for number options only + args: []string{"--float32", "-3.2"}, + }, + { + // Accept arguments which start with '-' if the next character is a digit, for number options only + args: []string{"--float32ptr", "-3.2"}, + }, + } + + var opts struct { + StringSlice []string `long:"string-slice"` + IntSlice []int `long:"int-slice"` + Int16 int16 `long:"int16"` + Float32 float32 `long:"float32"` + Float32Ptr *float32 `long:"float32ptr"` + OtherOption bool `long:"other-option" short:"o"` + } + + for _, test := range tests { + if test.expectError { + assertParseFail(t, test.errType, test.errMsg, &opts, test.args...) + } else { + args := assertParseSuccess(t, &opts, test.args...) + + assertStringArray(t, args, test.rest) + } + } +} + +func TestUnknownFlagHandler(t *testing.T) { + + var opts struct { + Flag1 string `long:"flag1"` + Flag2 string `long:"flag2"` + } + + p := NewParser(&opts, None) + + var unknownFlag1 string + var unknownFlag2 bool + var unknownFlag3 string + + // Set up a callback to intercept unknown options during parsing + p.UnknownOptionHandler = func(option string, arg SplitArgument, args []string) ([]string, error) { + if option == "unknownFlag1" { + if argValue, ok := arg.Value(); ok { + unknownFlag1 = argValue + return args, nil + } + // consume a value from remaining args list + unknownFlag1 = args[0] + return args[1:], nil + } else if option == "unknownFlag2" { + // treat this one as a bool switch, don't consume any args + unknownFlag2 = true + return args, nil + } else if option == "unknownFlag3" { + if argValue, ok := arg.Value(); ok { + unknownFlag3 = argValue + return args, nil + } + // consume a value from remaining args list + unknownFlag3 = args[0] + return args[1:], nil + } + + return args, fmt.Errorf("Unknown flag: %v", option) + } + + // Parse args containing some unknown flags, verify that + // our callback can handle all of them + _, err := p.ParseArgs([]string{"--flag1=stuff", "--unknownFlag1", "blah", "--unknownFlag2", "--unknownFlag3=baz", "--flag2=foo"}) + + if err != nil { + assertErrorf(t, "Parser returned unexpected error %v", err) + } + + assertString(t, opts.Flag1, "stuff") + assertString(t, opts.Flag2, "foo") + assertString(t, unknownFlag1, "blah") + assertString(t, unknownFlag3, "baz") + + if !unknownFlag2 { + assertErrorf(t, "Flag should have been set by unknown handler, but had value: %v", unknownFlag2) + } + + // Parse args with unknown flags that callback doesn't handle, verify it returns error + _, err = p.ParseArgs([]string{"--flag1=stuff", "--unknownFlagX", "blah", "--flag2=foo"}) + + if err == nil { + assertErrorf(t, "Parser should have returned error, but returned nil") + } +} + +func TestChoices(t *testing.T) { + var opts struct { + Choice string `long:"choose" choice:"v1" choice:"v2"` + } + + assertParseFail(t, ErrInvalidChoice, "Invalid value `invalid' for option `"+defaultLongOptDelimiter+"choose'. Allowed values are: v1 or v2", &opts, "--choose", "invalid") + assertParseSuccess(t, &opts, "--choose", "v2") + assertString(t, opts.Choice, "v2") +} + +func TestEmbedded(t *testing.T) { + type embedded struct { + V bool `short:"v"` + } + var opts struct { + embedded + } + + assertParseSuccess(t, &opts, "-v") + + if !opts.V { + t.Errorf("Expected V to be true") + } +} + +type command struct { +} + +func (c *command) Execute(args []string) error { + return nil +} + +func TestCommandHandlerNoCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + parser := NewParser(&opts, Default&^PrintErrors) + + var executedCommand Commander + var executedArgs []string + + executed := false + + parser.CommandHandler = func(command Commander, args []string) error { + executed = true + + executedCommand = command + executedArgs = args + + return nil + } + + _, err := parser.ParseArgs([]string{"arg1", "arg2"}) + + if err != nil { + t.Fatalf("Unexpected parse error: %s", err) + } + + if !executed { + t.Errorf("Expected command handler to be executed") + } + + if executedCommand != nil { + t.Errorf("Did not exect an executed command") + } + + assertStringArray(t, executedArgs, []string{"arg1", "arg2"}) +} + +func TestCommandHandler(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + + Command command `command:"cmd"` + }{} + + parser := NewParser(&opts, Default&^PrintErrors) + + var executedCommand Commander + var executedArgs []string + + executed := false + + parser.CommandHandler = func(command Commander, args []string) error { + executed = true + + executedCommand = command + executedArgs = args + + return nil + } + + _, err := parser.ParseArgs([]string{"cmd", "arg1", "arg2"}) + + if err != nil { + t.Fatalf("Unexpected parse error: %s", err) + } + + if !executed { + t.Errorf("Expected command handler to be executed") + } + + if executedCommand == nil { + t.Errorf("Expected command handler to be executed") + } + + assertStringArray(t, executedArgs, []string{"arg1", "arg2"}) +} diff --git a/vendor/github.com/jessevdk/go-flags/pointer_test.go b/vendor/github.com/jessevdk/go-flags/pointer_test.go new file mode 100644 index 00000000..dc779c78 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/pointer_test.go @@ -0,0 +1,164 @@ +package flags + +import ( + "testing" +) + +func TestPointerBool(t *testing.T) { + var opts = struct { + Value *bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if !*opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestPointerString(t *testing.T) { + var opts = struct { + Value *string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value") + + assertStringArray(t, ret, []string{}) + assertString(t, *opts.Value, "value") +} + +func TestPointerSlice(t *testing.T) { + var opts = struct { + Value *[]string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value1", "-v", "value2") + + assertStringArray(t, ret, []string{}) + assertStringArray(t, *opts.Value, []string{"value1", "value2"}) +} + +func TestPointerMap(t *testing.T) { + var opts = struct { + Value *map[string]int `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "k1:2", "-v", "k2:-5") + + assertStringArray(t, ret, []string{}) + + if v, ok := (*opts.Value)["k1"]; !ok { + t.Errorf("Expected key \"k1\" to exist") + } else if v != 2 { + t.Errorf("Expected \"k1\" to be 2, but got %#v", v) + } + + if v, ok := (*opts.Value)["k2"]; !ok { + t.Errorf("Expected key \"k2\" to exist") + } else if v != -5 { + t.Errorf("Expected \"k2\" to be -5, but got %#v", v) + } +} + +type marshalledString string + +func (m *marshalledString) UnmarshalFlag(value string) error { + *m = marshalledString(value) + return nil +} + +func (m marshalledString) MarshalFlag() (string, error) { + return string(m), nil +} + +func TestPointerStringMarshalled(t *testing.T) { + var opts = struct { + Value *marshalledString `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value") + + assertStringArray(t, ret, []string{}) + + if opts.Value == nil { + t.Error("Expected value not to be nil") + return + } + + assertString(t, string(*opts.Value), "value") +} + +type marshalledStruct struct { + Value string +} + +func (m *marshalledStruct) UnmarshalFlag(value string) error { + m.Value = value + return nil +} + +func (m marshalledStruct) MarshalFlag() (string, error) { + return m.Value, nil +} + +func TestPointerStructMarshalled(t *testing.T) { + var opts = struct { + Value *marshalledStruct `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value") + + assertStringArray(t, ret, []string{}) + + if opts.Value == nil { + t.Error("Expected value not to be nil") + return + } + + assertString(t, opts.Value.Value, "value") +} + +type PointerGroup struct { + Value bool `short:"v"` +} + +func TestPointerGroup(t *testing.T) { + var opts = struct { + Group *PointerGroup `group:"Group Options"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if !opts.Group.Value { + t.Errorf("Expected Group.Value to be true") + } +} + +func TestDoNotChangeNonTaggedFields(t *testing.T) { + var opts struct { + A struct { + Pointer *int + } + B *struct { + Pointer *int + } + } + + ret := assertParseSuccess(t, &opts) + + assertStringArray(t, ret, []string{}) + + if opts.A.Pointer != nil { + t.Error("Expected A.Pointer to be nil") + } + if opts.B != nil { + t.Error("Expected B to be nil") + } + if opts.B != nil && opts.B.Pointer != nil { + t.Error("Expected B.Pointer to be nil") + } +} diff --git a/vendor/github.com/jessevdk/go-flags/short_test.go b/vendor/github.com/jessevdk/go-flags/short_test.go new file mode 100644 index 00000000..5f4106b0 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/short_test.go @@ -0,0 +1,234 @@ +package flags + +import ( + "fmt" + "testing" +) + +func TestShort(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v") + + assertStringArray(t, ret, []string{}) + + if !opts.Value { + t.Errorf("Expected Value to be true") + } +} + +func TestShortTooLong(t *testing.T) { + var opts = struct { + Value bool `short:"vv"` + }{} + + assertParseFail(t, ErrShortNameTooLong, "short names can only be 1 character long, not `vv'", &opts) +} + +func TestShortRequired(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"true"` + }{} + + assertParseFail(t, ErrRequired, fmt.Sprintf("the required flag `%cv' was not specified", defaultShortOptDelimiter), &opts) +} + +func TestShortRequiredFalsy1(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"false"` + }{} + + assertParseSuccess(t, &opts) +} + +func TestShortRequiredFalsy2(t *testing.T) { + var opts = struct { + Value bool `short:"v" required:"no"` + }{} + + assertParseSuccess(t, &opts) +} + +func TestShortMultiConcat(t *testing.T) { + var opts = struct { + V bool `short:"v"` + O bool `short:"o"` + F bool `short:"f"` + }{} + + ret := assertParseSuccess(t, &opts, "-vo", "-f") + + assertStringArray(t, ret, []string{}) + + if !opts.V { + t.Errorf("Expected V to be true") + } + + if !opts.O { + t.Errorf("Expected O to be true") + } + + if !opts.F { + t.Errorf("Expected F to be true") + } +} + +func TestShortMultiRequiredConcat(t *testing.T) { + var opts = struct { + V bool `short:"v" required:"true"` + O bool `short:"o" required:"true"` + F bool `short:"f" required:"true"` + }{} + + ret := assertParseSuccess(t, &opts, "-vo", "-f") + + assertStringArray(t, ret, []string{}) + + if !opts.V { + t.Errorf("Expected V to be true") + } + + if !opts.O { + t.Errorf("Expected O to be true") + } + + if !opts.F { + t.Errorf("Expected F to be true") + } +} + +func TestShortMultiSlice(t *testing.T) { + var opts = struct { + Values []bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "-v") + + assertStringArray(t, ret, []string{}) + assertBoolArray(t, opts.Values, []bool{true, true}) +} + +func TestShortMultiSliceConcat(t *testing.T) { + var opts = struct { + Values []bool `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-vvv") + + assertStringArray(t, ret, []string{}) + assertBoolArray(t, opts.Values, []bool{true, true, true}) +} + +func TestShortWithEqualArg(t *testing.T) { + var opts = struct { + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v=value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestShortWithArg(t *testing.T) { + var opts = struct { + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-vvalue") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestShortArg(t *testing.T) { + var opts = struct { + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-v", "value") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "value") +} + +func TestShortMultiWithEqualArg(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffv=value") +} + +func TestShortMultiArg(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-ffv", "value") + + assertStringArray(t, ret, []string{}) + assertBoolArray(t, opts.F, []bool{true, true}) + assertString(t, opts.Value, "value") +} + +func TestShortMultiArgConcatFail(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + assertParseFail(t, ErrExpectedArgument, fmt.Sprintf("expected argument for flag `%cv'", defaultShortOptDelimiter), &opts, "-ffvvalue") +} + +func TestShortMultiArgConcat(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v"` + }{} + + ret := assertParseSuccess(t, &opts, "-vff") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "ff") +} + +func TestShortOptional(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v" optional:"yes" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "-fv", "f") + + assertStringArray(t, ret, []string{"f"}) + assertString(t, opts.Value, "value") +} + +func TestShortOptionalFalsy1(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v" optional:"false" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "-fv", "f") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "f") +} + +func TestShortOptionalFalsy2(t *testing.T) { + var opts = struct { + F []bool `short:"f"` + Value string `short:"v" optional:"no" optional-value:"value"` + }{} + + ret := assertParseSuccess(t, &opts, "-fv", "f") + + assertStringArray(t, ret, []string{}) + assertString(t, opts.Value, "f") +} diff --git a/vendor/github.com/jessevdk/go-flags/tag_test.go b/vendor/github.com/jessevdk/go-flags/tag_test.go new file mode 100644 index 00000000..9daa7401 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/tag_test.go @@ -0,0 +1,38 @@ +package flags + +import ( + "testing" +) + +func TestTagMissingColon(t *testing.T) { + var opts = struct { + Value bool `short` + }{} + + assertParseFail(t, ErrTag, "expected `:' after key name, but got end of tag (in `short`)", &opts, "") +} + +func TestTagMissingValue(t *testing.T) { + var opts = struct { + Value bool `short:` + }{} + + assertParseFail(t, ErrTag, "expected `\"' to start tag value at end of tag (in `short:`)", &opts, "") +} + +func TestTagMissingQuote(t *testing.T) { + var opts = struct { + Value bool `short:"v` + }{} + + assertParseFail(t, ErrTag, "expected end of tag value `\"' at end of tag (in `short:\"v`)", &opts, "") +} + +func TestTagNewline(t *testing.T) { + var opts = struct { + Value bool `long:"verbose" description:"verbose +something"` + }{} + + assertParseFail(t, ErrTag, "unexpected newline in tag value `description' (in `long:\"verbose\" description:\"verbose\nsomething\"`)", &opts, "") +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize.go b/vendor/github.com/jessevdk/go-flags/termsize.go new file mode 100644 index 00000000..df97e7e8 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize.go @@ -0,0 +1,28 @@ +// +build !windows,!plan9,!solaris + +package flags + +import ( + "syscall" + "unsafe" +) + +type winsize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func getTerminalColumns() int { + ws := winsize{} + + if tIOCGWINSZ != 0 { + syscall.Syscall(syscall.SYS_IOCTL, + uintptr(0), + uintptr(tIOCGWINSZ), + uintptr(unsafe.Pointer(&ws))) + + return int(ws.col) + } + + return 80 +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize_linux.go b/vendor/github.com/jessevdk/go-flags/termsize_linux.go new file mode 100644 index 00000000..e3975e28 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_linux.go @@ -0,0 +1,7 @@ +// +build linux + +package flags + +const ( + tIOCGWINSZ = 0x5413 +) diff --git a/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go new file mode 100644 index 00000000..2a9bbe00 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go @@ -0,0 +1,7 @@ +// +build windows plan9 solaris + +package flags + +func getTerminalColumns() int { + return 80 +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize_other.go b/vendor/github.com/jessevdk/go-flags/termsize_other.go new file mode 100644 index 00000000..30821515 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_other.go @@ -0,0 +1,7 @@ +// +build !darwin,!freebsd,!netbsd,!openbsd,!linux + +package flags + +const ( + tIOCGWINSZ = 0 +) diff --git a/vendor/github.com/jessevdk/go-flags/termsize_unix.go b/vendor/github.com/jessevdk/go-flags/termsize_unix.go new file mode 100644 index 00000000..fcc11860 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_unix.go @@ -0,0 +1,7 @@ +// +build darwin freebsd netbsd openbsd + +package flags + +const ( + tIOCGWINSZ = 0x40087468 +) diff --git a/vendor/github.com/jessevdk/go-flags/unknown_test.go b/vendor/github.com/jessevdk/go-flags/unknown_test.go new file mode 100644 index 00000000..858be458 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/unknown_test.go @@ -0,0 +1,66 @@ +package flags + +import ( + "testing" +) + +func TestUnknownFlags(t *testing.T) { + var opts = struct { + Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` + }{} + + args := []string{ + "-f", + } + + p := NewParser(&opts, 0) + args, err := p.ParseArgs(args) + + if err == nil { + t.Fatal("Expected error for unknown argument") + } +} + +func TestIgnoreUnknownFlags(t *testing.T) { + var opts = struct { + Verbose []bool `short:"v" long:"verbose" description:"Verbose output"` + }{} + + args := []string{ + "hello", + "world", + "-v", + "--foo=bar", + "--verbose", + "-f", + } + + p := NewParser(&opts, IgnoreUnknown) + args, err := p.ParseArgs(args) + + if err != nil { + t.Fatal(err) + } + + exargs := []string{ + "hello", + "world", + "--foo=bar", + "-f", + } + + issame := (len(args) == len(exargs)) + + if issame { + for i := 0; i < len(args); i++ { + if args[i] != exargs[i] { + issame = false + break + } + } + } + + if !issame { + t.Fatalf("Expected %v but got %v", exargs, args) + } +} diff --git a/vendor/github.com/rakyll/globalconf/.travis.yml b/vendor/github.com/rakyll/globalconf/.travis.yml deleted file mode 100644 index 5b77ae62..00000000 --- a/vendor/github.com/rakyll/globalconf/.travis.yml +++ /dev/null @@ -1,2 +0,0 @@ -language: go -go: 1.5 diff --git a/vendor/github.com/rakyll/globalconf/README.md b/vendor/github.com/rakyll/globalconf/README.md deleted file mode 100644 index dcbf4ddf..00000000 --- a/vendor/github.com/rakyll/globalconf/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# globalconf - -[![Build Status](https://travis-ci.org/rakyll/globalconf.png?branch=master)](https://travis-ci.org/rakyll/globalconf) - -Effortlessly persist/retrieve flags of your Golang programs. If you need global configuration instead of requiring user always to set command line flags, you are looking at the right package. `globalconf` allows your users to not only provide flags, but config files and environment variables as well. - -## Usage - -~~~ go -import "github.com/rakyll/globalconf" -~~~ - -### Loading a config file - -By default, globalconf provides you a config file under `~/.config//config.ini`. - -~~~ go -globalconf.New("appname") // loads from ~/.config//config.ini -~~~ - -If you don't prefer the default location you can load from a specified path as well. - -~~~ go -globalconf.NewWithOptions(&globalconf.Options{ - Filename: "/path/to/config/file", -}) -~~~ - -You may like to override configuration with env variables. See "Environment variables" header to see how to it works. - -~~~ go -globalconf.NewWithOptions(&globalconf.Options{ - Filename: "/path/to/config/file", - EnvPrefix: "APPCONF_", -}) -~~~ - -### Parsing flag values - -`globalconf` populates flags with data in the config file if they are not already set. - -~~~ go -var ( - flagName = flag.String("name", "", "Name of the person.") - flagAddress = flag.String("addr", "", "Address of the person.") -) -~~~ - -Assume the configuration file to be loaded contains the following lines. - - name = Burcu - addr = Brandschenkestrasse 110, 8002 - -And your program is being started, `$ myapp -name=Jane` -~~~ go -conf, err := globalconf.New("myapp") -conf.ParseAll() -~~~ - -`*flagName` is going to be equal to `Jane`, whereas `*flagAddress` is `Brandschenkestrasse 110, 8002`, what is provided in the configuration file. - -### Custom flag sets - -Custom flagsets are supported, but required registration before parse is done. The default flagset `flag.CommandLine` is automatically registered. - -~~~ go -globalconf.Register("termopts", termOptsFlagSet) -conf.ParseAll() // parses command line and all registered flag sets -~~~ - -Custom flagset values should be provided in their own segment. Getting back to the sample ini config file, termopts values will have their own segment. - - name = Burcu - addr = Brandschenkestrasse 110, 8002 - - [termopts] - color = true - background = ff0000 - -### Environment variables - -If an EnvPrefix is provided, environment variables will take precedence over values in the configuration file. -Set the `EnvPrefix` option when calling `globalconf.NewWithOptions`. -An `EnvPrefix` will only be used if it is a non-empty string. -Command line flags will override the environment variables. - -~~~ go -opts := globalconf.Options{ - EnvPrefix: "MYAPP_", - Filename: "/path/to/config", -} -conf, err := globalconf.NewWithOptions(&opts) -conf.ParseAll() -~~~ - -With environment variables: - - APPCONF_NAME = Burcu - -and configuration: - - name = Jane - addr = Brandschenkestrasse 110, 8002 - -`name` will be set to "burcu" and `addr` will be set to "Brandschenkestrasse 110, 8002". - -### Modifying stored flags - -Modifications are persisted as long as you set a new flag and your GlobalConf -object was configured with a filename. - -~~~ go -f := &flag.Flag{Name: "name", Value: val} -conf.Set("", f) // if you are modifying a command line flag - -f := &flag.Flag{Name: "color", Value: val} -conf.Set("termopts", color) // if you are modifying a custom flag set flag -~~~ - -### Deleting stored flags - -Like Set, Deletions are persisted as long as you delete a flag's value and your -GlobalConf object was configured with a filename. - -~~~ go -conf.Delete("", "name") // removes command line flag "name"s value from config -conf.Delete("termopts", "color") // removes "color"s value from the custom flag set -~~~ - -## License - -Copyright 2014 Google Inc. All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ![Analytics](https://ga-beacon.appspot.com/UA-46881978-1/globalconf?pixel) diff --git a/vendor/github.com/rakyll/globalconf/globalconf.go b/vendor/github.com/rakyll/globalconf/globalconf.go deleted file mode 100644 index 4b848018..00000000 --- a/vendor/github.com/rakyll/globalconf/globalconf.go +++ /dev/null @@ -1,177 +0,0 @@ -package globalconf - -import ( - "flag" - "io/ioutil" - "os" - "os/user" - "path" - "strings" - - ini "github.com/glacjay/goini" -) - -const ( - defaultConfigFileName = "config.ini" -) - -var flags map[string]*flag.FlagSet = make(map[string]*flag.FlagSet) - -// Represents a GlobalConf context. -type GlobalConf struct { - Filename string - EnvPrefix string - dict *ini.Dict -} - -type Options struct { - Filename string - EnvPrefix string -} - -// NewWithOptions creates a GlobalConf from the provided -// Options. The caller is responsible for creating any -// referenced config files. -func NewWithOptions(opts *Options) (g *GlobalConf, err error) { - Register("", flag.CommandLine) - - var dict ini.Dict - if opts.Filename != "" { - dict, err = ini.Load(opts.Filename) - if err != nil { - return nil, err - } - } else { - dict = make(ini.Dict, 0) - } - - return &GlobalConf{ - Filename: opts.Filename, - EnvPrefix: opts.EnvPrefix, - dict: &dict, - }, nil -} - -// Opens/creates a config file for the specified appName. -// The path to config file is ~/.config/appName/config.ini. -func New(appName string) (g *GlobalConf, err error) { - var u *user.User - if u, err = user.Current(); u == nil { - return - } - // Create config file's directory. - dirPath := path.Join(u.HomeDir, ".config", appName) - if err = os.MkdirAll(dirPath, 0755); err != nil { - return - } - // Touch a config file if it doesn't exit. - filePath := path.Join(dirPath, defaultConfigFileName) - if _, err = os.Stat(filePath); err != nil { - if !os.IsNotExist(err) { - return - } - // create file - if err = ioutil.WriteFile(filePath, []byte{}, 0644); err != nil { - return - } - } - opts := Options{Filename: filePath} - return NewWithOptions(&opts) -} - -// Sets a flag's value and persists the changes to the disk. -func (g *GlobalConf) Set(flagSetName string, f *flag.Flag) error { - g.dict.SetString(flagSetName, f.Name, f.Value.String()) - if g.Filename != "" { - return ini.Write(g.Filename, g.dict) - } - return nil -} - -// Deletes a flag from config file and persists the changes -// to the disk. -func (g *GlobalConf) Delete(flagSetName, flagName string) error { - g.dict.Delete(flagSetName, flagName) - if g.Filename != "" { - return ini.Write(g.Filename, g.dict) - } - return nil -} - -// ParseSet parses the config file for the provided flag set. -// If the flags are already set, values are overwritten -// by the values in the config file. Defaults are not set -// if the flag is not in the file. -func (g *GlobalConf) ParseSet(flagSetName string, set *flag.FlagSet) { - set.VisitAll(func(f *flag.Flag) { - if val, ok := getEnv(g.EnvPrefix, flagSetName, f.Name); ok { - set.Set(f.Name, val) - return - } - - val, found := g.dict.GetString(flagSetName, f.Name) - if found { - set.Set(f.Name, val) - } - }) -} - -// Parse parses all the registered flag sets, including the command -// line set and sets values from the config file if they are -// not already set. -func (g *GlobalConf) Parse() { - for name, set := range flags { - alreadySet := make(map[string]bool) - set.Visit(func(f *flag.Flag) { - alreadySet[f.Name] = true - }) - set.VisitAll(func(f *flag.Flag) { - // if not already set, set it from dict if ok - if alreadySet[f.Name] { - return - } - - if val, ok := getEnv(g.EnvPrefix, name, f.Name); ok { - set.Set(f.Name, val) - return - } - - val, found := g.dict.GetString(name, f.Name) - if found { - set.Set(f.Name, val) - } - }) - } -} - -// Parses command line flags and then, all of the registered -// flag sets with the values provided in the config file. -func (g *GlobalConf) ParseAll() { - if !flag.Parsed() { - flag.Parse() - } - g.Parse() -} - -// Looks up variable in environment -func getEnv(envPrefix, flagSetName, flagName string) (string, bool) { - // If we haven't set an EnvPrefix, don't lookup vals in the ENV - if envPrefix == "" { - return "", false - } - // Append a _ to flagSetName if it exists. - if flagSetName != "" { - flagSetName += "_" - } - flagName = strings.Replace(flagName, ".", "_", -1) - flagName = strings.Replace(flagName, "-", "_", -1) - envKey := strings.ToUpper(envPrefix + flagSetName + flagName) - return os.LookupEnv(envKey) -} - -// Register registers a flag set to be parsed. Register all flag sets -// before calling this function. flag.CommandLine is automatically -// registered. -func Register(flagSetName string, set *flag.FlagSet) { - flags[flagSetName] = set -} diff --git a/vendor/github.com/rakyll/globalconf/globalconf_test.go b/vendor/github.com/rakyll/globalconf/globalconf_test.go deleted file mode 100644 index fce2ceae..00000000 --- a/vendor/github.com/rakyll/globalconf/globalconf_test.go +++ /dev/null @@ -1,283 +0,0 @@ -package globalconf - -import ( - "flag" - "io/ioutil" - "os" - "testing" -) - -const envTestPrefix = "CONFTEST_" - -func TestNewWithOptionsNoFilename(t *testing.T) { - opts := Options{EnvPrefix: envTestPrefix} - - os.Setenv(envTestPrefix+"D", "EnvD") - - flagD := flag.String("d", "default", "") - flagE := flag.Bool("e", true, "") - - conf, err := NewWithOptions(&opts) - if err != nil { - t.Fatal(err) - } - conf.ParseAll() - - if *flagD != "EnvD" { - t.Errorf("flagD found %v, expected 'EnvD'", *flagD) - } - if !*flagE { - t.Errorf("flagE found %v, expected true", *flagE) - } -} - -func TestParse_Global(t *testing.T) { - resetForTesting("") - - os.Setenv(envTestPrefix+"D", "EnvD") - os.Setenv(envTestPrefix+"E", "true") - os.Setenv(envTestPrefix+"F", "5.5") - - flagA := flag.Bool("a", false, "") - flagB := flag.Float64("b", 0.0, "") - flagC := flag.String("c", "", "") - - flagD := flag.String("d", "", "") - flagE := flag.Bool("e", false, "") - flagF := flag.Float64("f", 0.0, "") - - parse(t, "./testdata/global.ini", envTestPrefix) - if !*flagA { - t.Errorf("flagA found %v, expected true", *flagA) - } - if *flagB != 5.6 { - t.Errorf("flagB found %v, expected 5.6", *flagB) - } - if *flagC != "Hello world" { - t.Errorf("flagC found %v, expected 'Hello world'", *flagC) - } - if *flagD != "EnvD" { - t.Errorf("flagD found %v, expected 'EnvD'", *flagD) - } - if !*flagE { - t.Errorf("flagE found %v, expected true", *flagE) - } - if *flagF != 5.5 { - t.Errorf("flagF found %v, expected 5.5", *flagF) - } -} - -func TestParse_DashConversion(t *testing.T) { - resetForTesting("") - - flagFooBar := flag.String("foo-bar", "", "") - os.Setenv("PREFIX_FOO_BAR", "baz") - - opts := Options{EnvPrefix: "PREFIX_"} - conf, err := NewWithOptions(&opts) - if err != nil { - t.Fatal(err) - } - conf.ParseAll() - - if *flagFooBar != "baz" { - t.Errorf("flagFooBar found %v, expected 5.5", *flagFooBar) - } -} - -func TestParse_GlobalWithDottedFlagname(t *testing.T) { - resetForTesting("") - os.Setenv(envTestPrefix+"SOME_VALUE", "some-value") - flagSomeValue := flag.String("some.value", "", "") - - parse(t, "./testdata/global.ini", envTestPrefix) - if *flagSomeValue != "some-value" { - t.Errorf("flagSomeValue found %v, some-value expected", *flagSomeValue) - } -} - -// Given the need to test overwriting a flag with an environmental variable set to an empty string -// Reset the flags and clear the env. -// Set the env var for the c flag to an empty string. -// Expect flagC to an empty string and not be the value Hello World from the INI file. -func TestParse_GlobalWithEmptyValue(t *testing.T) { - resetForTesting("") - - os.Setenv(envTestPrefix+"C", "") - flagC := flag.String("c", "", "") - - parse(t, "./testdata/global.ini", envTestPrefix) - if got, want := *flagC, ""; got != want { - t.Errorf("got flag = %q, want empty string", got) - } -} - -func TestParse_GlobalOverwrite(t *testing.T) { - resetForTesting("-b=7.6") - flagB := flag.Float64("b", 0.0, "") - - parse(t, "./testdata/global.ini", "") - if *flagB != 7.6 { - t.Errorf("flagB found %v, expected 7.6", *flagB) - } -} - -func TestParse_Custom(t *testing.T) { - resetForTesting("") - - os.Setenv(envTestPrefix+"CUSTOM_E", "Hello Env") - - flagB := flag.Float64("b", 5.0, "") - - name := "custom" - custom := flag.NewFlagSet(name, flag.ExitOnError) - flagD := custom.String("d", "dd", "") - flagE := custom.String("e", "ee", "") - - Register(name, custom) - parse(t, "./testdata/custom.ini", envTestPrefix) - if *flagB != 5.0 { - t.Errorf("flagB found %v, expected 5.0", *flagB) - } - if *flagD != "Hello d" { - t.Errorf("flagD found %v, expected 'Hello d'", *flagD) - } - if *flagE != "Hello Env" { - t.Errorf("flagE found %v, expected 'Hello Env'", *flagE) - } -} - -func TestParse_CustomOverwrite(t *testing.T) { - resetForTesting("-b=6") - flagB := flag.Float64("b", 5.0, "") - - name := "custom" - custom := flag.NewFlagSet(name, flag.ExitOnError) - flagD := custom.String("d", "dd", "") - - Register(name, custom) - parse(t, "./testdata/custom.ini", "") - if *flagB != 6.0 { - t.Errorf("flagB found %v, expected 6.0", *flagB) - } - if *flagD != "Hello d" { - t.Errorf("flagD found %v, expected 'Hello d'", *flagD) - } -} - -func TestParse_GlobalAndCustom(t *testing.T) { - resetForTesting("") - flagA := flag.Bool("a", false, "") - flagB := flag.Float64("b", 0.0, "") - flagC := flag.String("c", "", "") - - name := "custom" - custom := flag.NewFlagSet(name, flag.ExitOnError) - flagD := custom.String("d", "", "") - - Register(name, custom) - parse(t, "./testdata/globalandcustom.ini", "") - if !*flagA { - t.Errorf("flagA found %v, expected true", *flagA) - } - if *flagB != 5.6 { - t.Errorf("flagB found %v, expected 5.6", *flagB) - } - if *flagC != "Hello world" { - t.Errorf("flagC found %v, expected 'Hello world'", *flagC) - } - if *flagD != "Hello d" { - t.Errorf("flagD found %v, expected 'Hello d'", *flagD) - } -} - -func TestParse_GlobalAndCustomOverwrite(t *testing.T) { - resetForTesting("-a=true", "-b=5", "-c=Hello") - flagA := flag.Bool("a", false, "") - flagB := flag.Float64("b", 0.0, "") - flagC := flag.String("c", "", "") - - name := "custom" - custom := flag.NewFlagSet(name, flag.ExitOnError) - flagD := custom.String("d", "", "") - - Register(name, custom) - parse(t, "./testdata/globalandcustom.ini", "") - if !*flagA { - t.Errorf("flagA found %v, expected true", *flagA) - } - if *flagB != 5.0 { - t.Errorf("flagB found %v, expected 5.0", *flagB) - } - if *flagC != "Hello" { - t.Errorf("flagC found %v, expected 'Hello'", *flagC) - } - if *flagD != "Hello d" { - t.Errorf("flagD found %v, expected 'Hello d'", *flagD) - } -} - -func TestSet(t *testing.T) { - resetForTesting() - file, _ := ioutil.TempFile("", "") - conf := parse(t, file.Name(), "") - conf.Set("", &flag.Flag{Name: "a", Value: newFlagValue("test")}) - - flagA := flag.String("a", "", "") - parse(t, file.Name(), "") - if *flagA != "test" { - t.Errorf("flagA found %v, expected 'test'", *flagA) - } -} - -func TestDelete(t *testing.T) { - resetForTesting() - file, _ := ioutil.TempFile("", "") - conf := parse(t, file.Name(), "") - conf.Set("", &flag.Flag{Name: "a", Value: newFlagValue("test")}) - conf.Delete("", "a") - - flagA := flag.String("a", "", "") - parse(t, file.Name(), "") - if *flagA != "" { - t.Errorf("flagNewA found %v, expected ''", *flagA) - } -} - -func parse(t *testing.T, filename, envPrefix string) *GlobalConf { - opts := Options{ - Filename: filename, - EnvPrefix: envPrefix, - } - conf, err := NewWithOptions(&opts) - if err != nil { - t.Error(err) - } - conf.ParseAll() - return conf -} - -// Resets os.Args and the default flag set. -func resetForTesting(args ...string) { - os.Clearenv() - - os.Args = append([]string{"cmd"}, args...) - flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) -} - -type flagValue struct { - str string -} - -func (f *flagValue) String() string { - return f.str -} - -func (f *flagValue) Set(value string) error { - f.str = value - return nil -} - -func newFlagValue(val string) *flagValue { - return &flagValue{str: val} -} diff --git a/vendor/github.com/rakyll/globalconf/testdata/custom.ini b/vendor/github.com/rakyll/globalconf/testdata/custom.ini deleted file mode 100644 index 23795a1f..00000000 --- a/vendor/github.com/rakyll/globalconf/testdata/custom.ini +++ /dev/null @@ -1,2 +0,0 @@ -[custom] -d = Hello d diff --git a/vendor/github.com/rakyll/globalconf/testdata/global.ini b/vendor/github.com/rakyll/globalconf/testdata/global.ini deleted file mode 100644 index 12688885..00000000 --- a/vendor/github.com/rakyll/globalconf/testdata/global.ini +++ /dev/null @@ -1,3 +0,0 @@ -a = true -b = 5.6 -c = Hello world diff --git a/vendor/github.com/rakyll/globalconf/testdata/globalandcustom.ini b/vendor/github.com/rakyll/globalconf/testdata/globalandcustom.ini deleted file mode 100644 index c48a933e..00000000 --- a/vendor/github.com/rakyll/globalconf/testdata/globalandcustom.ini +++ /dev/null @@ -1,6 +0,0 @@ -a = true -b = 5.6 -c = Hello world - -[custom] -d = Hello d diff --git a/vendor/github.com/spf13/pflag/.gitignore b/vendor/github.com/spf13/pflag/.gitignore deleted file mode 100644 index c3da2901..00000000 --- a/vendor/github.com/spf13/pflag/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/* - diff --git a/vendor/github.com/spf13/pflag/.travis.yml b/vendor/github.com/spf13/pflag/.travis.yml deleted file mode 100644 index f8a63b30..00000000 --- a/vendor/github.com/spf13/pflag/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -sudo: false - -language: go - -go: - - 1.7.3 - - 1.8.1 - - tip - -matrix: - allow_failures: - - go: tip - -install: - - go get github.com/golang/lint/golint - - export PATH=$GOPATH/bin:$PATH - - go install ./... - -script: - - verify/all.sh -v - - go test ./... diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md deleted file mode 100644 index b052414d..00000000 --- a/vendor/github.com/spf13/pflag/README.md +++ /dev/null @@ -1,296 +0,0 @@ -[![Build Status](https://travis-ci.org/spf13/pflag.svg?branch=master)](https://travis-ci.org/spf13/pflag) -[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/pflag)](https://goreportcard.com/report/github.com/spf13/pflag) -[![GoDoc](https://godoc.org/github.com/spf13/pflag?status.svg)](https://godoc.org/github.com/spf13/pflag) - -## Description - -pflag is a drop-in replacement for Go's flag package, implementing -POSIX/GNU-style --flags. - -pflag is compatible with the [GNU extensions to the POSIX recommendations -for command-line options][1]. For a more precise description, see the -"Command-line flag syntax" section below. - -[1]: http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html - -pflag is available under the same style of BSD license as the Go language, -which can be found in the LICENSE file. - -## Installation - -pflag is available using the standard `go get` command. - -Install by running: - - go get github.com/spf13/pflag - -Run tests by running: - - go test github.com/spf13/pflag - -## Usage - -pflag is a drop-in replacement of Go's native flag package. If you import -pflag under the name "flag" then all code should continue to function -with no changes. - -``` go -import flag "github.com/spf13/pflag" -``` - -There is one exception to this: if you directly instantiate the Flag struct -there is one more field "Shorthand" that you will need to set. -Most code never instantiates this struct directly, and instead uses -functions such as String(), BoolVar(), and Var(), and is therefore -unaffected. - -Define flags using flag.String(), Bool(), Int(), etc. - -This declares an integer flag, -flagname, stored in the pointer ip, with type *int. - -``` go -var ip *int = flag.Int("flagname", 1234, "help message for flagname") -``` - -If you like, you can bind the flag to a variable using the Var() functions. - -``` go -var flagvar int -func init() { - flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") -} -``` - -Or you can create custom flags that satisfy the Value interface (with -pointer receivers) and couple them to flag parsing by - -``` go -flag.Var(&flagVal, "name", "help message for flagname") -``` - -For such flags, the default value is just the initial value of the variable. - -After all flags are defined, call - -``` go -flag.Parse() -``` - -to parse the command line into the defined flags. - -Flags may then be used directly. If you're using the flags themselves, -they are all pointers; if you bind to variables, they're values. - -``` go -fmt.Println("ip has value ", *ip) -fmt.Println("flagvar has value ", flagvar) -``` - -There are helpers function to get values later if you have the FlagSet but -it was difficult to keep up with all of the flag pointers in your code. -If you have a pflag.FlagSet with a flag called 'flagname' of type int you -can use GetInt() to get the int value. But notice that 'flagname' must exist -and it must be an int. GetString("flagname") will fail. - -``` go -i, err := flagset.GetInt("flagname") -``` - -After parsing, the arguments after the flag are available as the -slice flag.Args() or individually as flag.Arg(i). -The arguments are indexed from 0 through flag.NArg()-1. - -The pflag package also defines some new functions that are not in flag, -that give one-letter shorthands for flags. You can use these by appending -'P' to the name of any function that defines a flag. - -``` go -var ip = flag.IntP("flagname", "f", 1234, "help message") -var flagvar bool -func init() { - flag.BoolVarP(&flagvar, "boolname", "b", true, "help message") -} -flag.VarP(&flagVal, "varname", "v", "help message") -``` - -Shorthand letters can be used with single dashes on the command line. -Boolean shorthand flags can be combined with other shorthand flags. - -The default set of command-line flags is controlled by -top-level functions. The FlagSet type allows one to define -independent sets of flags, such as to implement subcommands -in a command-line interface. The methods of FlagSet are -analogous to the top-level functions for the command-line -flag set. - -## Setting no option default values for flags - -After you create a flag it is possible to set the pflag.NoOptDefVal for -the given flag. Doing this changes the meaning of the flag slightly. If -a flag has a NoOptDefVal and the flag is set on the command line without -an option the flag will be set to the NoOptDefVal. For example given: - -``` go -var ip = flag.IntP("flagname", "f", 1234, "help message") -flag.Lookup("flagname").NoOptDefVal = "4321" -``` - -Would result in something like - -| Parsed Arguments | Resulting Value | -| ------------- | ------------- | -| --flagname=1357 | ip=1357 | -| --flagname | ip=4321 | -| [nothing] | ip=1234 | - -## Command line flag syntax - -``` ---flag // boolean flags, or flags with no option default values ---flag x // only on flags without a default value ---flag=x -``` - -Unlike the flag package, a single dash before an option means something -different than a double dash. Single dashes signify a series of shorthand -letters for flags. All but the last shorthand letter must be boolean flags -or a flag with a default value - -``` -// boolean or flags where the 'no option default value' is set --f --f=true --abc -but --b true is INVALID - -// non-boolean and flags without a 'no option default value' --n 1234 --n=1234 --n1234 - -// mixed --abcs "hello" --absd="hello" --abcs1234 -``` - -Flag parsing stops after the terminator "--". Unlike the flag package, -flags can be interspersed with arguments anywhere on the command line -before this terminator. - -Integer flags accept 1234, 0664, 0x1234 and may be negative. -Boolean flags (in their long form) accept 1, 0, t, f, true, false, -TRUE, FALSE, True, False. -Duration flags accept any input valid for time.ParseDuration. - -## Mutating or "Normalizing" Flag names - -It is possible to set a custom flag name 'normalization function.' It allows flag names to be mutated both when created in the code and when used on the command line to some 'normalized' form. The 'normalized' form is used for comparison. Two examples of using the custom normalization func follow. - -**Example #1**: You want -, _, and . in flags to compare the same. aka --my-flag == --my_flag == --my.flag - -``` go -func wordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - from := []string{"-", "_"} - to := "." - for _, sep := range from { - name = strings.Replace(name, sep, to, -1) - } - return pflag.NormalizedName(name) -} - -myFlagSet.SetNormalizeFunc(wordSepNormalizeFunc) -``` - -**Example #2**: You want to alias two flags. aka --old-flag-name == --new-flag-name - -``` go -func aliasNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { - switch name { - case "old-flag-name": - name = "new-flag-name" - break - } - return pflag.NormalizedName(name) -} - -myFlagSet.SetNormalizeFunc(aliasNormalizeFunc) -``` - -## Deprecating a flag or its shorthand -It is possible to deprecate a flag, or just its shorthand. Deprecating a flag/shorthand hides it from help text and prints a usage message when the deprecated flag/shorthand is used. - -**Example #1**: You want to deprecate a flag named "badflag" as well as inform the users what flag they should use instead. -```go -// deprecate a flag by specifying its name and a usage message -flags.MarkDeprecated("badflag", "please use --good-flag instead") -``` -This hides "badflag" from help text, and prints `Flag --badflag has been deprecated, please use --good-flag instead` when "badflag" is used. - -**Example #2**: You want to keep a flag name "noshorthandflag" but deprecate its shortname "n". -```go -// deprecate a flag shorthand by specifying its flag name and a usage message -flags.MarkShorthandDeprecated("noshorthandflag", "please use --noshorthandflag only") -``` -This hides the shortname "n" from help text, and prints `Flag shorthand -n has been deprecated, please use --noshorthandflag only` when the shorthand "n" is used. - -Note that usage message is essential here, and it should not be empty. - -## Hidden flags -It is possible to mark a flag as hidden, meaning it will still function as normal, however will not show up in usage/help text. - -**Example**: You have a flag named "secretFlag" that you need for internal use only and don't want it showing up in help text, or for its usage text to be available. -```go -// hide a flag by specifying its name -flags.MarkHidden("secretFlag") -``` - -## Disable sorting of flags -`pflag` allows you to disable sorting of flags for help and usage message. - -**Example**: -```go -flags.BoolP("verbose", "v", false, "verbose output") -flags.String("coolflag", "yeaah", "it's really cool flag") -flags.Int("usefulflag", 777, "sometimes it's very useful") -flags.SortFlags = false -flags.PrintDefaults() -``` -**Output**: -``` - -v, --verbose verbose output - --coolflag string it's really cool flag (default "yeaah") - --usefulflag int sometimes it's very useful (default 777) -``` - - -## Supporting Go flags when using pflag -In order to support flags defined using Go's `flag` package, they must be added to the `pflag` flagset. This is usually necessary -to support flags defined by third-party dependencies (e.g. `golang/glog`). - -**Example**: You want to add the Go flags to the `CommandLine` flagset -```go -import ( - goflag "flag" - flag "github.com/spf13/pflag" -) - -var ip *int = flag.Int("flagname", 1234, "help message for flagname") - -func main() { - flag.CommandLine.AddGoFlagSet(goflag.CommandLine) - flag.Parse() -} -``` - -## More info - -You can see the full reference documentation of the pflag package -[at godoc.org][3], or through go's standard documentation system by -running `godoc -http=:6060` and browsing to -[http://localhost:6060/pkg/github.com/spf13/pflag][2] after -installation. - -[2]: http://localhost:6060/pkg/github.com/spf13/pflag -[3]: http://godoc.org/github.com/spf13/pflag diff --git a/vendor/github.com/spf13/pflag/bool.go b/vendor/github.com/spf13/pflag/bool.go deleted file mode 100644 index c4c5c0bf..00000000 --- a/vendor/github.com/spf13/pflag/bool.go +++ /dev/null @@ -1,94 +0,0 @@ -package pflag - -import "strconv" - -// optional interface to indicate boolean flags that can be -// supplied without "=value" text -type boolFlag interface { - Value - IsBoolFlag() bool -} - -// -- bool Value -type boolValue bool - -func newBoolValue(val bool, p *bool) *boolValue { - *p = val - return (*boolValue)(p) -} - -func (b *boolValue) Set(s string) error { - v, err := strconv.ParseBool(s) - *b = boolValue(v) - return err -} - -func (b *boolValue) Type() string { - return "bool" -} - -func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } - -func (b *boolValue) IsBoolFlag() bool { return true } - -func boolConv(sval string) (interface{}, error) { - return strconv.ParseBool(sval) -} - -// GetBool return the bool value of a flag with the given name -func (f *FlagSet) GetBool(name string) (bool, error) { - val, err := f.getFlagType(name, "bool", boolConv) - if err != nil { - return false, err - } - return val.(bool), nil -} - -// BoolVar defines a bool flag with specified name, default value, and usage string. -// The argument p points to a bool variable in which to store the value of the flag. -func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { - f.BoolVarP(p, name, "", value, usage) -} - -// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { - flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage) - flag.NoOptDefVal = "true" -} - -// BoolVar defines a bool flag with specified name, default value, and usage string. -// The argument p points to a bool variable in which to store the value of the flag. -func BoolVar(p *bool, name string, value bool, usage string) { - BoolVarP(p, name, "", value, usage) -} - -// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. -func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { - flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage) - flag.NoOptDefVal = "true" -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func (f *FlagSet) Bool(name string, value bool, usage string) *bool { - return f.BoolP(name, "", value, usage) -} - -// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { - p := new(bool) - f.BoolVarP(p, name, shorthand, value, usage) - return p -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func Bool(name string, value bool, usage string) *bool { - return BoolP(name, "", value, usage) -} - -// BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. -func BoolP(name, shorthand string, value bool, usage string) *bool { - b := CommandLine.BoolP(name, shorthand, value, usage) - return b -} diff --git a/vendor/github.com/spf13/pflag/bool_slice.go b/vendor/github.com/spf13/pflag/bool_slice.go deleted file mode 100644 index 5af02f1a..00000000 --- a/vendor/github.com/spf13/pflag/bool_slice.go +++ /dev/null @@ -1,147 +0,0 @@ -package pflag - -import ( - "io" - "strconv" - "strings" -) - -// -- boolSlice Value -type boolSliceValue struct { - value *[]bool - changed bool -} - -func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue { - bsv := new(boolSliceValue) - bsv.value = p - *bsv.value = val - return bsv -} - -// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag. -// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended. -func (s *boolSliceValue) Set(val string) error { - - // remove all quote characters - rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") - - // read flag arguments with CSV parser - boolStrSlice, err := readAsCSV(rmQuote.Replace(val)) - if err != nil && err != io.EOF { - return err - } - - // parse boolean values into slice - out := make([]bool, 0, len(boolStrSlice)) - for _, boolStr := range boolStrSlice { - b, err := strconv.ParseBool(strings.TrimSpace(boolStr)) - if err != nil { - return err - } - out = append(out, b) - } - - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - - s.changed = true - - return nil -} - -// Type returns a string that uniquely represents this flag's type. -func (s *boolSliceValue) Type() string { - return "boolSlice" -} - -// String defines a "native" format for this boolean slice flag value. -func (s *boolSliceValue) String() string { - - boolStrSlice := make([]string, len(*s.value)) - for i, b := range *s.value { - boolStrSlice[i] = strconv.FormatBool(b) - } - - out, _ := writeAsCSV(boolStrSlice) - - return "[" + out + "]" -} - -func boolSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []bool{}, nil - } - ss := strings.Split(val, ",") - out := make([]bool, len(ss)) - for i, t := range ss { - var err error - out[i], err = strconv.ParseBool(t) - if err != nil { - return nil, err - } - } - return out, nil -} - -// GetBoolSlice returns the []bool value of a flag with the given name. -func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) { - val, err := f.getFlagType(name, "boolSlice", boolSliceConv) - if err != nil { - return []bool{}, err - } - return val.([]bool), nil -} - -// BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string. -// The argument p points to a []bool variable in which to store the value of the flag. -func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) { - f.VarP(newBoolSliceValue(value, p), name, "", usage) -} - -// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { - f.VarP(newBoolSliceValue(value, p), name, shorthand, usage) -} - -// BoolSliceVar defines a []bool flag with specified name, default value, and usage string. -// The argument p points to a []bool variable in which to store the value of the flag. -func BoolSliceVar(p *[]bool, name string, value []bool, usage string) { - CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage) -} - -// BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. -func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { - CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage) -} - -// BoolSlice defines a []bool flag with specified name, default value, and usage string. -// The return value is the address of a []bool variable that stores the value of the flag. -func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool { - p := []bool{} - f.BoolSliceVarP(&p, name, "", value, usage) - return &p -} - -// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { - p := []bool{} - f.BoolSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// BoolSlice defines a []bool flag with specified name, default value, and usage string. -// The return value is the address of a []bool variable that stores the value of the flag. -func BoolSlice(name string, value []bool, usage string) *[]bool { - return CommandLine.BoolSliceP(name, "", value, usage) -} - -// BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. -func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { - return CommandLine.BoolSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/bool_slice_test.go b/vendor/github.com/spf13/pflag/bool_slice_test.go deleted file mode 100644 index b617dd23..00000000 --- a/vendor/github.com/spf13/pflag/bool_slice_test.go +++ /dev/null @@ -1,215 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" - "testing" -) - -func setUpBSFlagSet(bsp *[]bool) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.BoolSliceVar(bsp, "bs", []bool{}, "Command separated list!") - return f -} - -func setUpBSFlagSetWithDefault(bsp *[]bool) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.BoolSliceVar(bsp, "bs", []bool{false, true}, "Command separated list!") - return f -} - -func TestEmptyBS(t *testing.T) { - var bs []bool - f := setUpBSFlagSet(&bs) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getBS, err := f.GetBoolSlice("bs") - if err != nil { - t.Fatal("got an error from GetBoolSlice():", err) - } - if len(getBS) != 0 { - t.Fatalf("got bs %v with len=%d but expected length=0", getBS, len(getBS)) - } -} - -func TestBS(t *testing.T) { - var bs []bool - f := setUpBSFlagSet(&bs) - - vals := []string{"1", "F", "TRUE", "0"} - arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range bs { - b, err := strconv.ParseBool(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if b != v { - t.Fatalf("expected is[%d] to be %s but got: %t", i, vals[i], v) - } - } - getBS, err := f.GetBoolSlice("bs") - if err != nil { - t.Fatalf("got error: %v", err) - } - for i, v := range getBS { - b, err := strconv.ParseBool(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if b != v { - t.Fatalf("expected bs[%d] to be %s but got: %t from GetBoolSlice", i, vals[i], v) - } - } -} - -func TestBSDefault(t *testing.T) { - var bs []bool - f := setUpBSFlagSetWithDefault(&bs) - - vals := []string{"false", "T"} - - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range bs { - b, err := strconv.ParseBool(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if b != v { - t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) - } - } - - getBS, err := f.GetBoolSlice("bs") - if err != nil { - t.Fatal("got an error from GetBoolSlice():", err) - } - for i, v := range getBS { - b, err := strconv.ParseBool(vals[i]) - if err != nil { - t.Fatal("got an error from GetBoolSlice():", err) - } - if b != v { - t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) - } - } -} - -func TestBSWithDefault(t *testing.T) { - var bs []bool - f := setUpBSFlagSetWithDefault(&bs) - - vals := []string{"FALSE", "1"} - arg := fmt.Sprintf("--bs=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range bs { - b, err := strconv.ParseBool(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if b != v { - t.Fatalf("expected bs[%d] to be %t but got: %t", i, b, v) - } - } - - getBS, err := f.GetBoolSlice("bs") - if err != nil { - t.Fatal("got an error from GetBoolSlice():", err) - } - for i, v := range getBS { - b, err := strconv.ParseBool(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if b != v { - t.Fatalf("expected bs[%d] to be %t from GetBoolSlice but got: %t", i, b, v) - } - } -} - -func TestBSCalledTwice(t *testing.T) { - var bs []bool - f := setUpBSFlagSet(&bs) - - in := []string{"T,F", "T"} - expected := []bool{true, false, true} - argfmt := "--bs=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range bs { - if expected[i] != v { - t.Fatalf("expected bs[%d] to be %t but got %t", i, expected[i], v) - } - } -} - -func TestBSBadQuoting(t *testing.T) { - - tests := []struct { - Want []bool - FlagArg []string - }{ - { - Want: []bool{true, false, true}, - FlagArg: []string{"1", "0", "true"}, - }, - { - Want: []bool{true, false}, - FlagArg: []string{"True", "F"}, - }, - { - Want: []bool{true, false}, - FlagArg: []string{"T", "0"}, - }, - { - Want: []bool{true, false}, - FlagArg: []string{"1", "0"}, - }, - { - Want: []bool{true, false, false}, - FlagArg: []string{"true,false", "false"}, - }, - { - Want: []bool{true, false, false, true, false, true, false}, - FlagArg: []string{`"true,false,false,1,0, T"`, " false "}, - }, - { - Want: []bool{false, false, true, false, true, false, true}, - FlagArg: []string{`"0, False, T,false , true,F"`, "true"}, - }, - } - - for i, test := range tests { - - var bs []bool - f := setUpBSFlagSet(&bs) - - if err := f.Parse([]string{fmt.Sprintf("--bs=%s", strings.Join(test.FlagArg, ","))}); err != nil { - t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%#v", - err, test.FlagArg, test.Want[i]) - } - - for j, b := range bs { - if b != test.Want[j] { - t.Fatalf("bad value parsed for test %d on bool %d:\nwant:\t%t\ngot:\t%t", i, j, test.Want[j], b) - } - } - } -} diff --git a/vendor/github.com/spf13/pflag/bool_test.go b/vendor/github.com/spf13/pflag/bool_test.go deleted file mode 100644 index a4319e79..00000000 --- a/vendor/github.com/spf13/pflag/bool_test.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - "bytes" - "strconv" - "testing" -) - -// This value can be a boolean ("true", "false") or "maybe" -type triStateValue int - -const ( - triStateFalse triStateValue = 0 - triStateTrue triStateValue = 1 - triStateMaybe triStateValue = 2 -) - -const strTriStateMaybe = "maybe" - -func (v *triStateValue) IsBoolFlag() bool { - return true -} - -func (v *triStateValue) Get() interface{} { - return triStateValue(*v) -} - -func (v *triStateValue) Set(s string) error { - if s == strTriStateMaybe { - *v = triStateMaybe - return nil - } - boolVal, err := strconv.ParseBool(s) - if boolVal { - *v = triStateTrue - } else { - *v = triStateFalse - } - return err -} - -func (v *triStateValue) String() string { - if *v == triStateMaybe { - return strTriStateMaybe - } - return strconv.FormatBool(*v == triStateTrue) -} - -// The type of the flag as required by the pflag.Value interface -func (v *triStateValue) Type() string { - return "version" -} - -func setUpFlagSet(tristate *triStateValue) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - *tristate = triStateFalse - flag := f.VarPF(tristate, "tristate", "t", "tristate value (true, maybe or false)") - flag.NoOptDefVal = "true" - return f -} - -func TestExplicitTrue(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - err := f.Parse([]string{"--tristate=true"}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateTrue { - t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") - } -} - -func TestImplicitTrue(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - err := f.Parse([]string{"--tristate"}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateTrue { - t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") - } -} - -func TestShortFlag(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - err := f.Parse([]string{"-t"}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateTrue { - t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") - } -} - -func TestShortFlagExtraArgument(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - // The"maybe"turns into an arg, since short boolean options will only do true/false - err := f.Parse([]string{"-t", "maybe"}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateTrue { - t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead") - } - args := f.Args() - if len(args) != 1 || args[0] != "maybe" { - t.Fatal("expected an extra 'maybe' argument to stick around") - } -} - -func TestExplicitMaybe(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - err := f.Parse([]string{"--tristate=maybe"}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateMaybe { - t.Fatal("expected", triStateMaybe, "(triStateMaybe) but got", tristate, "instead") - } -} - -func TestExplicitFalse(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - err := f.Parse([]string{"--tristate=false"}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateFalse { - t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead") - } -} - -func TestImplicitFalse(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - if tristate != triStateFalse { - t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead") - } -} - -func TestInvalidValue(t *testing.T) { - var tristate triStateValue - f := setUpFlagSet(&tristate) - var buf bytes.Buffer - f.SetOutput(&buf) - err := f.Parse([]string{"--tristate=invalid"}) - if err == nil { - t.Fatal("expected an error but did not get any, tristate has value", tristate) - } -} - -func TestBoolP(t *testing.T) { - b := BoolP("bool", "b", false, "bool value in CommandLine") - c := BoolP("c", "c", false, "other bool value") - args := []string{"--bool"} - if err := CommandLine.Parse(args); err != nil { - t.Error("expected no error, got ", err) - } - if *b != true { - t.Errorf("expected b=true got b=%v", *b) - } - if *c != false { - t.Errorf("expect c=false got c=%v", *c) - } -} diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go deleted file mode 100644 index 250a4381..00000000 --- a/vendor/github.com/spf13/pflag/count.go +++ /dev/null @@ -1,96 +0,0 @@ -package pflag - -import "strconv" - -// -- count Value -type countValue int - -func newCountValue(val int, p *int) *countValue { - *p = val - return (*countValue)(p) -} - -func (i *countValue) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - // -1 means that no specific value was passed, so increment - if v == -1 { - *i = countValue(*i + 1) - } else { - *i = countValue(v) - } - return err -} - -func (i *countValue) Type() string { - return "count" -} - -func (i *countValue) String() string { return strconv.Itoa(int(*i)) } - -func countConv(sval string) (interface{}, error) { - i, err := strconv.Atoi(sval) - if err != nil { - return nil, err - } - return i, nil -} - -// GetCount return the int value of a flag with the given name -func (f *FlagSet) GetCount(name string) (int, error) { - val, err := f.getFlagType(name, "count", countConv) - if err != nil { - return 0, err - } - return val.(int), nil -} - -// CountVar defines a count flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -// A count flag will add 1 to its value evey time it is found on the command line -func (f *FlagSet) CountVar(p *int, name string, usage string) { - f.CountVarP(p, name, "", usage) -} - -// CountVarP is like CountVar only take a shorthand for the flag name. -func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { - flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) - flag.NoOptDefVal = "-1" -} - -// CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set -func CountVar(p *int, name string, usage string) { - CommandLine.CountVar(p, name, usage) -} - -// CountVarP is like CountVar only take a shorthand for the flag name. -func CountVarP(p *int, name, shorthand string, usage string) { - CommandLine.CountVarP(p, name, shorthand, usage) -} - -// Count defines a count flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -// A count flag will add 1 to its value evey time it is found on the command line -func (f *FlagSet) Count(name string, usage string) *int { - p := new(int) - f.CountVarP(p, name, "", usage) - return p -} - -// CountP is like Count only takes a shorthand for the flag name. -func (f *FlagSet) CountP(name, shorthand string, usage string) *int { - p := new(int) - f.CountVarP(p, name, shorthand, usage) - return p -} - -// Count defines a count flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -// A count flag will add 1 to its value evey time it is found on the command line -func Count(name string, usage string) *int { - return CommandLine.CountP(name, "", usage) -} - -// CountP is like Count only takes a shorthand for the flag name. -func CountP(name, shorthand string, usage string) *int { - return CommandLine.CountP(name, shorthand, usage) -} diff --git a/vendor/github.com/spf13/pflag/count_test.go b/vendor/github.com/spf13/pflag/count_test.go deleted file mode 100644 index 460d96a6..00000000 --- a/vendor/github.com/spf13/pflag/count_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package pflag - -import ( - "os" - "testing" -) - -func setUpCount(c *int) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.CountVarP(c, "verbose", "v", "a counter") - return f -} - -func TestCount(t *testing.T) { - testCases := []struct { - input []string - success bool - expected int - }{ - {[]string{"-vvv"}, true, 3}, - {[]string{"-v", "-v", "-v"}, true, 3}, - {[]string{"-v", "--verbose", "-v"}, true, 3}, - {[]string{"-v=3", "-v"}, true, 4}, - {[]string{"-v=a"}, false, 0}, - } - - devnull, _ := os.Open(os.DevNull) - os.Stderr = devnull - for i := range testCases { - var count int - f := setUpCount(&count) - - tc := &testCases[i] - - err := f.Parse(tc.input) - if err != nil && tc.success == true { - t.Errorf("expected success, got %q", err) - continue - } else if err == nil && tc.success == false { - t.Errorf("expected failure, got success") - continue - } else if tc.success { - c, err := f.GetCount("verbose") - if err != nil { - t.Errorf("Got error trying to fetch the counter flag") - } - if c != tc.expected { - t.Errorf("expected %q, got %q", tc.expected, c) - } - } - } -} diff --git a/vendor/github.com/spf13/pflag/duration.go b/vendor/github.com/spf13/pflag/duration.go deleted file mode 100644 index e9debef8..00000000 --- a/vendor/github.com/spf13/pflag/duration.go +++ /dev/null @@ -1,86 +0,0 @@ -package pflag - -import ( - "time" -) - -// -- time.Duration Value -type durationValue time.Duration - -func newDurationValue(val time.Duration, p *time.Duration) *durationValue { - *p = val - return (*durationValue)(p) -} - -func (d *durationValue) Set(s string) error { - v, err := time.ParseDuration(s) - *d = durationValue(v) - return err -} - -func (d *durationValue) Type() string { - return "duration" -} - -func (d *durationValue) String() string { return (*time.Duration)(d).String() } - -func durationConv(sval string) (interface{}, error) { - return time.ParseDuration(sval) -} - -// GetDuration return the duration value of a flag with the given name -func (f *FlagSet) GetDuration(name string) (time.Duration, error) { - val, err := f.getFlagType(name, "duration", durationConv) - if err != nil { - return 0, err - } - return val.(time.Duration), nil -} - -// DurationVar defines a time.Duration flag with specified name, default value, and usage string. -// The argument p points to a time.Duration variable in which to store the value of the flag. -func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { - f.VarP(newDurationValue(value, p), name, "", usage) -} - -// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { - f.VarP(newDurationValue(value, p), name, shorthand, usage) -} - -// DurationVar defines a time.Duration flag with specified name, default value, and usage string. -// The argument p points to a time.Duration variable in which to store the value of the flag. -func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { - CommandLine.VarP(newDurationValue(value, p), name, "", usage) -} - -// DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. -func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { - CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) -} - -// Duration defines a time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a time.Duration variable that stores the value of the flag. -func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { - p := new(time.Duration) - f.DurationVarP(p, name, "", value, usage) - return p -} - -// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { - p := new(time.Duration) - f.DurationVarP(p, name, shorthand, value, usage) - return p -} - -// Duration defines a time.Duration flag with specified name, default value, and usage string. -// The return value is the address of a time.Duration variable that stores the value of the flag. -func Duration(name string, value time.Duration, usage string) *time.Duration { - return CommandLine.DurationP(name, "", value, usage) -} - -// DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. -func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { - return CommandLine.DurationP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/example_test.go b/vendor/github.com/spf13/pflag/example_test.go deleted file mode 100644 index abd7806f..00000000 --- a/vendor/github.com/spf13/pflag/example_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag_test - -import ( - "fmt" - - "github.com/spf13/pflag" -) - -func ExampleShorthandLookup() { - name := "verbose" - short := name[:1] - - pflag.BoolP(name, short, false, "verbose output") - - // len(short) must be == 1 - flag := pflag.ShorthandLookup(short) - - fmt.Println(flag.Name) -} - -func ExampleFlagSet_ShorthandLookup() { - name := "verbose" - short := name[:1] - - fs := pflag.NewFlagSet("Example", pflag.ContinueOnError) - fs.BoolP(name, short, false, "verbose output") - - // len(short) must be == 1 - flag := fs.ShorthandLookup(short) - - fmt.Println(flag.Name) -} diff --git a/vendor/github.com/spf13/pflag/export_test.go b/vendor/github.com/spf13/pflag/export_test.go deleted file mode 100644 index 9318fee0..00000000 --- a/vendor/github.com/spf13/pflag/export_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - "io/ioutil" - "os" -) - -// Additional routines compiled into the package only during testing. - -// ResetForTesting clears all flag state and sets the usage function as directed. -// After calling ResetForTesting, parse errors in flag handling will not -// exit the program. -func ResetForTesting(usage func()) { - CommandLine = &FlagSet{ - name: os.Args[0], - errorHandling: ContinueOnError, - output: ioutil.Discard, - } - Usage = usage -} - -// GetCommandLine returns the default FlagSet. -func GetCommandLine() *FlagSet { - return CommandLine -} diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go deleted file mode 100644 index 6f1fc300..00000000 --- a/vendor/github.com/spf13/pflag/flag.go +++ /dev/null @@ -1,1128 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package pflag is a drop-in replacement for Go's flag package, implementing -POSIX/GNU-style --flags. - -pflag is compatible with the GNU extensions to the POSIX recommendations -for command-line options. See -http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html - -Usage: - -pflag is a drop-in replacement of Go's native flag package. If you import -pflag under the name "flag" then all code should continue to function -with no changes. - - import flag "github.com/spf13/pflag" - -There is one exception to this: if you directly instantiate the Flag struct -there is one more field "Shorthand" that you will need to set. -Most code never instantiates this struct directly, and instead uses -functions such as String(), BoolVar(), and Var(), and is therefore -unaffected. - -Define flags using flag.String(), Bool(), Int(), etc. - -This declares an integer flag, -flagname, stored in the pointer ip, with type *int. - var ip = flag.Int("flagname", 1234, "help message for flagname") -If you like, you can bind the flag to a variable using the Var() functions. - var flagvar int - func init() { - flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") - } -Or you can create custom flags that satisfy the Value interface (with -pointer receivers) and couple them to flag parsing by - flag.Var(&flagVal, "name", "help message for flagname") -For such flags, the default value is just the initial value of the variable. - -After all flags are defined, call - flag.Parse() -to parse the command line into the defined flags. - -Flags may then be used directly. If you're using the flags themselves, -they are all pointers; if you bind to variables, they're values. - fmt.Println("ip has value ", *ip) - fmt.Println("flagvar has value ", flagvar) - -After parsing, the arguments after the flag are available as the -slice flag.Args() or individually as flag.Arg(i). -The arguments are indexed from 0 through flag.NArg()-1. - -The pflag package also defines some new functions that are not in flag, -that give one-letter shorthands for flags. You can use these by appending -'P' to the name of any function that defines a flag. - var ip = flag.IntP("flagname", "f", 1234, "help message") - var flagvar bool - func init() { - flag.BoolVarP("boolname", "b", true, "help message") - } - flag.VarP(&flagVar, "varname", "v", 1234, "help message") -Shorthand letters can be used with single dashes on the command line. -Boolean shorthand flags can be combined with other shorthand flags. - -Command line flag syntax: - --flag // boolean flags only - --flag=x - -Unlike the flag package, a single dash before an option means something -different than a double dash. Single dashes signify a series of shorthand -letters for flags. All but the last shorthand letter must be boolean flags. - // boolean flags - -f - -abc - // non-boolean flags - -n 1234 - -Ifile - // mixed - -abcs "hello" - -abcn1234 - -Flag parsing stops after the terminator "--". Unlike the flag package, -flags can be interspersed with arguments anywhere on the command line -before this terminator. - -Integer flags accept 1234, 0664, 0x1234 and may be negative. -Boolean flags (in their long form) accept 1, 0, t, f, true, false, -TRUE, FALSE, True, False. -Duration flags accept any input valid for time.ParseDuration. - -The default set of command-line flags is controlled by -top-level functions. The FlagSet type allows one to define -independent sets of flags, such as to implement subcommands -in a command-line interface. The methods of FlagSet are -analogous to the top-level functions for the command-line -flag set. -*/ -package pflag - -import ( - "bytes" - "errors" - "fmt" - "io" - "os" - "sort" - "strings" -) - -// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. -var ErrHelp = errors.New("pflag: help requested") - -// ErrorHandling defines how to handle flag parsing errors. -type ErrorHandling int - -const ( - // ContinueOnError will return an err from Parse() if an error is found - ContinueOnError ErrorHandling = iota - // ExitOnError will call os.Exit(2) if an error is found when parsing - ExitOnError - // PanicOnError will panic() if an error is found when parsing flags - PanicOnError -) - -// NormalizedName is a flag name that has been normalized according to rules -// for the FlagSet (e.g. making '-' and '_' equivalent). -type NormalizedName string - -// A FlagSet represents a set of defined flags. -type FlagSet struct { - // Usage is the function called when an error occurs while parsing flags. - // The field is a function (not a method) that may be changed to point to - // a custom error handler. - Usage func() - - // SortFlags is used to indicate, if user wants to have sorted flags in - // help/usage messages. - SortFlags bool - - name string - parsed bool - actual map[NormalizedName]*Flag - orderedActual []*Flag - sortedActual []*Flag - formal map[NormalizedName]*Flag - orderedFormal []*Flag - sortedFormal []*Flag - shorthands map[byte]*Flag - args []string // arguments after flags - argsLenAtDash int // len(args) when a '--' was located when parsing, or -1 if no -- - errorHandling ErrorHandling - output io.Writer // nil means stderr; use out() accessor - interspersed bool // allow interspersed option/non-option args - normalizeNameFunc func(f *FlagSet, name string) NormalizedName -} - -// A Flag represents the state of a flag. -type Flag struct { - Name string // name as it appears on command line - Shorthand string // one-letter abbreviated flag - Usage string // help message - Value Value // value as set - DefValue string // default value (as text); for usage message - Changed bool // If the user set the value (or if left to default) - NoOptDefVal string // default value (as text); if the flag is on the command line without any options - Deprecated string // If this flag is deprecated, this string is the new or now thing to use - Hidden bool // used by cobra.Command to allow flags to be hidden from help/usage text - ShorthandDeprecated string // If the shorthand of this flag is deprecated, this string is the new or now thing to use - Annotations map[string][]string // used by cobra.Command bash autocomple code -} - -// Value is the interface to the dynamic value stored in a flag. -// (The default value is represented as a string.) -type Value interface { - String() string - Set(string) error - Type() string -} - -// sortFlags returns the flags as a slice in lexicographical sorted order. -func sortFlags(flags map[NormalizedName]*Flag) []*Flag { - list := make(sort.StringSlice, len(flags)) - i := 0 - for k := range flags { - list[i] = string(k) - i++ - } - list.Sort() - result := make([]*Flag, len(list)) - for i, name := range list { - result[i] = flags[NormalizedName(name)] - } - return result -} - -// SetNormalizeFunc allows you to add a function which can translate flag names. -// Flags added to the FlagSet will be translated and then when anything tries to -// look up the flag that will also be translated. So it would be possible to create -// a flag named "getURL" and have it translated to "geturl". A user could then pass -// "--getUrl" which may also be translated to "geturl" and everything will work. -func (f *FlagSet) SetNormalizeFunc(n func(f *FlagSet, name string) NormalizedName) { - f.normalizeNameFunc = n - f.sortedFormal = f.sortedFormal[:0] - for k, v := range f.orderedFormal { - delete(f.formal, NormalizedName(v.Name)) - nname := f.normalizeFlagName(v.Name) - v.Name = string(nname) - f.formal[nname] = v - f.orderedFormal[k] = v - } -} - -// GetNormalizeFunc returns the previously set NormalizeFunc of a function which -// does no translation, if not set previously. -func (f *FlagSet) GetNormalizeFunc() func(f *FlagSet, name string) NormalizedName { - if f.normalizeNameFunc != nil { - return f.normalizeNameFunc - } - return func(f *FlagSet, name string) NormalizedName { return NormalizedName(name) } -} - -func (f *FlagSet) normalizeFlagName(name string) NormalizedName { - n := f.GetNormalizeFunc() - return n(f, name) -} - -func (f *FlagSet) out() io.Writer { - if f.output == nil { - return os.Stderr - } - return f.output -} - -// SetOutput sets the destination for usage and error messages. -// If output is nil, os.Stderr is used. -func (f *FlagSet) SetOutput(output io.Writer) { - f.output = output -} - -// VisitAll visits the flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits all flags, even those not set. -func (f *FlagSet) VisitAll(fn func(*Flag)) { - if len(f.formal) == 0 { - return - } - - var flags []*Flag - if f.SortFlags { - if len(f.formal) != len(f.sortedFormal) { - f.sortedFormal = sortFlags(f.formal) - } - flags = f.sortedFormal - } else { - flags = f.orderedFormal - } - - for _, flag := range flags { - fn(flag) - } -} - -// HasFlags returns a bool to indicate if the FlagSet has any flags definied. -func (f *FlagSet) HasFlags() bool { - return len(f.formal) > 0 -} - -// HasAvailableFlags returns a bool to indicate if the FlagSet has any flags -// definied that are not hidden or deprecated. -func (f *FlagSet) HasAvailableFlags() bool { - for _, flag := range f.formal { - if !flag.Hidden && len(flag.Deprecated) == 0 { - return true - } - } - return false -} - -// VisitAll visits the command-line flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits all flags, even those not set. -func VisitAll(fn func(*Flag)) { - CommandLine.VisitAll(fn) -} - -// Visit visits the flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits only those flags that have been set. -func (f *FlagSet) Visit(fn func(*Flag)) { - if len(f.actual) == 0 { - return - } - - var flags []*Flag - if f.SortFlags { - if len(f.actual) != len(f.sortedActual) { - f.sortedActual = sortFlags(f.actual) - } - flags = f.sortedActual - } else { - flags = f.orderedActual - } - - for _, flag := range flags { - fn(flag) - } -} - -// Visit visits the command-line flags in lexicographical order or -// in primordial order if f.SortFlags is false, calling fn for each. -// It visits only those flags that have been set. -func Visit(fn func(*Flag)) { - CommandLine.Visit(fn) -} - -// Lookup returns the Flag structure of the named flag, returning nil if none exists. -func (f *FlagSet) Lookup(name string) *Flag { - return f.lookup(f.normalizeFlagName(name)) -} - -// ShorthandLookup returns the Flag structure of the short handed flag, -// returning nil if none exists. -// It panics, if len(name) > 1. -func (f *FlagSet) ShorthandLookup(name string) *Flag { - if name == "" { - return nil - } - if len(name) > 1 { - msg := fmt.Sprintf("can not look up shorthand which is more than one ASCII character: %q", name) - fmt.Fprintf(f.out(), msg) - panic(msg) - } - c := name[0] - return f.shorthands[c] -} - -// lookup returns the Flag structure of the named flag, returning nil if none exists. -func (f *FlagSet) lookup(name NormalizedName) *Flag { - return f.formal[name] -} - -// func to return a given type for a given flag name -func (f *FlagSet) getFlagType(name string, ftype string, convFunc func(sval string) (interface{}, error)) (interface{}, error) { - flag := f.Lookup(name) - if flag == nil { - err := fmt.Errorf("flag accessed but not defined: %s", name) - return nil, err - } - - if flag.Value.Type() != ftype { - err := fmt.Errorf("trying to get %s value of flag of type %s", ftype, flag.Value.Type()) - return nil, err - } - - sval := flag.Value.String() - result, err := convFunc(sval) - if err != nil { - return nil, err - } - return result, nil -} - -// ArgsLenAtDash will return the length of f.Args at the moment when a -- was -// found during arg parsing. This allows your program to know which args were -// before the -- and which came after. -func (f *FlagSet) ArgsLenAtDash() int { - return f.argsLenAtDash -} - -// MarkDeprecated indicated that a flag is deprecated in your program. It will -// continue to function but will not show up in help or usage messages. Using -// this flag will also print the given usageMessage. -func (f *FlagSet) MarkDeprecated(name string, usageMessage string) error { - flag := f.Lookup(name) - if flag == nil { - return fmt.Errorf("flag %q does not exist", name) - } - if usageMessage == "" { - return fmt.Errorf("deprecated message for flag %q must be set", name) - } - flag.Deprecated = usageMessage - return nil -} - -// MarkShorthandDeprecated will mark the shorthand of a flag deprecated in your -// program. It will continue to function but will not show up in help or usage -// messages. Using this flag will also print the given usageMessage. -func (f *FlagSet) MarkShorthandDeprecated(name string, usageMessage string) error { - flag := f.Lookup(name) - if flag == nil { - return fmt.Errorf("flag %q does not exist", name) - } - if usageMessage == "" { - return fmt.Errorf("deprecated message for flag %q must be set", name) - } - flag.ShorthandDeprecated = usageMessage - return nil -} - -// MarkHidden sets a flag to 'hidden' in your program. It will continue to -// function but will not show up in help or usage messages. -func (f *FlagSet) MarkHidden(name string) error { - flag := f.Lookup(name) - if flag == nil { - return fmt.Errorf("flag %q does not exist", name) - } - flag.Hidden = true - return nil -} - -// Lookup returns the Flag structure of the named command-line flag, -// returning nil if none exists. -func Lookup(name string) *Flag { - return CommandLine.Lookup(name) -} - -// ShorthandLookup returns the Flag structure of the short handed flag, -// returning nil if none exists. -func ShorthandLookup(name string) *Flag { - return CommandLine.ShorthandLookup(name) -} - -// Set sets the value of the named flag. -func (f *FlagSet) Set(name, value string) error { - normalName := f.normalizeFlagName(name) - flag, ok := f.formal[normalName] - if !ok { - return fmt.Errorf("no such flag -%v", name) - } - - err := flag.Value.Set(value) - if err != nil { - var flagName string - if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { - flagName = fmt.Sprintf("-%s, --%s", flag.Shorthand, flag.Name) - } else { - flagName = fmt.Sprintf("--%s", flag.Name) - } - return fmt.Errorf("invalid argument %q for %q flag: %v", value, flagName, err) - } - - if f.actual == nil { - f.actual = make(map[NormalizedName]*Flag) - } - f.actual[normalName] = flag - f.orderedActual = append(f.orderedActual, flag) - - flag.Changed = true - - if flag.Deprecated != "" { - fmt.Fprintf(f.out(), "Flag --%s has been deprecated, %s\n", flag.Name, flag.Deprecated) - } - return nil -} - -// SetAnnotation allows one to set arbitrary annotations on a flag in the FlagSet. -// This is sometimes used by spf13/cobra programs which want to generate additional -// bash completion information. -func (f *FlagSet) SetAnnotation(name, key string, values []string) error { - normalName := f.normalizeFlagName(name) - flag, ok := f.formal[normalName] - if !ok { - return fmt.Errorf("no such flag -%v", name) - } - if flag.Annotations == nil { - flag.Annotations = map[string][]string{} - } - flag.Annotations[key] = values - return nil -} - -// Changed returns true if the flag was explicitly set during Parse() and false -// otherwise -func (f *FlagSet) Changed(name string) bool { - flag := f.Lookup(name) - // If a flag doesn't exist, it wasn't changed.... - if flag == nil { - return false - } - return flag.Changed -} - -// Set sets the value of the named command-line flag. -func Set(name, value string) error { - return CommandLine.Set(name, value) -} - -// PrintDefaults prints, to standard error unless configured -// otherwise, the default values of all defined flags in the set. -func (f *FlagSet) PrintDefaults() { - usages := f.FlagUsages() - fmt.Fprint(f.out(), usages) -} - -// defaultIsZeroValue returns true if the default value for this flag represents -// a zero value. -func (f *Flag) defaultIsZeroValue() bool { - switch f.Value.(type) { - case boolFlag: - return f.DefValue == "false" - case *durationValue: - // Beginning in Go 1.7, duration zero values are "0s" - return f.DefValue == "0" || f.DefValue == "0s" - case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value: - return f.DefValue == "0" - case *stringValue: - return f.DefValue == "" - case *ipValue, *ipMaskValue, *ipNetValue: - return f.DefValue == "" - case *intSliceValue, *stringSliceValue, *stringArrayValue: - return f.DefValue == "[]" - default: - switch f.Value.String() { - case "false": - return true - case "": - return true - case "": - return true - case "0": - return true - } - return false - } -} - -// UnquoteUsage extracts a back-quoted name from the usage -// string for a flag and returns it and the un-quoted usage. -// Given "a `name` to show" it returns ("name", "a name to show"). -// If there are no back quotes, the name is an educated guess of the -// type of the flag's value, or the empty string if the flag is boolean. -func UnquoteUsage(flag *Flag) (name string, usage string) { - // Look for a back-quoted name, but avoid the strings package. - usage = flag.Usage - for i := 0; i < len(usage); i++ { - if usage[i] == '`' { - for j := i + 1; j < len(usage); j++ { - if usage[j] == '`' { - name = usage[i+1 : j] - usage = usage[:i] + name + usage[j+1:] - return name, usage - } - } - break // Only one back quote; use type name. - } - } - - name = flag.Value.Type() - switch name { - case "bool": - name = "" - case "float64": - name = "float" - case "int64": - name = "int" - case "uint64": - name = "uint" - } - - return -} - -// Splits the string `s` on whitespace into an initial substring up to -// `i` runes in length and the remainder. Will go `slop` over `i` if -// that encompasses the entire string (which allows the caller to -// avoid short orphan words on the final line). -func wrapN(i, slop int, s string) (string, string) { - if i+slop > len(s) { - return s, "" - } - - w := strings.LastIndexAny(s[:i], " \t") - if w <= 0 { - return s, "" - } - - return s[:w], s[w+1:] -} - -// Wraps the string `s` to a maximum width `w` with leading indent -// `i`. The first line is not indented (this is assumed to be done by -// caller). Pass `w` == 0 to do no wrapping -func wrap(i, w int, s string) string { - if w == 0 { - return s - } - - // space between indent i and end of line width w into which - // we should wrap the text. - wrap := w - i - - var r, l string - - // Not enough space for sensible wrapping. Wrap as a block on - // the next line instead. - if wrap < 24 { - i = 16 - wrap = w - i - r += "\n" + strings.Repeat(" ", i) - } - // If still not enough space then don't even try to wrap. - if wrap < 24 { - return s - } - - // Try to avoid short orphan words on the final line, by - // allowing wrapN to go a bit over if that would fit in the - // remainder of the line. - slop := 5 - wrap = wrap - slop - - // Handle first line, which is indented by the caller (or the - // special case above) - l, s = wrapN(wrap, slop, s) - r = r + l - - // Now wrap the rest - for s != "" { - var t string - - t, s = wrapN(wrap, slop, s) - r = r + "\n" + strings.Repeat(" ", i) + t - } - - return r - -} - -// FlagUsagesWrapped returns a string containing the usage information -// for all flags in the FlagSet. Wrapped to `cols` columns (0 for no -// wrapping) -func (f *FlagSet) FlagUsagesWrapped(cols int) string { - buf := new(bytes.Buffer) - - lines := make([]string, 0, len(f.formal)) - - maxlen := 0 - f.VisitAll(func(flag *Flag) { - if flag.Deprecated != "" || flag.Hidden { - return - } - - line := "" - if flag.Shorthand != "" && flag.ShorthandDeprecated == "" { - line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name) - } else { - line = fmt.Sprintf(" --%s", flag.Name) - } - - varname, usage := UnquoteUsage(flag) - if varname != "" { - line += " " + varname - } - if flag.NoOptDefVal != "" { - switch flag.Value.Type() { - case "string": - line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal) - case "bool": - if flag.NoOptDefVal != "true" { - line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) - } - default: - line += fmt.Sprintf("[=%s]", flag.NoOptDefVal) - } - } - - // This special character will be replaced with spacing once the - // correct alignment is calculated - line += "\x00" - if len(line) > maxlen { - maxlen = len(line) - } - - line += usage - if !flag.defaultIsZeroValue() { - if flag.Value.Type() == "string" { - line += fmt.Sprintf(" (default %q)", flag.DefValue) - } else { - line += fmt.Sprintf(" (default %s)", flag.DefValue) - } - } - - lines = append(lines, line) - }) - - for _, line := range lines { - sidx := strings.Index(line, "\x00") - spacing := strings.Repeat(" ", maxlen-sidx) - // maxlen + 2 comes from + 1 for the \x00 and + 1 for the (deliberate) off-by-one in maxlen-sidx - fmt.Fprintln(buf, line[:sidx], spacing, wrap(maxlen+2, cols, line[sidx+1:])) - } - - return buf.String() -} - -// FlagUsages returns a string containing the usage information for all flags in -// the FlagSet -func (f *FlagSet) FlagUsages() string { - return f.FlagUsagesWrapped(0) -} - -// PrintDefaults prints to standard error the default values of all defined command-line flags. -func PrintDefaults() { - CommandLine.PrintDefaults() -} - -// defaultUsage is the default function to print a usage message. -func defaultUsage(f *FlagSet) { - fmt.Fprintf(f.out(), "Usage of %s:\n", f.name) - f.PrintDefaults() -} - -// NOTE: Usage is not just defaultUsage(CommandLine) -// because it serves (via godoc flag Usage) as the example -// for how to write your own usage function. - -// Usage prints to standard error a usage message documenting all defined command-line flags. -// The function is a variable that may be changed to point to a custom function. -// By default it prints a simple header and calls PrintDefaults; for details about the -// format of the output and how to control it, see the documentation for PrintDefaults. -var Usage = func() { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) - PrintDefaults() -} - -// NFlag returns the number of flags that have been set. -func (f *FlagSet) NFlag() int { return len(f.actual) } - -// NFlag returns the number of command-line flags that have been set. -func NFlag() int { return len(CommandLine.actual) } - -// Arg returns the i'th argument. Arg(0) is the first remaining argument -// after flags have been processed. -func (f *FlagSet) Arg(i int) string { - if i < 0 || i >= len(f.args) { - return "" - } - return f.args[i] -} - -// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument -// after flags have been processed. -func Arg(i int) string { - return CommandLine.Arg(i) -} - -// NArg is the number of arguments remaining after flags have been processed. -func (f *FlagSet) NArg() int { return len(f.args) } - -// NArg is the number of arguments remaining after flags have been processed. -func NArg() int { return len(CommandLine.args) } - -// Args returns the non-flag arguments. -func (f *FlagSet) Args() []string { return f.args } - -// Args returns the non-flag command-line arguments. -func Args() []string { return CommandLine.args } - -// Var defines a flag with the specified name and usage string. The type and -// value of the flag are represented by the first argument, of type Value, which -// typically holds a user-defined implementation of Value. For instance, the -// caller could create a flag that turns a comma-separated string into a slice -// of strings by giving the slice the methods of Value; in particular, Set would -// decompose the comma-separated string into the slice. -func (f *FlagSet) Var(value Value, name string, usage string) { - f.VarP(value, name, "", usage) -} - -// VarPF is like VarP, but returns the flag created -func (f *FlagSet) VarPF(value Value, name, shorthand, usage string) *Flag { - // Remember the default value as a string; it won't change. - flag := &Flag{ - Name: name, - Shorthand: shorthand, - Usage: usage, - Value: value, - DefValue: value.String(), - } - f.AddFlag(flag) - return flag -} - -// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) VarP(value Value, name, shorthand, usage string) { - f.VarPF(value, name, shorthand, usage) -} - -// AddFlag will add the flag to the FlagSet -func (f *FlagSet) AddFlag(flag *Flag) { - normalizedFlagName := f.normalizeFlagName(flag.Name) - - _, alreadyThere := f.formal[normalizedFlagName] - if alreadyThere { - msg := fmt.Sprintf("%s flag redefined: %s", f.name, flag.Name) - fmt.Fprintln(f.out(), msg) - panic(msg) // Happens only if flags are declared with identical names - } - if f.formal == nil { - f.formal = make(map[NormalizedName]*Flag) - } - - flag.Name = string(normalizedFlagName) - f.formal[normalizedFlagName] = flag - f.orderedFormal = append(f.orderedFormal, flag) - - if flag.Shorthand == "" { - return - } - if len(flag.Shorthand) > 1 { - msg := fmt.Sprintf("%q shorthand is more than one ASCII character", flag.Shorthand) - fmt.Fprintf(f.out(), msg) - panic(msg) - } - if f.shorthands == nil { - f.shorthands = make(map[byte]*Flag) - } - c := flag.Shorthand[0] - used, alreadyThere := f.shorthands[c] - if alreadyThere { - msg := fmt.Sprintf("unable to redefine %q shorthand in %q flagset: it's already used for %q flag", c, f.name, used.Name) - fmt.Fprintf(f.out(), msg) - panic(msg) - } - f.shorthands[c] = flag -} - -// AddFlagSet adds one FlagSet to another. If a flag is already present in f -// the flag from newSet will be ignored. -func (f *FlagSet) AddFlagSet(newSet *FlagSet) { - if newSet == nil { - return - } - newSet.VisitAll(func(flag *Flag) { - if f.Lookup(flag.Name) == nil { - f.AddFlag(flag) - } - }) -} - -// Var defines a flag with the specified name and usage string. The type and -// value of the flag are represented by the first argument, of type Value, which -// typically holds a user-defined implementation of Value. For instance, the -// caller could create a flag that turns a comma-separated string into a slice -// of strings by giving the slice the methods of Value; in particular, Set would -// decompose the comma-separated string into the slice. -func Var(value Value, name string, usage string) { - CommandLine.VarP(value, name, "", usage) -} - -// VarP is like Var, but accepts a shorthand letter that can be used after a single dash. -func VarP(value Value, name, shorthand, usage string) { - CommandLine.VarP(value, name, shorthand, usage) -} - -// failf prints to standard error a formatted error and usage message and -// returns the error. -func (f *FlagSet) failf(format string, a ...interface{}) error { - err := fmt.Errorf(format, a...) - fmt.Fprintln(f.out(), err) - f.usage() - return err -} - -// usage calls the Usage method for the flag set, or the usage function if -// the flag set is CommandLine. -func (f *FlagSet) usage() { - if f == CommandLine { - Usage() - } else if f.Usage == nil { - defaultUsage(f) - } else { - f.Usage() - } -} - -func (f *FlagSet) parseLongArg(s string, args []string, fn parseFunc) (a []string, err error) { - a = args - name := s[2:] - if len(name) == 0 || name[0] == '-' || name[0] == '=' { - err = f.failf("bad flag syntax: %s", s) - return - } - - split := strings.SplitN(name, "=", 2) - name = split[0] - flag, exists := f.formal[f.normalizeFlagName(name)] - if !exists { - if name == "help" { // special case for nice help message. - f.usage() - return a, ErrHelp - } - err = f.failf("unknown flag: --%s", name) - return - } - - var value string - if len(split) == 2 { - // '--flag=arg' - value = split[1] - } else if flag.NoOptDefVal != "" { - // '--flag' (arg was optional) - value = flag.NoOptDefVal - } else if len(a) > 0 { - // '--flag arg' - value = a[0] - a = a[1:] - } else { - // '--flag' (arg was required) - err = f.failf("flag needs an argument: %s", s) - return - } - - err = fn(flag, value) - return -} - -func (f *FlagSet) parseSingleShortArg(shorthands string, args []string, fn parseFunc) (outShorts string, outArgs []string, err error) { - if strings.HasPrefix(shorthands, "test.") { - return - } - - outArgs = args - outShorts = shorthands[1:] - c := shorthands[0] - - flag, exists := f.shorthands[c] - if !exists { - if c == 'h' { // special case for nice help message. - f.usage() - err = ErrHelp - return - } - err = f.failf("unknown shorthand flag: %q in -%s", c, shorthands) - return - } - - var value string - if len(shorthands) > 2 && shorthands[1] == '=' { - // '-f=arg' - value = shorthands[2:] - outShorts = "" - } else if flag.NoOptDefVal != "" { - // '-f' (arg was optional) - value = flag.NoOptDefVal - } else if len(shorthands) > 1 { - // '-farg' - value = shorthands[1:] - outShorts = "" - } else if len(args) > 0 { - // '-f arg' - value = args[0] - outArgs = args[1:] - } else { - // '-f' (arg was required) - err = f.failf("flag needs an argument: %q in -%s", c, shorthands) - return - } - - if flag.ShorthandDeprecated != "" { - fmt.Fprintf(f.out(), "Flag shorthand -%s has been deprecated, %s\n", flag.Shorthand, flag.ShorthandDeprecated) - } - - err = fn(flag, value) - return -} - -func (f *FlagSet) parseShortArg(s string, args []string, fn parseFunc) (a []string, err error) { - a = args - shorthands := s[1:] - - // "shorthands" can be a series of shorthand letters of flags (e.g. "-vvv"). - for len(shorthands) > 0 { - shorthands, a, err = f.parseSingleShortArg(shorthands, args, fn) - if err != nil { - return - } - } - - return -} - -func (f *FlagSet) parseArgs(args []string, fn parseFunc) (err error) { - for len(args) > 0 { - s := args[0] - args = args[1:] - if len(s) == 0 || s[0] != '-' || len(s) == 1 { - if !f.interspersed { - f.args = append(f.args, s) - f.args = append(f.args, args...) - return nil - } - f.args = append(f.args, s) - continue - } - - if s[1] == '-' { - if len(s) == 2 { // "--" terminates the flags - f.argsLenAtDash = len(f.args) - f.args = append(f.args, args...) - break - } - args, err = f.parseLongArg(s, args, fn) - } else { - args, err = f.parseShortArg(s, args, fn) - } - if err != nil { - return - } - } - return -} - -// Parse parses flag definitions from the argument list, which should not -// include the command name. Must be called after all flags in the FlagSet -// are defined and before flags are accessed by the program. -// The return value will be ErrHelp if -help was set but not defined. -func (f *FlagSet) Parse(arguments []string) error { - f.parsed = true - - if len(arguments) < 0 { - return nil - } - - f.args = make([]string, 0, len(arguments)) - - set := func(flag *Flag, value string) error { - return f.Set(flag.Name, value) - } - - err := f.parseArgs(arguments, set) - if err != nil { - switch f.errorHandling { - case ContinueOnError: - return err - case ExitOnError: - os.Exit(2) - case PanicOnError: - panic(err) - } - } - return nil -} - -type parseFunc func(flag *Flag, value string) error - -// ParseAll parses flag definitions from the argument list, which should not -// include the command name. The arguments for fn are flag and value. Must be -// called after all flags in the FlagSet are defined and before flags are -// accessed by the program. The return value will be ErrHelp if -help was set -// but not defined. -func (f *FlagSet) ParseAll(arguments []string, fn func(flag *Flag, value string) error) error { - f.parsed = true - f.args = make([]string, 0, len(arguments)) - - err := f.parseArgs(arguments, fn) - if err != nil { - switch f.errorHandling { - case ContinueOnError: - return err - case ExitOnError: - os.Exit(2) - case PanicOnError: - panic(err) - } - } - return nil -} - -// Parsed reports whether f.Parse has been called. -func (f *FlagSet) Parsed() bool { - return f.parsed -} - -// Parse parses the command-line flags from os.Args[1:]. Must be called -// after all flags are defined and before flags are accessed by the program. -func Parse() { - // Ignore errors; CommandLine is set for ExitOnError. - CommandLine.Parse(os.Args[1:]) -} - -// ParseAll parses the command-line flags from os.Args[1:] and called fn for each. -// The arguments for fn are flag and value. Must be called after all flags are -// defined and before flags are accessed by the program. -func ParseAll(fn func(flag *Flag, value string) error) { - // Ignore errors; CommandLine is set for ExitOnError. - CommandLine.ParseAll(os.Args[1:], fn) -} - -// SetInterspersed sets whether to support interspersed option/non-option arguments. -func SetInterspersed(interspersed bool) { - CommandLine.SetInterspersed(interspersed) -} - -// Parsed returns true if the command-line flags have been parsed. -func Parsed() bool { - return CommandLine.Parsed() -} - -// CommandLine is the default set of command-line flags, parsed from os.Args. -var CommandLine = NewFlagSet(os.Args[0], ExitOnError) - -// NewFlagSet returns a new, empty flag set with the specified name, -// error handling property and SortFlags set to true. -func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { - f := &FlagSet{ - name: name, - errorHandling: errorHandling, - argsLenAtDash: -1, - interspersed: true, - SortFlags: true, - } - return f -} - -// SetInterspersed sets whether to support interspersed option/non-option arguments. -func (f *FlagSet) SetInterspersed(interspersed bool) { - f.interspersed = interspersed -} - -// Init sets the name and error handling property for a flag set. -// By default, the zero FlagSet uses an empty name and the -// ContinueOnError error handling policy. -func (f *FlagSet) Init(name string, errorHandling ErrorHandling) { - f.name = name - f.errorHandling = errorHandling - f.argsLenAtDash = -1 -} diff --git a/vendor/github.com/spf13/pflag/flag_test.go b/vendor/github.com/spf13/pflag/flag_test.go deleted file mode 100644 index c3def0fd..00000000 --- a/vendor/github.com/spf13/pflag/flag_test.go +++ /dev/null @@ -1,1085 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "reflect" - "sort" - "strconv" - "strings" - "testing" - "time" -) - -var ( - testBool = Bool("test_bool", false, "bool value") - testInt = Int("test_int", 0, "int value") - testInt64 = Int64("test_int64", 0, "int64 value") - testUint = Uint("test_uint", 0, "uint value") - testUint64 = Uint64("test_uint64", 0, "uint64 value") - testString = String("test_string", "0", "string value") - testFloat = Float64("test_float64", 0, "float64 value") - testDuration = Duration("test_duration", 0, "time.Duration value") - testOptionalInt = Int("test_optional_int", 0, "optional int value") - normalizeFlagNameInvocations = 0 -) - -func boolString(s string) string { - if s == "0" { - return "false" - } - return "true" -} - -func TestEverything(t *testing.T) { - m := make(map[string]*Flag) - desired := "0" - visitor := func(f *Flag) { - if len(f.Name) > 5 && f.Name[0:5] == "test_" { - m[f.Name] = f - ok := false - switch { - case f.Value.String() == desired: - ok = true - case f.Name == "test_bool" && f.Value.String() == boolString(desired): - ok = true - case f.Name == "test_duration" && f.Value.String() == desired+"s": - ok = true - } - if !ok { - t.Error("Visit: bad value", f.Value.String(), "for", f.Name) - } - } - } - VisitAll(visitor) - if len(m) != 9 { - t.Error("VisitAll misses some flags") - for k, v := range m { - t.Log(k, *v) - } - } - m = make(map[string]*Flag) - Visit(visitor) - if len(m) != 0 { - t.Errorf("Visit sees unset flags") - for k, v := range m { - t.Log(k, *v) - } - } - // Now set all flags - Set("test_bool", "true") - Set("test_int", "1") - Set("test_int64", "1") - Set("test_uint", "1") - Set("test_uint64", "1") - Set("test_string", "1") - Set("test_float64", "1") - Set("test_duration", "1s") - Set("test_optional_int", "1") - desired = "1" - Visit(visitor) - if len(m) != 9 { - t.Error("Visit fails after set") - for k, v := range m { - t.Log(k, *v) - } - } - // Now test they're visited in sort order. - var flagNames []string - Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) }) - if !sort.StringsAreSorted(flagNames) { - t.Errorf("flag names not sorted: %v", flagNames) - } -} - -func TestUsage(t *testing.T) { - called := false - ResetForTesting(func() { called = true }) - if GetCommandLine().Parse([]string{"--x"}) == nil { - t.Error("parse did not fail for unknown flag") - } - if !called { - t.Error("did not call Usage for unknown flag") - } -} - -func TestAddFlagSet(t *testing.T) { - oldSet := NewFlagSet("old", ContinueOnError) - newSet := NewFlagSet("new", ContinueOnError) - - oldSet.String("flag1", "flag1", "flag1") - oldSet.String("flag2", "flag2", "flag2") - - newSet.String("flag2", "flag2", "flag2") - newSet.String("flag3", "flag3", "flag3") - - oldSet.AddFlagSet(newSet) - - if len(oldSet.formal) != 3 { - t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet) - } -} - -func TestAnnotation(t *testing.T) { - f := NewFlagSet("shorthand", ContinueOnError) - - if err := f.SetAnnotation("missing-flag", "key", nil); err == nil { - t.Errorf("Expected error setting annotation on non-existent flag") - } - - f.StringP("stringa", "a", "", "string value") - if err := f.SetAnnotation("stringa", "key", nil); err != nil { - t.Errorf("Unexpected error setting new nil annotation: %v", err) - } - if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil { - t.Errorf("Unexpected annotation: %v", annotation) - } - - f.StringP("stringb", "b", "", "string2 value") - if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil { - t.Errorf("Unexpected error setting new annotation: %v", err) - } - if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) { - t.Errorf("Unexpected annotation: %v", annotation) - } - - if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil { - t.Errorf("Unexpected error updating annotation: %v", err) - } - if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) { - t.Errorf("Unexpected annotation: %v", annotation) - } -} - -func testParse(f *FlagSet, t *testing.T) { - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - boolFlag := f.Bool("bool", false, "bool value") - bool2Flag := f.Bool("bool2", false, "bool2 value") - bool3Flag := f.Bool("bool3", false, "bool3 value") - intFlag := f.Int("int", 0, "int value") - int8Flag := f.Int8("int8", 0, "int value") - int32Flag := f.Int32("int32", 0, "int value") - int64Flag := f.Int64("int64", 0, "int64 value") - uintFlag := f.Uint("uint", 0, "uint value") - uint8Flag := f.Uint8("uint8", 0, "uint value") - uint16Flag := f.Uint16("uint16", 0, "uint value") - uint32Flag := f.Uint32("uint32", 0, "uint value") - uint64Flag := f.Uint64("uint64", 0, "uint64 value") - stringFlag := f.String("string", "0", "string value") - float32Flag := f.Float32("float32", 0, "float32 value") - float64Flag := f.Float64("float64", 0, "float64 value") - ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value") - maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value") - durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value") - optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value") - f.Lookup("optional-int-no-value").NoOptDefVal = "9" - optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value") - f.Lookup("optional-int-no-value").NoOptDefVal = "9" - extra := "one-extra-argument" - args := []string{ - "--bool", - "--bool2=true", - "--bool3=false", - "--int=22", - "--int8=-8", - "--int32=-32", - "--int64=0x23", - "--uint", "24", - "--uint8=8", - "--uint16=16", - "--uint32=32", - "--uint64=25", - "--string=hello", - "--float32=-172e12", - "--float64=2718e28", - "--ip=10.11.12.13", - "--mask=255.255.255.0", - "--duration=2m", - "--optional-int-no-value", - "--optional-int-with-value=42", - extra, - } - if err := f.Parse(args); err != nil { - t.Fatal(err) - } - if !f.Parsed() { - t.Error("f.Parse() = false after Parse") - } - if *boolFlag != true { - t.Error("bool flag should be true, is ", *boolFlag) - } - if v, err := f.GetBool("bool"); err != nil || v != *boolFlag { - t.Error("GetBool does not work.") - } - if *bool2Flag != true { - t.Error("bool2 flag should be true, is ", *bool2Flag) - } - if *bool3Flag != false { - t.Error("bool3 flag should be false, is ", *bool2Flag) - } - if *intFlag != 22 { - t.Error("int flag should be 22, is ", *intFlag) - } - if v, err := f.GetInt("int"); err != nil || v != *intFlag { - t.Error("GetInt does not work.") - } - if *int8Flag != -8 { - t.Error("int8 flag should be 0x23, is ", *int8Flag) - } - if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag { - t.Error("GetInt8 does not work.") - } - if *int32Flag != -32 { - t.Error("int32 flag should be 0x23, is ", *int32Flag) - } - if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag { - t.Error("GetInt32 does not work.") - } - if *int64Flag != 0x23 { - t.Error("int64 flag should be 0x23, is ", *int64Flag) - } - if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag { - t.Error("GetInt64 does not work.") - } - if *uintFlag != 24 { - t.Error("uint flag should be 24, is ", *uintFlag) - } - if v, err := f.GetUint("uint"); err != nil || v != *uintFlag { - t.Error("GetUint does not work.") - } - if *uint8Flag != 8 { - t.Error("uint8 flag should be 8, is ", *uint8Flag) - } - if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag { - t.Error("GetUint8 does not work.") - } - if *uint16Flag != 16 { - t.Error("uint16 flag should be 16, is ", *uint16Flag) - } - if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag { - t.Error("GetUint16 does not work.") - } - if *uint32Flag != 32 { - t.Error("uint32 flag should be 32, is ", *uint32Flag) - } - if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag { - t.Error("GetUint32 does not work.") - } - if *uint64Flag != 25 { - t.Error("uint64 flag should be 25, is ", *uint64Flag) - } - if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag { - t.Error("GetUint64 does not work.") - } - if *stringFlag != "hello" { - t.Error("string flag should be `hello`, is ", *stringFlag) - } - if v, err := f.GetString("string"); err != nil || v != *stringFlag { - t.Error("GetString does not work.") - } - if *float32Flag != -172e12 { - t.Error("float32 flag should be -172e12, is ", *float32Flag) - } - if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag { - t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag) - } - if *float64Flag != 2718e28 { - t.Error("float64 flag should be 2718e28, is ", *float64Flag) - } - if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag { - t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag) - } - if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) { - t.Error("ip flag should be 10.11.12.13, is ", *ipFlag) - } - if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) { - t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag) - } - if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() { - t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String()) - } - if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() { - t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err) - } - if *durationFlag != 2*time.Minute { - t.Error("duration flag should be 2m, is ", *durationFlag) - } - if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag { - t.Error("GetDuration does not work.") - } - if _, err := f.GetInt("duration"); err == nil { - t.Error("GetInt parsed a time.Duration?!?!") - } - if *optionalIntNoValueFlag != 9 { - t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag) - } - if *optionalIntWithValueFlag != 42 { - t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag) - } - if len(f.Args()) != 1 { - t.Error("expected one argument, got", len(f.Args())) - } else if f.Args()[0] != extra { - t.Errorf("expected argument %q got %q", extra, f.Args()[0]) - } -} - -func testParseAll(f *FlagSet, t *testing.T) { - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - f.BoolP("boola", "a", false, "bool value") - f.BoolP("boolb", "b", false, "bool2 value") - f.BoolP("boolc", "c", false, "bool3 value") - f.BoolP("boold", "d", false, "bool4 value") - f.StringP("stringa", "s", "0", "string value") - f.StringP("stringz", "z", "0", "string value") - f.StringP("stringx", "x", "0", "string value") - f.StringP("stringy", "y", "0", "string value") - f.Lookup("stringx").NoOptDefVal = "1" - args := []string{ - "-ab", - "-cs=xx", - "--stringz=something", - "-d=true", - "-x", - "-y", - "ee", - } - want := []string{ - "boola", "true", - "boolb", "true", - "boolc", "true", - "stringa", "xx", - "stringz", "something", - "boold", "true", - "stringx", "1", - "stringy", "ee", - } - got := []string{} - store := func(flag *Flag, value string) error { - got = append(got, flag.Name) - if len(value) > 0 { - got = append(got, value) - } - return nil - } - if err := f.ParseAll(args, store); err != nil { - t.Errorf("expected no error, got %s", err) - } - if !f.Parsed() { - t.Errorf("f.Parse() = false after Parse") - } - if !reflect.DeepEqual(got, want) { - t.Errorf("f.ParseAll() fail to restore the args") - t.Errorf("Got: %v", got) - t.Errorf("Want: %v", want) - } -} - -func TestShorthand(t *testing.T) { - f := NewFlagSet("shorthand", ContinueOnError) - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - boolaFlag := f.BoolP("boola", "a", false, "bool value") - boolbFlag := f.BoolP("boolb", "b", false, "bool2 value") - boolcFlag := f.BoolP("boolc", "c", false, "bool3 value") - booldFlag := f.BoolP("boold", "d", false, "bool4 value") - stringaFlag := f.StringP("stringa", "s", "0", "string value") - stringzFlag := f.StringP("stringz", "z", "0", "string value") - extra := "interspersed-argument" - notaflag := "--i-look-like-a-flag" - args := []string{ - "-ab", - extra, - "-cs", - "hello", - "-z=something", - "-d=true", - "--", - notaflag, - } - f.SetOutput(ioutil.Discard) - if err := f.Parse(args); err != nil { - t.Error("expected no error, got ", err) - } - if !f.Parsed() { - t.Error("f.Parse() = false after Parse") - } - if *boolaFlag != true { - t.Error("boola flag should be true, is ", *boolaFlag) - } - if *boolbFlag != true { - t.Error("boolb flag should be true, is ", *boolbFlag) - } - if *boolcFlag != true { - t.Error("boolc flag should be true, is ", *boolcFlag) - } - if *booldFlag != true { - t.Error("boold flag should be true, is ", *booldFlag) - } - if *stringaFlag != "hello" { - t.Error("stringa flag should be `hello`, is ", *stringaFlag) - } - if *stringzFlag != "something" { - t.Error("stringz flag should be `something`, is ", *stringzFlag) - } - if len(f.Args()) != 2 { - t.Error("expected one argument, got", len(f.Args())) - } else if f.Args()[0] != extra { - t.Errorf("expected argument %q got %q", extra, f.Args()[0]) - } else if f.Args()[1] != notaflag { - t.Errorf("expected argument %q got %q", notaflag, f.Args()[1]) - } - if f.ArgsLenAtDash() != 1 { - t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1) - } -} - -func TestShorthandLookup(t *testing.T) { - f := NewFlagSet("shorthand", ContinueOnError) - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - f.BoolP("boola", "a", false, "bool value") - f.BoolP("boolb", "b", false, "bool2 value") - args := []string{ - "-ab", - } - f.SetOutput(ioutil.Discard) - if err := f.Parse(args); err != nil { - t.Error("expected no error, got ", err) - } - if !f.Parsed() { - t.Error("f.Parse() = false after Parse") - } - flag := f.ShorthandLookup("a") - if flag == nil { - t.Errorf("f.ShorthandLookup(\"a\") returned nil") - } - if flag.Name != "boola" { - t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name) - } - flag = f.ShorthandLookup("") - if flag != nil { - t.Errorf("f.ShorthandLookup(\"\") did not return nil") - } - defer func() { - recover() - }() - flag = f.ShorthandLookup("ab") - // should NEVER get here. lookup should panic. defer'd func should recover it. - t.Errorf("f.ShorthandLookup(\"ab\") did not panic") -} - -func TestParse(t *testing.T) { - ResetForTesting(func() { t.Error("bad parse") }) - testParse(GetCommandLine(), t) -} - -func TestParseAll(t *testing.T) { - ResetForTesting(func() { t.Error("bad parse") }) - testParseAll(GetCommandLine(), t) -} - -func TestFlagSetParse(t *testing.T) { - testParse(NewFlagSet("test", ContinueOnError), t) -} - -func TestChangedHelper(t *testing.T) { - f := NewFlagSet("changedtest", ContinueOnError) - f.Bool("changed", false, "changed bool") - f.Bool("settrue", true, "true to true") - f.Bool("setfalse", false, "false to false") - f.Bool("unchanged", false, "unchanged bool") - - args := []string{"--changed", "--settrue", "--setfalse=false"} - if err := f.Parse(args); err != nil { - t.Error("f.Parse() = false after Parse") - } - if !f.Changed("changed") { - t.Errorf("--changed wasn't changed!") - } - if !f.Changed("settrue") { - t.Errorf("--settrue wasn't changed!") - } - if !f.Changed("setfalse") { - t.Errorf("--setfalse wasn't changed!") - } - if f.Changed("unchanged") { - t.Errorf("--unchanged was changed!") - } - if f.Changed("invalid") { - t.Errorf("--invalid was changed!") - } - if f.ArgsLenAtDash() != -1 { - t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash()) - } -} - -func replaceSeparators(name string, from []string, to string) string { - result := name - for _, sep := range from { - result = strings.Replace(result, sep, to, -1) - } - // Type convert to indicate normalization has been done. - return result -} - -func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName { - seps := []string{"-", "_"} - name = replaceSeparators(name, seps, ".") - normalizeFlagNameInvocations++ - - return NormalizedName(name) -} - -func testWordSepNormalizedNames(args []string, t *testing.T) { - f := NewFlagSet("normalized", ContinueOnError) - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - withDashFlag := f.Bool("with-dash-flag", false, "bool value") - // Set this after some flags have been added and before others. - f.SetNormalizeFunc(wordSepNormalizeFunc) - withUnderFlag := f.Bool("with_under_flag", false, "bool value") - withBothFlag := f.Bool("with-both_flag", false, "bool value") - if err := f.Parse(args); err != nil { - t.Fatal(err) - } - if !f.Parsed() { - t.Error("f.Parse() = false after Parse") - } - if *withDashFlag != true { - t.Error("withDashFlag flag should be true, is ", *withDashFlag) - } - if *withUnderFlag != true { - t.Error("withUnderFlag flag should be true, is ", *withUnderFlag) - } - if *withBothFlag != true { - t.Error("withBothFlag flag should be true, is ", *withBothFlag) - } -} - -func TestWordSepNormalizedNames(t *testing.T) { - args := []string{ - "--with-dash-flag", - "--with-under-flag", - "--with-both-flag", - } - testWordSepNormalizedNames(args, t) - - args = []string{ - "--with_dash_flag", - "--with_under_flag", - "--with_both_flag", - } - testWordSepNormalizedNames(args, t) - - args = []string{ - "--with-dash_flag", - "--with-under_flag", - "--with-both_flag", - } - testWordSepNormalizedNames(args, t) -} - -func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName { - seps := []string{"-", "_"} - - oldName := replaceSeparators("old-valid_flag", seps, ".") - newName := replaceSeparators("valid-flag", seps, ".") - - name = replaceSeparators(name, seps, ".") - switch name { - case oldName: - name = newName - break - } - - return NormalizedName(name) -} - -func TestCustomNormalizedNames(t *testing.T) { - f := NewFlagSet("normalized", ContinueOnError) - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - - validFlag := f.Bool("valid-flag", false, "bool value") - f.SetNormalizeFunc(aliasAndWordSepFlagNames) - someOtherFlag := f.Bool("some-other-flag", false, "bool value") - - args := []string{"--old_valid_flag", "--some-other_flag"} - if err := f.Parse(args); err != nil { - t.Fatal(err) - } - - if *validFlag != true { - t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag) - } - if *someOtherFlag != true { - t.Error("someOtherFlag should be true, is ", *someOtherFlag) - } -} - -// Every flag we add, the name (displayed also in usage) should normalized -func TestNormalizationFuncShouldChangeFlagName(t *testing.T) { - // Test normalization after addition - f := NewFlagSet("normalized", ContinueOnError) - - f.Bool("valid_flag", false, "bool value") - if f.Lookup("valid_flag").Name != "valid_flag" { - t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name) - } - - f.SetNormalizeFunc(wordSepNormalizeFunc) - if f.Lookup("valid_flag").Name != "valid.flag" { - t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name) - } - - // Test normalization before addition - f = NewFlagSet("normalized", ContinueOnError) - f.SetNormalizeFunc(wordSepNormalizeFunc) - - f.Bool("valid_flag", false, "bool value") - if f.Lookup("valid_flag").Name != "valid.flag" { - t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name) - } -} - -// Declare a user-defined flag type. -type flagVar []string - -func (f *flagVar) String() string { - return fmt.Sprint([]string(*f)) -} - -func (f *flagVar) Set(value string) error { - *f = append(*f, value) - return nil -} - -func (f *flagVar) Type() string { - return "flagVar" -} - -func TestUserDefined(t *testing.T) { - var flags FlagSet - flags.Init("test", ContinueOnError) - var v flagVar - flags.VarP(&v, "v", "v", "usage") - if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil { - t.Error(err) - } - if len(v) != 3 { - t.Fatal("expected 3 args; got ", len(v)) - } - expect := "[1 2 3]" - if v.String() != expect { - t.Errorf("expected value %q got %q", expect, v.String()) - } -} - -func TestSetOutput(t *testing.T) { - var flags FlagSet - var buf bytes.Buffer - flags.SetOutput(&buf) - flags.Init("test", ContinueOnError) - flags.Parse([]string{"--unknown"}) - if out := buf.String(); !strings.Contains(out, "--unknown") { - t.Logf("expected output mentioning unknown; got %q", out) - } -} - -// This tests that one can reset the flags. This still works but not well, and is -// superseded by FlagSet. -func TestChangingArgs(t *testing.T) { - ResetForTesting(func() { t.Fatal("bad parse") }) - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - os.Args = []string{"cmd", "--before", "subcmd"} - before := Bool("before", false, "") - if err := GetCommandLine().Parse(os.Args[1:]); err != nil { - t.Fatal(err) - } - cmd := Arg(0) - os.Args = []string{"subcmd", "--after", "args"} - after := Bool("after", false, "") - Parse() - args := Args() - - if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" { - t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args) - } -} - -// Test that -help invokes the usage message and returns ErrHelp. -func TestHelp(t *testing.T) { - var helpCalled = false - fs := NewFlagSet("help test", ContinueOnError) - fs.Usage = func() { helpCalled = true } - var flag bool - fs.BoolVar(&flag, "flag", false, "regular flag") - // Regular flag invocation should work - err := fs.Parse([]string{"--flag=true"}) - if err != nil { - t.Fatal("expected no error; got ", err) - } - if !flag { - t.Error("flag was not set by --flag") - } - if helpCalled { - t.Error("help called for regular flag") - helpCalled = false // reset for next test - } - // Help flag should work as expected. - err = fs.Parse([]string{"--help"}) - if err == nil { - t.Fatal("error expected") - } - if err != ErrHelp { - t.Fatal("expected ErrHelp; got ", err) - } - if !helpCalled { - t.Fatal("help was not called") - } - // If we define a help flag, that should override. - var help bool - fs.BoolVar(&help, "help", false, "help flag") - helpCalled = false - err = fs.Parse([]string{"--help"}) - if err != nil { - t.Fatal("expected no error for defined --help; got ", err) - } - if helpCalled { - t.Fatal("help was called; should not have been for defined help flag") - } -} - -func TestNoInterspersed(t *testing.T) { - f := NewFlagSet("test", ContinueOnError) - f.SetInterspersed(false) - f.Bool("true", true, "always true") - f.Bool("false", false, "always false") - err := f.Parse([]string{"--true", "break", "--false"}) - if err != nil { - t.Fatal("expected no error; got ", err) - } - args := f.Args() - if len(args) != 2 || args[0] != "break" || args[1] != "--false" { - t.Fatal("expected interspersed options/non-options to fail") - } -} - -func TestTermination(t *testing.T) { - f := NewFlagSet("termination", ContinueOnError) - boolFlag := f.BoolP("bool", "l", false, "bool value") - if f.Parsed() { - t.Error("f.Parse() = true before Parse") - } - arg1 := "ls" - arg2 := "-l" - args := []string{ - "--", - arg1, - arg2, - } - f.SetOutput(ioutil.Discard) - if err := f.Parse(args); err != nil { - t.Fatal("expected no error; got ", err) - } - if !f.Parsed() { - t.Error("f.Parse() = false after Parse") - } - if *boolFlag { - t.Error("expected boolFlag=false, got true") - } - if len(f.Args()) != 2 { - t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args()) - } - if f.Args()[0] != arg1 { - t.Errorf("expected argument %q got %q", arg1, f.Args()[0]) - } - if f.Args()[1] != arg2 { - t.Errorf("expected argument %q got %q", arg2, f.Args()[1]) - } - if f.ArgsLenAtDash() != 0 { - t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash()) - } -} - -func TestDeprecatedFlagInDocs(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - f.Bool("badflag", true, "always true") - f.MarkDeprecated("badflag", "use --good-flag instead") - - out := new(bytes.Buffer) - f.SetOutput(out) - f.PrintDefaults() - - if strings.Contains(out.String(), "badflag") { - t.Errorf("found deprecated flag in usage!") - } -} - -func TestDeprecatedFlagShorthandInDocs(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - name := "noshorthandflag" - f.BoolP(name, "n", true, "always true") - f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name)) - - out := new(bytes.Buffer) - f.SetOutput(out) - f.PrintDefaults() - - if strings.Contains(out.String(), "-n,") { - t.Errorf("found deprecated flag shorthand in usage!") - } -} - -func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) { - oldStderr := os.Stderr - r, w, _ := os.Pipe() - os.Stderr = w - - err := f.Parse(args) - - outC := make(chan string) - // copy the output in a separate goroutine so printing can't block indefinitely - go func() { - var buf bytes.Buffer - io.Copy(&buf, r) - outC <- buf.String() - }() - - w.Close() - os.Stderr = oldStderr - out := <-outC - - return out, err -} - -func TestDeprecatedFlagUsage(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - f.Bool("badflag", true, "always true") - usageMsg := "use --good-flag instead" - f.MarkDeprecated("badflag", usageMsg) - - args := []string{"--badflag"} - out, err := parseReturnStderr(t, f, args) - if err != nil { - t.Fatal("expected no error; got ", err) - } - - if !strings.Contains(out, usageMsg) { - t.Errorf("usageMsg not printed when using a deprecated flag!") - } -} - -func TestDeprecatedFlagShorthandUsage(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - name := "noshorthandflag" - f.BoolP(name, "n", true, "always true") - usageMsg := fmt.Sprintf("use --%s instead", name) - f.MarkShorthandDeprecated(name, usageMsg) - - args := []string{"-n"} - out, err := parseReturnStderr(t, f, args) - if err != nil { - t.Fatal("expected no error; got ", err) - } - - if !strings.Contains(out, usageMsg) { - t.Errorf("usageMsg not printed when using a deprecated flag!") - } -} - -func TestDeprecatedFlagUsageNormalized(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - f.Bool("bad-double_flag", true, "always true") - f.SetNormalizeFunc(wordSepNormalizeFunc) - usageMsg := "use --good-flag instead" - f.MarkDeprecated("bad_double-flag", usageMsg) - - args := []string{"--bad_double_flag"} - out, err := parseReturnStderr(t, f, args) - if err != nil { - t.Fatal("expected no error; got ", err) - } - - if !strings.Contains(out, usageMsg) { - t.Errorf("usageMsg not printed when using a deprecated flag!") - } -} - -// Name normalization function should be called only once on flag addition -func TestMultipleNormalizeFlagNameInvocations(t *testing.T) { - normalizeFlagNameInvocations = 0 - - f := NewFlagSet("normalized", ContinueOnError) - f.SetNormalizeFunc(wordSepNormalizeFunc) - f.Bool("with_under_flag", false, "bool value") - - if normalizeFlagNameInvocations != 1 { - t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations) - } -} - -// -func TestHiddenFlagInUsage(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - f.Bool("secretFlag", true, "shhh") - f.MarkHidden("secretFlag") - - out := new(bytes.Buffer) - f.SetOutput(out) - f.PrintDefaults() - - if strings.Contains(out.String(), "secretFlag") { - t.Errorf("found hidden flag in usage!") - } -} - -// -func TestHiddenFlagUsage(t *testing.T) { - f := NewFlagSet("bob", ContinueOnError) - f.Bool("secretFlag", true, "shhh") - f.MarkHidden("secretFlag") - - args := []string{"--secretFlag"} - out, err := parseReturnStderr(t, f, args) - if err != nil { - t.Fatal("expected no error; got ", err) - } - - if strings.Contains(out, "shhh") { - t.Errorf("usage message printed when using a hidden flag!") - } -} - -const defaultOutput = ` --A for bootstrapping, allow 'any' type - --Alongflagname disable bounds checking - -C, --CCC a boolean defaulting to true (default true) - --D path set relative path for local imports - -E, --EEE num[=1234] a num with NoOptDefVal (default 4321) - --F number a non-zero number (default 2.7) - --G float a float that defaults to zero - --IP ip IP address with no default - --IPMask ipMask Netmask address with no default - --IPNet ipNet IP network with no default - --Ints intSlice int slice with zero default - --N int a non-zero int (default 27) - --ND1 string[="bar"] a string with NoOptDefVal (default "foo") - --ND2 num[=4321] a num with NoOptDefVal (default 1234) - --StringArray stringArray string array with zero default - --StringSlice stringSlice string slice with zero default - --Z int an int that defaults to zero - --custom custom custom Value implementation - --customP custom a VarP with default (default 10) - --maxT timeout set timeout for dial -` - -// Custom value that satisfies the Value interface. -type customValue int - -func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) } - -func (cv *customValue) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *cv = customValue(v) - return err -} - -func (cv *customValue) Type() string { return "custom" } - -func TestPrintDefaults(t *testing.T) { - fs := NewFlagSet("print defaults test", ContinueOnError) - var buf bytes.Buffer - fs.SetOutput(&buf) - fs.Bool("A", false, "for bootstrapping, allow 'any' type") - fs.Bool("Alongflagname", false, "disable bounds checking") - fs.BoolP("CCC", "C", true, "a boolean defaulting to true") - fs.String("D", "", "set relative `path` for local imports") - fs.Float64("F", 2.7, "a non-zero `number`") - fs.Float64("G", 0, "a float that defaults to zero") - fs.Int("N", 27, "a non-zero int") - fs.IntSlice("Ints", []int{}, "int slice with zero default") - fs.IP("IP", nil, "IP address with no default") - fs.IPMask("IPMask", nil, "Netmask address with no default") - fs.IPNet("IPNet", net.IPNet{}, "IP network with no default") - fs.Int("Z", 0, "an int that defaults to zero") - fs.Duration("maxT", 0, "set `timeout` for dial") - fs.String("ND1", "foo", "a string with NoOptDefVal") - fs.Lookup("ND1").NoOptDefVal = "bar" - fs.Int("ND2", 1234, "a `num` with NoOptDefVal") - fs.Lookup("ND2").NoOptDefVal = "4321" - fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal") - fs.ShorthandLookup("E").NoOptDefVal = "1234" - fs.StringSlice("StringSlice", []string{}, "string slice with zero default") - fs.StringArray("StringArray", []string{}, "string array with zero default") - - var cv customValue - fs.Var(&cv, "custom", "custom Value implementation") - - cv2 := customValue(10) - fs.VarP(&cv2, "customP", "", "a VarP with default") - - fs.PrintDefaults() - got := buf.String() - if got != defaultOutput { - fmt.Println("\n" + got) - fmt.Println("\n" + defaultOutput) - t.Errorf("got %q want %q\n", got, defaultOutput) - } -} - -func TestVisitAllFlagOrder(t *testing.T) { - fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError) - fs.SortFlags = false - // https://github.com/spf13/pflag/issues/120 - fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName { - return NormalizedName(name) - }) - - names := []string{"C", "B", "A", "D"} - for _, name := range names { - fs.Bool(name, false, "") - } - - i := 0 - fs.VisitAll(func(f *Flag) { - if names[i] != f.Name { - t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) - } - i++ - }) -} - -func TestVisitFlagOrder(t *testing.T) { - fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError) - fs.SortFlags = false - names := []string{"C", "B", "A", "D"} - for _, name := range names { - fs.Bool(name, false, "") - fs.Set(name, "true") - } - - i := 0 - fs.Visit(func(f *Flag) { - if names[i] != f.Name { - t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name) - } - i++ - }) -} diff --git a/vendor/github.com/spf13/pflag/float32.go b/vendor/github.com/spf13/pflag/float32.go deleted file mode 100644 index a243f81f..00000000 --- a/vendor/github.com/spf13/pflag/float32.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- float32 Value -type float32Value float32 - -func newFloat32Value(val float32, p *float32) *float32Value { - *p = val - return (*float32Value)(p) -} - -func (f *float32Value) Set(s string) error { - v, err := strconv.ParseFloat(s, 32) - *f = float32Value(v) - return err -} - -func (f *float32Value) Type() string { - return "float32" -} - -func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) } - -func float32Conv(sval string) (interface{}, error) { - v, err := strconv.ParseFloat(sval, 32) - if err != nil { - return 0, err - } - return float32(v), nil -} - -// GetFloat32 return the float32 value of a flag with the given name -func (f *FlagSet) GetFloat32(name string) (float32, error) { - val, err := f.getFlagType(name, "float32", float32Conv) - if err != nil { - return 0, err - } - return val.(float32), nil -} - -// Float32Var defines a float32 flag with specified name, default value, and usage string. -// The argument p points to a float32 variable in which to store the value of the flag. -func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) { - f.VarP(newFloat32Value(value, p), name, "", usage) -} - -// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { - f.VarP(newFloat32Value(value, p), name, shorthand, usage) -} - -// Float32Var defines a float32 flag with specified name, default value, and usage string. -// The argument p points to a float32 variable in which to store the value of the flag. -func Float32Var(p *float32, name string, value float32, usage string) { - CommandLine.VarP(newFloat32Value(value, p), name, "", usage) -} - -// Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. -func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { - CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) -} - -// Float32 defines a float32 flag with specified name, default value, and usage string. -// The return value is the address of a float32 variable that stores the value of the flag. -func (f *FlagSet) Float32(name string, value float32, usage string) *float32 { - p := new(float32) - f.Float32VarP(p, name, "", value, usage) - return p -} - -// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { - p := new(float32) - f.Float32VarP(p, name, shorthand, value, usage) - return p -} - -// Float32 defines a float32 flag with specified name, default value, and usage string. -// The return value is the address of a float32 variable that stores the value of the flag. -func Float32(name string, value float32, usage string) *float32 { - return CommandLine.Float32P(name, "", value, usage) -} - -// Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. -func Float32P(name, shorthand string, value float32, usage string) *float32 { - return CommandLine.Float32P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/float64.go b/vendor/github.com/spf13/pflag/float64.go deleted file mode 100644 index 04b5492a..00000000 --- a/vendor/github.com/spf13/pflag/float64.go +++ /dev/null @@ -1,84 +0,0 @@ -package pflag - -import "strconv" - -// -- float64 Value -type float64Value float64 - -func newFloat64Value(val float64, p *float64) *float64Value { - *p = val - return (*float64Value)(p) -} - -func (f *float64Value) Set(s string) error { - v, err := strconv.ParseFloat(s, 64) - *f = float64Value(v) - return err -} - -func (f *float64Value) Type() string { - return "float64" -} - -func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } - -func float64Conv(sval string) (interface{}, error) { - return strconv.ParseFloat(sval, 64) -} - -// GetFloat64 return the float64 value of a flag with the given name -func (f *FlagSet) GetFloat64(name string) (float64, error) { - val, err := f.getFlagType(name, "float64", float64Conv) - if err != nil { - return 0, err - } - return val.(float64), nil -} - -// Float64Var defines a float64 flag with specified name, default value, and usage string. -// The argument p points to a float64 variable in which to store the value of the flag. -func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { - f.VarP(newFloat64Value(value, p), name, "", usage) -} - -// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { - f.VarP(newFloat64Value(value, p), name, shorthand, usage) -} - -// Float64Var defines a float64 flag with specified name, default value, and usage string. -// The argument p points to a float64 variable in which to store the value of the flag. -func Float64Var(p *float64, name string, value float64, usage string) { - CommandLine.VarP(newFloat64Value(value, p), name, "", usage) -} - -// Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. -func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { - CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) -} - -// Float64 defines a float64 flag with specified name, default value, and usage string. -// The return value is the address of a float64 variable that stores the value of the flag. -func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { - p := new(float64) - f.Float64VarP(p, name, "", value, usage) - return p -} - -// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { - p := new(float64) - f.Float64VarP(p, name, shorthand, value, usage) - return p -} - -// Float64 defines a float64 flag with specified name, default value, and usage string. -// The return value is the address of a float64 variable that stores the value of the flag. -func Float64(name string, value float64, usage string) *float64 { - return CommandLine.Float64P(name, "", value, usage) -} - -// Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. -func Float64P(name, shorthand string, value float64, usage string) *float64 { - return CommandLine.Float64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/golangflag.go b/vendor/github.com/spf13/pflag/golangflag.go deleted file mode 100644 index c4f47ebe..00000000 --- a/vendor/github.com/spf13/pflag/golangflag.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - goflag "flag" - "reflect" - "strings" -) - -// flagValueWrapper implements pflag.Value around a flag.Value. The main -// difference here is the addition of the Type method that returns a string -// name of the type. As this is generally unknown, we approximate that with -// reflection. -type flagValueWrapper struct { - inner goflag.Value - flagType string -} - -// We are just copying the boolFlag interface out of goflag as that is what -// they use to decide if a flag should get "true" when no arg is given. -type goBoolFlag interface { - goflag.Value - IsBoolFlag() bool -} - -func wrapFlagValue(v goflag.Value) Value { - // If the flag.Value happens to also be a pflag.Value, just use it directly. - if pv, ok := v.(Value); ok { - return pv - } - - pv := &flagValueWrapper{ - inner: v, - } - - t := reflect.TypeOf(v) - if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { - t = t.Elem() - } - - pv.flagType = strings.TrimSuffix(t.Name(), "Value") - return pv -} - -func (v *flagValueWrapper) String() string { - return v.inner.String() -} - -func (v *flagValueWrapper) Set(s string) error { - return v.inner.Set(s) -} - -func (v *flagValueWrapper) Type() string { - return v.flagType -} - -// PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag -// If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei -// with both `-v` and `--v` in flags. If the golang flag was more than a single -// character (ex: `verbose`) it will only be accessible via `--verbose` -func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { - // Remember the default value as a string; it won't change. - flag := &Flag{ - Name: goflag.Name, - Usage: goflag.Usage, - Value: wrapFlagValue(goflag.Value), - // Looks like golang flags don't set DefValue correctly :-( - //DefValue: goflag.DefValue, - DefValue: goflag.Value.String(), - } - // Ex: if the golang flag was -v, allow both -v and --v to work - if len(flag.Name) == 1 { - flag.Shorthand = flag.Name - } - if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { - flag.NoOptDefVal = "true" - } - return flag -} - -// AddGoFlag will add the given *flag.Flag to the pflag.FlagSet -func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { - if f.Lookup(goflag.Name) != nil { - return - } - newflag := PFlagFromGoFlag(goflag) - f.AddFlag(newflag) -} - -// AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet -func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { - if newSet == nil { - return - } - newSet.VisitAll(func(goflag *goflag.Flag) { - f.AddGoFlag(goflag) - }) -} diff --git a/vendor/github.com/spf13/pflag/golangflag_test.go b/vendor/github.com/spf13/pflag/golangflag_test.go deleted file mode 100644 index 77e2d7d8..00000000 --- a/vendor/github.com/spf13/pflag/golangflag_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - goflag "flag" - "testing" -) - -func TestGoflags(t *testing.T) { - goflag.String("stringFlag", "stringFlag", "stringFlag") - goflag.Bool("boolFlag", false, "boolFlag") - - f := NewFlagSet("test", ContinueOnError) - - f.AddGoFlagSet(goflag.CommandLine) - err := f.Parse([]string{"--stringFlag=bob", "--boolFlag"}) - if err != nil { - t.Fatal("expected no error; get", err) - } - - getString, err := f.GetString("stringFlag") - if err != nil { - t.Fatal("expected no error; get", err) - } - if getString != "bob" { - t.Fatalf("expected getString=bob but got getString=%s", getString) - } - - getBool, err := f.GetBool("boolFlag") - if err != nil { - t.Fatal("expected no error; get", err) - } - if getBool != true { - t.Fatalf("expected getBool=true but got getBool=%v", getBool) - } -} diff --git a/vendor/github.com/spf13/pflag/int.go b/vendor/github.com/spf13/pflag/int.go deleted file mode 100644 index 1474b89d..00000000 --- a/vendor/github.com/spf13/pflag/int.go +++ /dev/null @@ -1,84 +0,0 @@ -package pflag - -import "strconv" - -// -- int Value -type intValue int - -func newIntValue(val int, p *int) *intValue { - *p = val - return (*intValue)(p) -} - -func (i *intValue) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = intValue(v) - return err -} - -func (i *intValue) Type() string { - return "int" -} - -func (i *intValue) String() string { return strconv.Itoa(int(*i)) } - -func intConv(sval string) (interface{}, error) { - return strconv.Atoi(sval) -} - -// GetInt return the int value of a flag with the given name -func (f *FlagSet) GetInt(name string) (int, error) { - val, err := f.getFlagType(name, "int", intConv) - if err != nil { - return 0, err - } - return val.(int), nil -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { - f.VarP(newIntValue(value, p), name, "", usage) -} - -// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { - f.VarP(newIntValue(value, p), name, shorthand, usage) -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func IntVar(p *int, name string, value int, usage string) { - CommandLine.VarP(newIntValue(value, p), name, "", usage) -} - -// IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. -func IntVarP(p *int, name, shorthand string, value int, usage string) { - CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func (f *FlagSet) Int(name string, value int, usage string) *int { - p := new(int) - f.IntVarP(p, name, "", value, usage) - return p -} - -// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { - p := new(int) - f.IntVarP(p, name, shorthand, value, usage) - return p -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func Int(name string, value int, usage string) *int { - return CommandLine.IntP(name, "", value, usage) -} - -// IntP is like Int, but accepts a shorthand letter that can be used after a single dash. -func IntP(name, shorthand string, value int, usage string) *int { - return CommandLine.IntP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int32.go b/vendor/github.com/spf13/pflag/int32.go deleted file mode 100644 index 9b95944f..00000000 --- a/vendor/github.com/spf13/pflag/int32.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- int32 Value -type int32Value int32 - -func newInt32Value(val int32, p *int32) *int32Value { - *p = val - return (*int32Value)(p) -} - -func (i *int32Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 32) - *i = int32Value(v) - return err -} - -func (i *int32Value) Type() string { - return "int32" -} - -func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int32Conv(sval string) (interface{}, error) { - v, err := strconv.ParseInt(sval, 0, 32) - if err != nil { - return 0, err - } - return int32(v), nil -} - -// GetInt32 return the int32 value of a flag with the given name -func (f *FlagSet) GetInt32(name string) (int32, error) { - val, err := f.getFlagType(name, "int32", int32Conv) - if err != nil { - return 0, err - } - return val.(int32), nil -} - -// Int32Var defines an int32 flag with specified name, default value, and usage string. -// The argument p points to an int32 variable in which to store the value of the flag. -func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { - f.VarP(newInt32Value(value, p), name, "", usage) -} - -// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { - f.VarP(newInt32Value(value, p), name, shorthand, usage) -} - -// Int32Var defines an int32 flag with specified name, default value, and usage string. -// The argument p points to an int32 variable in which to store the value of the flag. -func Int32Var(p *int32, name string, value int32, usage string) { - CommandLine.VarP(newInt32Value(value, p), name, "", usage) -} - -// Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. -func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { - CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) -} - -// Int32 defines an int32 flag with specified name, default value, and usage string. -// The return value is the address of an int32 variable that stores the value of the flag. -func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { - p := new(int32) - f.Int32VarP(p, name, "", value, usage) - return p -} - -// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { - p := new(int32) - f.Int32VarP(p, name, shorthand, value, usage) - return p -} - -// Int32 defines an int32 flag with specified name, default value, and usage string. -// The return value is the address of an int32 variable that stores the value of the flag. -func Int32(name string, value int32, usage string) *int32 { - return CommandLine.Int32P(name, "", value, usage) -} - -// Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. -func Int32P(name, shorthand string, value int32, usage string) *int32 { - return CommandLine.Int32P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int64.go b/vendor/github.com/spf13/pflag/int64.go deleted file mode 100644 index 0026d781..00000000 --- a/vendor/github.com/spf13/pflag/int64.go +++ /dev/null @@ -1,84 +0,0 @@ -package pflag - -import "strconv" - -// -- int64 Value -type int64Value int64 - -func newInt64Value(val int64, p *int64) *int64Value { - *p = val - return (*int64Value)(p) -} - -func (i *int64Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 64) - *i = int64Value(v) - return err -} - -func (i *int64Value) Type() string { - return "int64" -} - -func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int64Conv(sval string) (interface{}, error) { - return strconv.ParseInt(sval, 0, 64) -} - -// GetInt64 return the int64 value of a flag with the given name -func (f *FlagSet) GetInt64(name string) (int64, error) { - val, err := f.getFlagType(name, "int64", int64Conv) - if err != nil { - return 0, err - } - return val.(int64), nil -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { - f.VarP(newInt64Value(value, p), name, "", usage) -} - -// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { - f.VarP(newInt64Value(value, p), name, shorthand, usage) -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func Int64Var(p *int64, name string, value int64, usage string) { - CommandLine.VarP(newInt64Value(value, p), name, "", usage) -} - -// Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. -func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { - CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { - p := new(int64) - f.Int64VarP(p, name, "", value, usage) - return p -} - -// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { - p := new(int64) - f.Int64VarP(p, name, shorthand, value, usage) - return p -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func Int64(name string, value int64, usage string) *int64 { - return CommandLine.Int64P(name, "", value, usage) -} - -// Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. -func Int64P(name, shorthand string, value int64, usage string) *int64 { - return CommandLine.Int64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int8.go b/vendor/github.com/spf13/pflag/int8.go deleted file mode 100644 index 4da92228..00000000 --- a/vendor/github.com/spf13/pflag/int8.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- int8 Value -type int8Value int8 - -func newInt8Value(val int8, p *int8) *int8Value { - *p = val - return (*int8Value)(p) -} - -func (i *int8Value) Set(s string) error { - v, err := strconv.ParseInt(s, 0, 8) - *i = int8Value(v) - return err -} - -func (i *int8Value) Type() string { - return "int8" -} - -func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } - -func int8Conv(sval string) (interface{}, error) { - v, err := strconv.ParseInt(sval, 0, 8) - if err != nil { - return 0, err - } - return int8(v), nil -} - -// GetInt8 return the int8 value of a flag with the given name -func (f *FlagSet) GetInt8(name string) (int8, error) { - val, err := f.getFlagType(name, "int8", int8Conv) - if err != nil { - return 0, err - } - return val.(int8), nil -} - -// Int8Var defines an int8 flag with specified name, default value, and usage string. -// The argument p points to an int8 variable in which to store the value of the flag. -func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { - f.VarP(newInt8Value(value, p), name, "", usage) -} - -// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { - f.VarP(newInt8Value(value, p), name, shorthand, usage) -} - -// Int8Var defines an int8 flag with specified name, default value, and usage string. -// The argument p points to an int8 variable in which to store the value of the flag. -func Int8Var(p *int8, name string, value int8, usage string) { - CommandLine.VarP(newInt8Value(value, p), name, "", usage) -} - -// Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. -func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { - CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) -} - -// Int8 defines an int8 flag with specified name, default value, and usage string. -// The return value is the address of an int8 variable that stores the value of the flag. -func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { - p := new(int8) - f.Int8VarP(p, name, "", value, usage) - return p -} - -// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { - p := new(int8) - f.Int8VarP(p, name, shorthand, value, usage) - return p -} - -// Int8 defines an int8 flag with specified name, default value, and usage string. -// The return value is the address of an int8 variable that stores the value of the flag. -func Int8(name string, value int8, usage string) *int8 { - return CommandLine.Int8P(name, "", value, usage) -} - -// Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. -func Int8P(name, shorthand string, value int8, usage string) *int8 { - return CommandLine.Int8P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int_slice.go b/vendor/github.com/spf13/pflag/int_slice.go deleted file mode 100644 index 1e7c9edd..00000000 --- a/vendor/github.com/spf13/pflag/int_slice.go +++ /dev/null @@ -1,128 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- intSlice Value -type intSliceValue struct { - value *[]int - changed bool -} - -func newIntSliceValue(val []int, p *[]int) *intSliceValue { - isv := new(intSliceValue) - isv.value = p - *isv.value = val - return isv -} - -func (s *intSliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]int, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.Atoi(d) - if err != nil { - return err - } - - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *intSliceValue) Type() string { - return "intSlice" -} - -func (s *intSliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%d", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func intSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []int{}, nil - } - ss := strings.Split(val, ",") - out := make([]int, len(ss)) - for i, d := range ss { - var err error - out[i], err = strconv.Atoi(d) - if err != nil { - return nil, err - } - - } - return out, nil -} - -// GetIntSlice return the []int value of a flag with the given name -func (f *FlagSet) GetIntSlice(name string) ([]int, error) { - val, err := f.getFlagType(name, "intSlice", intSliceConv) - if err != nil { - return []int{}, err - } - return val.([]int), nil -} - -// IntSliceVar defines a intSlice flag with specified name, default value, and usage string. -// The argument p points to a []int variable in which to store the value of the flag. -func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) { - f.VarP(newIntSliceValue(value, p), name, "", usage) -} - -// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { - f.VarP(newIntSliceValue(value, p), name, shorthand, usage) -} - -// IntSliceVar defines a int[] flag with specified name, default value, and usage string. -// The argument p points to a int[] variable in which to store the value of the flag. -func IntSliceVar(p *[]int, name string, value []int, usage string) { - CommandLine.VarP(newIntSliceValue(value, p), name, "", usage) -} - -// IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. -func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { - CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage) -} - -// IntSlice defines a []int flag with specified name, default value, and usage string. -// The return value is the address of a []int variable that stores the value of the flag. -func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int { - p := []int{} - f.IntSliceVarP(&p, name, "", value, usage) - return &p -} - -// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int { - p := []int{} - f.IntSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// IntSlice defines a []int flag with specified name, default value, and usage string. -// The return value is the address of a []int variable that stores the value of the flag. -func IntSlice(name string, value []int, usage string) *[]int { - return CommandLine.IntSliceP(name, "", value, usage) -} - -// IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. -func IntSliceP(name, shorthand string, value []int, usage string) *[]int { - return CommandLine.IntSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/int_slice_test.go b/vendor/github.com/spf13/pflag/int_slice_test.go deleted file mode 100644 index 745aecb9..00000000 --- a/vendor/github.com/spf13/pflag/int_slice_test.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - "fmt" - "strconv" - "strings" - "testing" -) - -func setUpISFlagSet(isp *[]int) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.IntSliceVar(isp, "is", []int{}, "Command separated list!") - return f -} - -func setUpISFlagSetWithDefault(isp *[]int) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.IntSliceVar(isp, "is", []int{0, 1}, "Command separated list!") - return f -} - -func TestEmptyIS(t *testing.T) { - var is []int - f := setUpISFlagSet(&is) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getIS, err := f.GetIntSlice("is") - if err != nil { - t.Fatal("got an error from GetIntSlice():", err) - } - if len(getIS) != 0 { - t.Fatalf("got is %v with len=%d but expected length=0", getIS, len(getIS)) - } -} - -func TestIS(t *testing.T) { - var is []int - f := setUpISFlagSet(&is) - - vals := []string{"1", "2", "4", "3"} - arg := fmt.Sprintf("--is=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range is { - d, err := strconv.Atoi(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if d != v { - t.Fatalf("expected is[%d] to be %s but got: %d", i, vals[i], v) - } - } - getIS, err := f.GetIntSlice("is") - if err != nil { - t.Fatalf("got error: %v", err) - } - for i, v := range getIS { - d, err := strconv.Atoi(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if d != v { - t.Fatalf("expected is[%d] to be %s but got: %d from GetIntSlice", i, vals[i], v) - } - } -} - -func TestISDefault(t *testing.T) { - var is []int - f := setUpISFlagSetWithDefault(&is) - - vals := []string{"0", "1"} - - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range is { - d, err := strconv.Atoi(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if d != v { - t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v) - } - } - - getIS, err := f.GetIntSlice("is") - if err != nil { - t.Fatal("got an error from GetIntSlice():", err) - } - for i, v := range getIS { - d, err := strconv.Atoi(vals[i]) - if err != nil { - t.Fatal("got an error from GetIntSlice():", err) - } - if d != v { - t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v) - } - } -} - -func TestISWithDefault(t *testing.T) { - var is []int - f := setUpISFlagSetWithDefault(&is) - - vals := []string{"1", "2"} - arg := fmt.Sprintf("--is=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range is { - d, err := strconv.Atoi(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if d != v { - t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v) - } - } - - getIS, err := f.GetIntSlice("is") - if err != nil { - t.Fatal("got an error from GetIntSlice():", err) - } - for i, v := range getIS { - d, err := strconv.Atoi(vals[i]) - if err != nil { - t.Fatalf("got error: %v", err) - } - if d != v { - t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v) - } - } -} - -func TestISCalledTwice(t *testing.T) { - var is []int - f := setUpISFlagSet(&is) - - in := []string{"1,2", "3"} - expected := []int{1, 2, 3} - argfmt := "--is=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range is { - if expected[i] != v { - t.Fatalf("expected is[%d] to be %d but got: %d", i, expected[i], v) - } - } -} diff --git a/vendor/github.com/spf13/pflag/ip.go b/vendor/github.com/spf13/pflag/ip.go deleted file mode 100644 index 3d414ba6..00000000 --- a/vendor/github.com/spf13/pflag/ip.go +++ /dev/null @@ -1,94 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strings" -) - -// -- net.IP value -type ipValue net.IP - -func newIPValue(val net.IP, p *net.IP) *ipValue { - *p = val - return (*ipValue)(p) -} - -func (i *ipValue) String() string { return net.IP(*i).String() } -func (i *ipValue) Set(s string) error { - ip := net.ParseIP(strings.TrimSpace(s)) - if ip == nil { - return fmt.Errorf("failed to parse IP: %q", s) - } - *i = ipValue(ip) - return nil -} - -func (i *ipValue) Type() string { - return "ip" -} - -func ipConv(sval string) (interface{}, error) { - ip := net.ParseIP(sval) - if ip != nil { - return ip, nil - } - return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) -} - -// GetIP return the net.IP value of a flag with the given name -func (f *FlagSet) GetIP(name string) (net.IP, error) { - val, err := f.getFlagType(name, "ip", ipConv) - if err != nil { - return nil, err - } - return val.(net.IP), nil -} - -// IPVar defines an net.IP flag with specified name, default value, and usage string. -// The argument p points to an net.IP variable in which to store the value of the flag. -func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { - f.VarP(newIPValue(value, p), name, "", usage) -} - -// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { - f.VarP(newIPValue(value, p), name, shorthand, usage) -} - -// IPVar defines an net.IP flag with specified name, default value, and usage string. -// The argument p points to an net.IP variable in which to store the value of the flag. -func IPVar(p *net.IP, name string, value net.IP, usage string) { - CommandLine.VarP(newIPValue(value, p), name, "", usage) -} - -// IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. -func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { - CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) -} - -// IP defines an net.IP flag with specified name, default value, and usage string. -// The return value is the address of an net.IP variable that stores the value of the flag. -func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { - p := new(net.IP) - f.IPVarP(p, name, "", value, usage) - return p -} - -// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { - p := new(net.IP) - f.IPVarP(p, name, shorthand, value, usage) - return p -} - -// IP defines an net.IP flag with specified name, default value, and usage string. -// The return value is the address of an net.IP variable that stores the value of the flag. -func IP(name string, value net.IP, usage string) *net.IP { - return CommandLine.IPP(name, "", value, usage) -} - -// IPP is like IP, but accepts a shorthand letter that can be used after a single dash. -func IPP(name, shorthand string, value net.IP, usage string) *net.IP { - return CommandLine.IPP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ip_slice.go b/vendor/github.com/spf13/pflag/ip_slice.go deleted file mode 100644 index 7dd196fe..00000000 --- a/vendor/github.com/spf13/pflag/ip_slice.go +++ /dev/null @@ -1,148 +0,0 @@ -package pflag - -import ( - "fmt" - "io" - "net" - "strings" -) - -// -- ipSlice Value -type ipSliceValue struct { - value *[]net.IP - changed bool -} - -func newIPSliceValue(val []net.IP, p *[]net.IP) *ipSliceValue { - ipsv := new(ipSliceValue) - ipsv.value = p - *ipsv.value = val - return ipsv -} - -// Set converts, and assigns, the comma-separated IP argument string representation as the []net.IP value of this flag. -// If Set is called on a flag that already has a []net.IP assigned, the newly converted values will be appended. -func (s *ipSliceValue) Set(val string) error { - - // remove all quote characters - rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") - - // read flag arguments with CSV parser - ipStrSlice, err := readAsCSV(rmQuote.Replace(val)) - if err != nil && err != io.EOF { - return err - } - - // parse ip values into slice - out := make([]net.IP, 0, len(ipStrSlice)) - for _, ipStr := range ipStrSlice { - ip := net.ParseIP(strings.TrimSpace(ipStr)) - if ip == nil { - return fmt.Errorf("invalid string being converted to IP address: %s", ipStr) - } - out = append(out, ip) - } - - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - - s.changed = true - - return nil -} - -// Type returns a string that uniquely represents this flag's type. -func (s *ipSliceValue) Type() string { - return "ipSlice" -} - -// String defines a "native" format for this net.IP slice flag value. -func (s *ipSliceValue) String() string { - - ipStrSlice := make([]string, len(*s.value)) - for i, ip := range *s.value { - ipStrSlice[i] = ip.String() - } - - out, _ := writeAsCSV(ipStrSlice) - - return "[" + out + "]" -} - -func ipSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Emtpy string would cause a slice with one (empty) entry - if len(val) == 0 { - return []net.IP{}, nil - } - ss := strings.Split(val, ",") - out := make([]net.IP, len(ss)) - for i, sval := range ss { - ip := net.ParseIP(strings.TrimSpace(sval)) - if ip == nil { - return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) - } - out[i] = ip - } - return out, nil -} - -// GetIPSlice returns the []net.IP value of a flag with the given name -func (f *FlagSet) GetIPSlice(name string) ([]net.IP, error) { - val, err := f.getFlagType(name, "ipSlice", ipSliceConv) - if err != nil { - return []net.IP{}, err - } - return val.([]net.IP), nil -} - -// IPSliceVar defines a ipSlice flag with specified name, default value, and usage string. -// The argument p points to a []net.IP variable in which to store the value of the flag. -func (f *FlagSet) IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { - f.VarP(newIPSliceValue(value, p), name, "", usage) -} - -// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { - f.VarP(newIPSliceValue(value, p), name, shorthand, usage) -} - -// IPSliceVar defines a []net.IP flag with specified name, default value, and usage string. -// The argument p points to a []net.IP variable in which to store the value of the flag. -func IPSliceVar(p *[]net.IP, name string, value []net.IP, usage string) { - CommandLine.VarP(newIPSliceValue(value, p), name, "", usage) -} - -// IPSliceVarP is like IPSliceVar, but accepts a shorthand letter that can be used after a single dash. -func IPSliceVarP(p *[]net.IP, name, shorthand string, value []net.IP, usage string) { - CommandLine.VarP(newIPSliceValue(value, p), name, shorthand, usage) -} - -// IPSlice defines a []net.IP flag with specified name, default value, and usage string. -// The return value is the address of a []net.IP variable that stores the value of that flag. -func (f *FlagSet) IPSlice(name string, value []net.IP, usage string) *[]net.IP { - p := []net.IP{} - f.IPSliceVarP(&p, name, "", value, usage) - return &p -} - -// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { - p := []net.IP{} - f.IPSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// IPSlice defines a []net.IP flag with specified name, default value, and usage string. -// The return value is the address of a []net.IP variable that stores the value of the flag. -func IPSlice(name string, value []net.IP, usage string) *[]net.IP { - return CommandLine.IPSliceP(name, "", value, usage) -} - -// IPSliceP is like IPSlice, but accepts a shorthand letter that can be used after a single dash. -func IPSliceP(name, shorthand string, value []net.IP, usage string) *[]net.IP { - return CommandLine.IPSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ip_slice_test.go b/vendor/github.com/spf13/pflag/ip_slice_test.go deleted file mode 100644 index b0c681c5..00000000 --- a/vendor/github.com/spf13/pflag/ip_slice_test.go +++ /dev/null @@ -1,222 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strings" - "testing" -) - -func setUpIPSFlagSet(ipsp *[]net.IP) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.IPSliceVar(ipsp, "ips", []net.IP{}, "Command separated list!") - return f -} - -func setUpIPSFlagSetWithDefault(ipsp *[]net.IP) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.IPSliceVar(ipsp, "ips", - []net.IP{ - net.ParseIP("192.168.1.1"), - net.ParseIP("0:0:0:0:0:0:0:1"), - }, - "Command separated list!") - return f -} - -func TestEmptyIP(t *testing.T) { - var ips []net.IP - f := setUpIPSFlagSet(&ips) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getIPS, err := f.GetIPSlice("ips") - if err != nil { - t.Fatal("got an error from GetIPSlice():", err) - } - if len(getIPS) != 0 { - t.Fatalf("got ips %v with len=%d but expected length=0", getIPS, len(getIPS)) - } -} - -func TestIPS(t *testing.T) { - var ips []net.IP - f := setUpIPSFlagSet(&ips) - - vals := []string{"192.168.1.1", "10.0.0.1", "0:0:0:0:0:0:0:2"} - arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ips { - if ip := net.ParseIP(vals[i]); ip == nil { - t.Fatalf("invalid string being converted to IP address: %s", vals[i]) - } else if !ip.Equal(v) { - t.Fatalf("expected ips[%d] to be %s but got: %s from GetIPSlice", i, vals[i], v) - } - } -} - -func TestIPSDefault(t *testing.T) { - var ips []net.IP - f := setUpIPSFlagSetWithDefault(&ips) - - vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"} - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ips { - if ip := net.ParseIP(vals[i]); ip == nil { - t.Fatalf("invalid string being converted to IP address: %s", vals[i]) - } else if !ip.Equal(v) { - t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) - } - } - - getIPS, err := f.GetIPSlice("ips") - if err != nil { - t.Fatal("got an error from GetIPSlice") - } - for i, v := range getIPS { - if ip := net.ParseIP(vals[i]); ip == nil { - t.Fatalf("invalid string being converted to IP address: %s", vals[i]) - } else if !ip.Equal(v) { - t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) - } - } -} - -func TestIPSWithDefault(t *testing.T) { - var ips []net.IP - f := setUpIPSFlagSetWithDefault(&ips) - - vals := []string{"192.168.1.1", "0:0:0:0:0:0:0:1"} - arg := fmt.Sprintf("--ips=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ips { - if ip := net.ParseIP(vals[i]); ip == nil { - t.Fatalf("invalid string being converted to IP address: %s", vals[i]) - } else if !ip.Equal(v) { - t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) - } - } - - getIPS, err := f.GetIPSlice("ips") - if err != nil { - t.Fatal("got an error from GetIPSlice") - } - for i, v := range getIPS { - if ip := net.ParseIP(vals[i]); ip == nil { - t.Fatalf("invalid string being converted to IP address: %s", vals[i]) - } else if !ip.Equal(v) { - t.Fatalf("expected ips[%d] to be %s but got: %s", i, vals[i], v) - } - } -} - -func TestIPSCalledTwice(t *testing.T) { - var ips []net.IP - f := setUpIPSFlagSet(&ips) - - in := []string{"192.168.1.2,0:0:0:0:0:0:0:1", "10.0.0.1"} - expected := []net.IP{net.ParseIP("192.168.1.2"), net.ParseIP("0:0:0:0:0:0:0:1"), net.ParseIP("10.0.0.1")} - argfmt := "ips=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ips { - if !expected[i].Equal(v) { - t.Fatalf("expected ips[%d] to be %s but got: %s", i, expected[i], v) - } - } -} - -func TestIPSBadQuoting(t *testing.T) { - - tests := []struct { - Want []net.IP - FlagArg []string - }{ - { - Want: []net.IP{ - net.ParseIP("a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568"), - net.ParseIP("203.107.49.208"), - net.ParseIP("14.57.204.90"), - }, - FlagArg: []string{ - "a4ab:61d:f03e:5d7d:fad7:d4c2:a1a5:568", - "203.107.49.208", - "14.57.204.90", - }, - }, - { - Want: []net.IP{ - net.ParseIP("204.228.73.195"), - net.ParseIP("86.141.15.94"), - }, - FlagArg: []string{ - "204.228.73.195", - "86.141.15.94", - }, - }, - { - Want: []net.IP{ - net.ParseIP("c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f"), - net.ParseIP("4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472"), - }, - FlagArg: []string{ - "c70c:db36:3001:890f:c6ea:3f9b:7a39:cc3f", - "4d17:1d6e:e699:bd7a:88c5:5e7e:ac6a:4472", - }, - }, - { - Want: []net.IP{ - net.ParseIP("5170:f971:cfac:7be3:512a:af37:952c:bc33"), - net.ParseIP("93.21.145.140"), - net.ParseIP("2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca"), - }, - FlagArg: []string{ - " 5170:f971:cfac:7be3:512a:af37:952c:bc33 , 93.21.145.140 ", - "2cac:61d3:c5ff:6caf:73e0:1b1a:c336:c1ca", - }, - }, - { - Want: []net.IP{ - net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), - net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), - net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), - net.ParseIP("2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"), - }, - FlagArg: []string{ - `"2e5e:66b2:6441:848:5b74:76ea:574c:3a7b, 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b,2e5e:66b2:6441:848:5b74:76ea:574c:3a7b "`, - " 2e5e:66b2:6441:848:5b74:76ea:574c:3a7b"}, - }, - } - - for i, test := range tests { - - var ips []net.IP - f := setUpIPSFlagSet(&ips) - - if err := f.Parse([]string{fmt.Sprintf("--ips=%s", strings.Join(test.FlagArg, ","))}); err != nil { - t.Fatalf("flag parsing failed with error: %s\nparsing:\t%#v\nwant:\t\t%s", - err, test.FlagArg, test.Want[i]) - } - - for j, b := range ips { - if !b.Equal(test.Want[j]) { - t.Fatalf("bad value parsed for test %d on net.IP %d:\nwant:\t%s\ngot:\t%s", i, j, test.Want[j], b) - } - } - } -} diff --git a/vendor/github.com/spf13/pflag/ip_test.go b/vendor/github.com/spf13/pflag/ip_test.go deleted file mode 100644 index 1fec50e4..00000000 --- a/vendor/github.com/spf13/pflag/ip_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "os" - "testing" -) - -func setUpIP(ip *net.IP) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.IPVar(ip, "address", net.ParseIP("0.0.0.0"), "IP Address") - return f -} - -func TestIP(t *testing.T) { - testCases := []struct { - input string - success bool - expected string - }{ - {"0.0.0.0", true, "0.0.0.0"}, - {" 0.0.0.0 ", true, "0.0.0.0"}, - {"1.2.3.4", true, "1.2.3.4"}, - {"127.0.0.1", true, "127.0.0.1"}, - {"255.255.255.255", true, "255.255.255.255"}, - {"", false, ""}, - {"0", false, ""}, - {"localhost", false, ""}, - {"0.0.0", false, ""}, - {"0.0.0.", false, ""}, - {"0.0.0.0.", false, ""}, - {"0.0.0.256", false, ""}, - {"0 . 0 . 0 . 0", false, ""}, - } - - devnull, _ := os.Open(os.DevNull) - os.Stderr = devnull - for i := range testCases { - var addr net.IP - f := setUpIP(&addr) - - tc := &testCases[i] - - arg := fmt.Sprintf("--address=%s", tc.input) - err := f.Parse([]string{arg}) - if err != nil && tc.success == true { - t.Errorf("expected success, got %q", err) - continue - } else if err == nil && tc.success == false { - t.Errorf("expected failure") - continue - } else if tc.success { - ip, err := f.GetIP("address") - if err != nil { - t.Errorf("Got error trying to fetch the IP flag: %v", err) - } - if ip.String() != tc.expected { - t.Errorf("expected %q, got %q", tc.expected, ip.String()) - } - } - } -} diff --git a/vendor/github.com/spf13/pflag/ipmask.go b/vendor/github.com/spf13/pflag/ipmask.go deleted file mode 100644 index 5bd44bd2..00000000 --- a/vendor/github.com/spf13/pflag/ipmask.go +++ /dev/null @@ -1,122 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strconv" -) - -// -- net.IPMask value -type ipMaskValue net.IPMask - -func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue { - *p = val - return (*ipMaskValue)(p) -} - -func (i *ipMaskValue) String() string { return net.IPMask(*i).String() } -func (i *ipMaskValue) Set(s string) error { - ip := ParseIPv4Mask(s) - if ip == nil { - return fmt.Errorf("failed to parse IP mask: %q", s) - } - *i = ipMaskValue(ip) - return nil -} - -func (i *ipMaskValue) Type() string { - return "ipMask" -} - -// ParseIPv4Mask written in IP form (e.g. 255.255.255.0). -// This function should really belong to the net package. -func ParseIPv4Mask(s string) net.IPMask { - mask := net.ParseIP(s) - if mask == nil { - if len(s) != 8 { - return nil - } - // net.IPMask.String() actually outputs things like ffffff00 - // so write a horrible parser for that as well :-( - m := []int{} - for i := 0; i < 4; i++ { - b := "0x" + s[2*i:2*i+2] - d, err := strconv.ParseInt(b, 0, 0) - if err != nil { - return nil - } - m = append(m, int(d)) - } - s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) - mask = net.ParseIP(s) - if mask == nil { - return nil - } - } - return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) -} - -func parseIPv4Mask(sval string) (interface{}, error) { - mask := ParseIPv4Mask(sval) - if mask == nil { - return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval) - } - return mask, nil -} - -// GetIPv4Mask return the net.IPv4Mask value of a flag with the given name -func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) { - val, err := f.getFlagType(name, "ipMask", parseIPv4Mask) - if err != nil { - return nil, err - } - return val.(net.IPMask), nil -} - -// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. -// The argument p points to an net.IPMask variable in which to store the value of the flag. -func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { - f.VarP(newIPMaskValue(value, p), name, "", usage) -} - -// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { - f.VarP(newIPMaskValue(value, p), name, shorthand, usage) -} - -// IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. -// The argument p points to an net.IPMask variable in which to store the value of the flag. -func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { - CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) -} - -// IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. -func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { - CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) -} - -// IPMask defines an net.IPMask flag with specified name, default value, and usage string. -// The return value is the address of an net.IPMask variable that stores the value of the flag. -func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask { - p := new(net.IPMask) - f.IPMaskVarP(p, name, "", value, usage) - return p -} - -// IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { - p := new(net.IPMask) - f.IPMaskVarP(p, name, shorthand, value, usage) - return p -} - -// IPMask defines an net.IPMask flag with specified name, default value, and usage string. -// The return value is the address of an net.IPMask variable that stores the value of the flag. -func IPMask(name string, value net.IPMask, usage string) *net.IPMask { - return CommandLine.IPMaskP(name, "", value, usage) -} - -// IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash. -func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { - return CommandLine.IPMaskP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ipnet.go b/vendor/github.com/spf13/pflag/ipnet.go deleted file mode 100644 index e2c1b8bc..00000000 --- a/vendor/github.com/spf13/pflag/ipnet.go +++ /dev/null @@ -1,98 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "strings" -) - -// IPNet adapts net.IPNet for use as a flag. -type ipNetValue net.IPNet - -func (ipnet ipNetValue) String() string { - n := net.IPNet(ipnet) - return n.String() -} - -func (ipnet *ipNetValue) Set(value string) error { - _, n, err := net.ParseCIDR(strings.TrimSpace(value)) - if err != nil { - return err - } - *ipnet = ipNetValue(*n) - return nil -} - -func (*ipNetValue) Type() string { - return "ipNet" -} - -func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue { - *p = val - return (*ipNetValue)(p) -} - -func ipNetConv(sval string) (interface{}, error) { - _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) - if err == nil { - return *n, nil - } - return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval) -} - -// GetIPNet return the net.IPNet value of a flag with the given name -func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) { - val, err := f.getFlagType(name, "ipNet", ipNetConv) - if err != nil { - return net.IPNet{}, err - } - return val.(net.IPNet), nil -} - -// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. -// The argument p points to an net.IPNet variable in which to store the value of the flag. -func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { - f.VarP(newIPNetValue(value, p), name, "", usage) -} - -// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { - f.VarP(newIPNetValue(value, p), name, shorthand, usage) -} - -// IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. -// The argument p points to an net.IPNet variable in which to store the value of the flag. -func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { - CommandLine.VarP(newIPNetValue(value, p), name, "", usage) -} - -// IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. -func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { - CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage) -} - -// IPNet defines an net.IPNet flag with specified name, default value, and usage string. -// The return value is the address of an net.IPNet variable that stores the value of the flag. -func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet { - p := new(net.IPNet) - f.IPNetVarP(p, name, "", value, usage) - return p -} - -// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { - p := new(net.IPNet) - f.IPNetVarP(p, name, shorthand, value, usage) - return p -} - -// IPNet defines an net.IPNet flag with specified name, default value, and usage string. -// The return value is the address of an net.IPNet variable that stores the value of the flag. -func IPNet(name string, value net.IPNet, usage string) *net.IPNet { - return CommandLine.IPNetP(name, "", value, usage) -} - -// IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. -func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { - return CommandLine.IPNetP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/ipnet_test.go b/vendor/github.com/spf13/pflag/ipnet_test.go deleted file mode 100644 index 335b6fa1..00000000 --- a/vendor/github.com/spf13/pflag/ipnet_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package pflag - -import ( - "fmt" - "net" - "os" - "testing" -) - -func setUpIPNet(ip *net.IPNet) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - _, def, _ := net.ParseCIDR("0.0.0.0/0") - f.IPNetVar(ip, "address", *def, "IP Address") - return f -} - -func TestIPNet(t *testing.T) { - testCases := []struct { - input string - success bool - expected string - }{ - {"0.0.0.0/0", true, "0.0.0.0/0"}, - {" 0.0.0.0/0 ", true, "0.0.0.0/0"}, - {"1.2.3.4/8", true, "1.0.0.0/8"}, - {"127.0.0.1/16", true, "127.0.0.0/16"}, - {"255.255.255.255/19", true, "255.255.224.0/19"}, - {"255.255.255.255/32", true, "255.255.255.255/32"}, - {"", false, ""}, - {"/0", false, ""}, - {"0", false, ""}, - {"0/0", false, ""}, - {"localhost/0", false, ""}, - {"0.0.0/4", false, ""}, - {"0.0.0./8", false, ""}, - {"0.0.0.0./12", false, ""}, - {"0.0.0.256/16", false, ""}, - {"0.0.0.0 /20", false, ""}, - {"0.0.0.0/ 24", false, ""}, - {"0 . 0 . 0 . 0 / 28", false, ""}, - {"0.0.0.0/33", false, ""}, - } - - devnull, _ := os.Open(os.DevNull) - os.Stderr = devnull - for i := range testCases { - var addr net.IPNet - f := setUpIPNet(&addr) - - tc := &testCases[i] - - arg := fmt.Sprintf("--address=%s", tc.input) - err := f.Parse([]string{arg}) - if err != nil && tc.success == true { - t.Errorf("expected success, got %q", err) - continue - } else if err == nil && tc.success == false { - t.Errorf("expected failure") - continue - } else if tc.success { - ip, err := f.GetIPNet("address") - if err != nil { - t.Errorf("Got error trying to fetch the IP flag: %v", err) - } - if ip.String() != tc.expected { - t.Errorf("expected %q, got %q", tc.expected, ip.String()) - } - } - } -} diff --git a/vendor/github.com/spf13/pflag/string.go b/vendor/github.com/spf13/pflag/string.go deleted file mode 100644 index 04e0a26f..00000000 --- a/vendor/github.com/spf13/pflag/string.go +++ /dev/null @@ -1,80 +0,0 @@ -package pflag - -// -- string Value -type stringValue string - -func newStringValue(val string, p *string) *stringValue { - *p = val - return (*stringValue)(p) -} - -func (s *stringValue) Set(val string) error { - *s = stringValue(val) - return nil -} -func (s *stringValue) Type() string { - return "string" -} - -func (s *stringValue) String() string { return string(*s) } - -func stringConv(sval string) (interface{}, error) { - return sval, nil -} - -// GetString return the string value of a flag with the given name -func (f *FlagSet) GetString(name string) (string, error) { - val, err := f.getFlagType(name, "string", stringConv) - if err != nil { - return "", err - } - return val.(string), nil -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { - f.VarP(newStringValue(value, p), name, "", usage) -} - -// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { - f.VarP(newStringValue(value, p), name, shorthand, usage) -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func StringVar(p *string, name string, value string, usage string) { - CommandLine.VarP(newStringValue(value, p), name, "", usage) -} - -// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. -func StringVarP(p *string, name, shorthand string, value string, usage string) { - CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func (f *FlagSet) String(name string, value string, usage string) *string { - p := new(string) - f.StringVarP(p, name, "", value, usage) - return p -} - -// StringP is like String, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { - p := new(string) - f.StringVarP(p, name, shorthand, value, usage) - return p -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func String(name string, value string, usage string) *string { - return CommandLine.StringP(name, "", value, usage) -} - -// StringP is like String, but accepts a shorthand letter that can be used after a single dash. -func StringP(name, shorthand string, value string, usage string) *string { - return CommandLine.StringP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go deleted file mode 100644 index 276b7ed4..00000000 --- a/vendor/github.com/spf13/pflag/string_array.go +++ /dev/null @@ -1,103 +0,0 @@ -package pflag - -// -- stringArray Value -type stringArrayValue struct { - value *[]string - changed bool -} - -func newStringArrayValue(val []string, p *[]string) *stringArrayValue { - ssv := new(stringArrayValue) - ssv.value = p - *ssv.value = val - return ssv -} - -func (s *stringArrayValue) Set(val string) error { - if !s.changed { - *s.value = []string{val} - s.changed = true - } else { - *s.value = append(*s.value, val) - } - return nil -} - -func (s *stringArrayValue) Type() string { - return "stringArray" -} - -func (s *stringArrayValue) String() string { - str, _ := writeAsCSV(*s.value) - return "[" + str + "]" -} - -func stringArrayConv(sval string) (interface{}, error) { - sval = sval[1 : len(sval)-1] - // An empty string would cause a array with one (empty) string - if len(sval) == 0 { - return []string{}, nil - } - return readAsCSV(sval) -} - -// GetStringArray return the []string value of a flag with the given name -func (f *FlagSet) GetStringArray(name string) ([]string, error) { - val, err := f.getFlagType(name, "stringArray", stringArrayConv) - if err != nil { - return []string{}, err - } - return val.([]string), nil -} - -// StringArrayVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the values of the multiple flags. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { - f.VarP(newStringArrayValue(value, p), name, "", usage) -} - -// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { - f.VarP(newStringArrayValue(value, p), name, shorthand, usage) -} - -// StringArrayVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the value of the flag. -// The value of each argument will not try to be separated by comma -func StringArrayVar(p *[]string, name string, value []string, usage string) { - CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) -} - -// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. -func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { - CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage) -} - -// StringArray defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { - p := []string{} - f.StringArrayVarP(&p, name, "", value, usage) - return &p -} - -// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string { - p := []string{} - f.StringArrayVarP(&p, name, shorthand, value, usage) - return &p -} - -// StringArray defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -// The value of each argument will not try to be separated by comma -func StringArray(name string, value []string, usage string) *[]string { - return CommandLine.StringArrayP(name, "", value, usage) -} - -// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. -func StringArrayP(name, shorthand string, value []string, usage string) *[]string { - return CommandLine.StringArrayP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_array_test.go b/vendor/github.com/spf13/pflag/string_array_test.go deleted file mode 100644 index 1ceac8c6..00000000 --- a/vendor/github.com/spf13/pflag/string_array_test.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - "fmt" - "testing" -) - -func setUpSAFlagSet(sap *[]string) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.StringArrayVar(sap, "sa", []string{}, "Command separated list!") - return f -} - -func setUpSAFlagSetWithDefault(sap *[]string) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.StringArrayVar(sap, "sa", []string{"default", "values"}, "Command separated list!") - return f -} - -func TestEmptySA(t *testing.T) { - var sa []string - f := setUpSAFlagSet(&sa) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getSA, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("got an error from GetStringArray():", err) - } - if len(getSA) != 0 { - t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA)) - } -} - -func TestEmptySAValue(t *testing.T) { - var sa []string - f := setUpSAFlagSet(&sa) - err := f.Parse([]string{"--sa="}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getSA, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("got an error from GetStringArray():", err) - } - if len(getSA) != 0 { - t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA)) - } -} - -func TestSADefault(t *testing.T) { - var sa []string - f := setUpSAFlagSetWithDefault(&sa) - - vals := []string{"default", "values"} - - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range sa { - if vals[i] != v { - t.Fatalf("expected sa[%d] to be %s but got: %s", i, vals[i], v) - } - } - - getSA, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("got an error from GetStringArray():", err) - } - for i, v := range getSA { - if vals[i] != v { - t.Fatalf("expected sa[%d] to be %s from GetStringArray but got: %s", i, vals[i], v) - } - } -} - -func TestSAWithDefault(t *testing.T) { - var sa []string - f := setUpSAFlagSetWithDefault(&sa) - - val := "one" - arg := fmt.Sprintf("--sa=%s", val) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(sa) != 1 { - t.Fatalf("expected number of values to be %d but %d", 1, len(sa)) - } - - if sa[0] != val { - t.Fatalf("expected value to be %s but got: %s", sa[0], val) - } - - getSA, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("got an error from GetStringArray():", err) - } - - if len(getSA) != 1 { - t.Fatalf("expected number of values to be %d but %d", 1, len(getSA)) - } - - if getSA[0] != val { - t.Fatalf("expected value to be %s but got: %s", getSA[0], val) - } -} - -func TestSACalledTwice(t *testing.T) { - var sa []string - f := setUpSAFlagSet(&sa) - - in := []string{"one", "two"} - expected := []string{"one", "two"} - argfmt := "--sa=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(sa) { - t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) - } - for i, v := range sa { - if expected[i] != v { - t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) - } - } - - values, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(values) { - t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(sa)) - } - for i, v := range values { - if expected[i] != v { - t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) - } - } -} - -func TestSAWithSpecialChar(t *testing.T) { - var sa []string - f := setUpSAFlagSet(&sa) - - in := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"} - expected := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"} - argfmt := "--sa=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - arg3 := fmt.Sprintf(argfmt, in[2]) - arg4 := fmt.Sprintf(argfmt, in[3]) - err := f.Parse([]string{arg1, arg2, arg3, arg4}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(sa) { - t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) - } - for i, v := range sa { - if expected[i] != v { - t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) - } - } - - values, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(values) { - t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) - } - for i, v := range values { - if expected[i] != v { - t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) - } - } -} - -func TestSAWithSquareBrackets(t *testing.T) { - var sa []string - f := setUpSAFlagSet(&sa) - - in := []string{"][]-[", "[a-z]", "[a-z]+"} - expected := []string{"][]-[", "[a-z]", "[a-z]+"} - argfmt := "--sa=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - arg3 := fmt.Sprintf(argfmt, in[2]) - err := f.Parse([]string{arg1, arg2, arg3}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(sa) { - t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa)) - } - for i, v := range sa { - if expected[i] != v { - t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v) - } - } - - values, err := f.GetStringArray("sa") - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(values) { - t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) - } - for i, v := range values { - if expected[i] != v { - t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v) - } - } -} diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go deleted file mode 100644 index 05eee754..00000000 --- a/vendor/github.com/spf13/pflag/string_slice.go +++ /dev/null @@ -1,129 +0,0 @@ -package pflag - -import ( - "bytes" - "encoding/csv" - "strings" -) - -// -- stringSlice Value -type stringSliceValue struct { - value *[]string - changed bool -} - -func newStringSliceValue(val []string, p *[]string) *stringSliceValue { - ssv := new(stringSliceValue) - ssv.value = p - *ssv.value = val - return ssv -} - -func readAsCSV(val string) ([]string, error) { - if val == "" { - return []string{}, nil - } - stringReader := strings.NewReader(val) - csvReader := csv.NewReader(stringReader) - return csvReader.Read() -} - -func writeAsCSV(vals []string) (string, error) { - b := &bytes.Buffer{} - w := csv.NewWriter(b) - err := w.Write(vals) - if err != nil { - return "", err - } - w.Flush() - return strings.TrimSuffix(b.String(), "\n"), nil -} - -func (s *stringSliceValue) Set(val string) error { - v, err := readAsCSV(val) - if err != nil { - return err - } - if !s.changed { - *s.value = v - } else { - *s.value = append(*s.value, v...) - } - s.changed = true - return nil -} - -func (s *stringSliceValue) Type() string { - return "stringSlice" -} - -func (s *stringSliceValue) String() string { - str, _ := writeAsCSV(*s.value) - return "[" + str + "]" -} - -func stringSliceConv(sval string) (interface{}, error) { - sval = sval[1 : len(sval)-1] - // An empty string would cause a slice with one (empty) string - if len(sval) == 0 { - return []string{}, nil - } - return readAsCSV(sval) -} - -// GetStringSlice return the []string value of a flag with the given name -func (f *FlagSet) GetStringSlice(name string) ([]string, error) { - val, err := f.getFlagType(name, "stringSlice", stringSliceConv) - if err != nil { - return []string{}, err - } - return val.([]string), nil -} - -// StringSliceVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the value of the flag. -func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { - f.VarP(newStringSliceValue(value, p), name, "", usage) -} - -// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { - f.VarP(newStringSliceValue(value, p), name, shorthand, usage) -} - -// StringSliceVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a []string variable in which to store the value of the flag. -func StringSliceVar(p *[]string, name string, value []string, usage string) { - CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) -} - -// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. -func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { - CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage) -} - -// StringSlice defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { - p := []string{} - f.StringSliceVarP(&p, name, "", value, usage) - return &p -} - -// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string { - p := []string{} - f.StringSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// StringSlice defines a string flag with specified name, default value, and usage string. -// The return value is the address of a []string variable that stores the value of the flag. -func StringSlice(name string, value []string, usage string) *[]string { - return CommandLine.StringSliceP(name, "", value, usage) -} - -// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. -func StringSliceP(name, shorthand string, value []string, usage string) *[]string { - return CommandLine.StringSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/string_slice_test.go b/vendor/github.com/spf13/pflag/string_slice_test.go deleted file mode 100644 index c41f3bd6..00000000 --- a/vendor/github.com/spf13/pflag/string_slice_test.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pflag - -import ( - "fmt" - "strings" - "testing" -) - -func setUpSSFlagSet(ssp *[]string) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.StringSliceVar(ssp, "ss", []string{}, "Command separated list!") - return f -} - -func setUpSSFlagSetWithDefault(ssp *[]string) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.StringSliceVar(ssp, "ss", []string{"default", "values"}, "Command separated list!") - return f -} - -func TestEmptySS(t *testing.T) { - var ss []string - f := setUpSSFlagSet(&ss) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getSS, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("got an error from GetStringSlice():", err) - } - if len(getSS) != 0 { - t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS)) - } -} - -func TestEmptySSValue(t *testing.T) { - var ss []string - f := setUpSSFlagSet(&ss) - err := f.Parse([]string{"--ss="}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getSS, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("got an error from GetStringSlice():", err) - } - if len(getSS) != 0 { - t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS)) - } -} - -func TestSS(t *testing.T) { - var ss []string - f := setUpSSFlagSet(&ss) - - vals := []string{"one", "two", "4", "3"} - arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ss { - if vals[i] != v { - t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) - } - } - - getSS, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("got an error from GetStringSlice():", err) - } - for i, v := range getSS { - if vals[i] != v { - t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) - } - } -} - -func TestSSDefault(t *testing.T) { - var ss []string - f := setUpSSFlagSetWithDefault(&ss) - - vals := []string{"default", "values"} - - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ss { - if vals[i] != v { - t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) - } - } - - getSS, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("got an error from GetStringSlice():", err) - } - for i, v := range getSS { - if vals[i] != v { - t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) - } - } -} - -func TestSSWithDefault(t *testing.T) { - var ss []string - f := setUpSSFlagSetWithDefault(&ss) - - vals := []string{"one", "two", "4", "3"} - arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range ss { - if vals[i] != v { - t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v) - } - } - - getSS, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("got an error from GetStringSlice():", err) - } - for i, v := range getSS { - if vals[i] != v { - t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v) - } - } -} - -func TestSSCalledTwice(t *testing.T) { - var ss []string - f := setUpSSFlagSet(&ss) - - in := []string{"one,two", "three"} - expected := []string{"one", "two", "three"} - argfmt := "--ss=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(ss) { - t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) - } - for i, v := range ss { - if expected[i] != v { - t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) - } - } - - values, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(values) { - t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(ss)) - } - for i, v := range values { - if expected[i] != v { - t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) - } - } -} - -func TestSSWithComma(t *testing.T) { - var ss []string - f := setUpSSFlagSet(&ss) - - in := []string{`"one,two"`, `"three"`, `"four,five",six`} - expected := []string{"one,two", "three", "four,five", "six"} - argfmt := "--ss=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - arg3 := fmt.Sprintf(argfmt, in[2]) - err := f.Parse([]string{arg1, arg2, arg3}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(ss) { - t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) - } - for i, v := range ss { - if expected[i] != v { - t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) - } - } - - values, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(values) { - t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) - } - for i, v := range values { - if expected[i] != v { - t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) - } - } -} - -func TestSSWithSquareBrackets(t *testing.T) { - var ss []string - f := setUpSSFlagSet(&ss) - - in := []string{`"[a-z]"`, `"[a-z]+"`} - expected := []string{"[a-z]", "[a-z]+"} - argfmt := "--ss=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(ss) { - t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss)) - } - for i, v := range ss { - if expected[i] != v { - t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v) - } - } - - values, err := f.GetStringSlice("ss") - if err != nil { - t.Fatal("expected no error; got", err) - } - - if len(expected) != len(values) { - t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values)) - } - for i, v := range values { - if expected[i] != v { - t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v) - } - } -} diff --git a/vendor/github.com/spf13/pflag/uint.go b/vendor/github.com/spf13/pflag/uint.go deleted file mode 100644 index dcbc2b75..00000000 --- a/vendor/github.com/spf13/pflag/uint.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint Value -type uintValue uint - -func newUintValue(val uint, p *uint) *uintValue { - *p = val - return (*uintValue)(p) -} - -func (i *uintValue) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 64) - *i = uintValue(v) - return err -} - -func (i *uintValue) Type() string { - return "uint" -} - -func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uintConv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 0) - if err != nil { - return 0, err - } - return uint(v), nil -} - -// GetUint return the uint value of a flag with the given name -func (f *FlagSet) GetUint(name string) (uint, error) { - val, err := f.getFlagType(name, "uint", uintConv) - if err != nil { - return 0, err - } - return val.(uint), nil -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { - f.VarP(newUintValue(value, p), name, "", usage) -} - -// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { - f.VarP(newUintValue(value, p), name, shorthand, usage) -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func UintVar(p *uint, name string, value uint, usage string) { - CommandLine.VarP(newUintValue(value, p), name, "", usage) -} - -// UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. -func UintVarP(p *uint, name, shorthand string, value uint, usage string) { - CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func (f *FlagSet) Uint(name string, value uint, usage string) *uint { - p := new(uint) - f.UintVarP(p, name, "", value, usage) - return p -} - -// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { - p := new(uint) - f.UintVarP(p, name, shorthand, value, usage) - return p -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint(name string, value uint, usage string) *uint { - return CommandLine.UintP(name, "", value, usage) -} - -// UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. -func UintP(name, shorthand string, value uint, usage string) *uint { - return CommandLine.UintP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint16.go b/vendor/github.com/spf13/pflag/uint16.go deleted file mode 100644 index 7e9914ed..00000000 --- a/vendor/github.com/spf13/pflag/uint16.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint16 value -type uint16Value uint16 - -func newUint16Value(val uint16, p *uint16) *uint16Value { - *p = val - return (*uint16Value)(p) -} - -func (i *uint16Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 16) - *i = uint16Value(v) - return err -} - -func (i *uint16Value) Type() string { - return "uint16" -} - -func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint16Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 16) - if err != nil { - return 0, err - } - return uint16(v), nil -} - -// GetUint16 return the uint16 value of a flag with the given name -func (f *FlagSet) GetUint16(name string) (uint16, error) { - val, err := f.getFlagType(name, "uint16", uint16Conv) - if err != nil { - return 0, err - } - return val.(uint16), nil -} - -// Uint16Var defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { - f.VarP(newUint16Value(value, p), name, "", usage) -} - -// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { - f.VarP(newUint16Value(value, p), name, shorthand, usage) -} - -// Uint16Var defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func Uint16Var(p *uint16, name string, value uint16, usage string) { - CommandLine.VarP(newUint16Value(value, p), name, "", usage) -} - -// Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. -func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { - CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) -} - -// Uint16 defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 { - p := new(uint16) - f.Uint16VarP(p, name, "", value, usage) - return p -} - -// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { - p := new(uint16) - f.Uint16VarP(p, name, shorthand, value, usage) - return p -} - -// Uint16 defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint16(name string, value uint16, usage string) *uint16 { - return CommandLine.Uint16P(name, "", value, usage) -} - -// Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. -func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { - return CommandLine.Uint16P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint32.go b/vendor/github.com/spf13/pflag/uint32.go deleted file mode 100644 index d8024539..00000000 --- a/vendor/github.com/spf13/pflag/uint32.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint32 value -type uint32Value uint32 - -func newUint32Value(val uint32, p *uint32) *uint32Value { - *p = val - return (*uint32Value)(p) -} - -func (i *uint32Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 32) - *i = uint32Value(v) - return err -} - -func (i *uint32Value) Type() string { - return "uint32" -} - -func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint32Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 32) - if err != nil { - return 0, err - } - return uint32(v), nil -} - -// GetUint32 return the uint32 value of a flag with the given name -func (f *FlagSet) GetUint32(name string) (uint32, error) { - val, err := f.getFlagType(name, "uint32", uint32Conv) - if err != nil { - return 0, err - } - return val.(uint32), nil -} - -// Uint32Var defines a uint32 flag with specified name, default value, and usage string. -// The argument p points to a uint32 variable in which to store the value of the flag. -func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { - f.VarP(newUint32Value(value, p), name, "", usage) -} - -// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { - f.VarP(newUint32Value(value, p), name, shorthand, usage) -} - -// Uint32Var defines a uint32 flag with specified name, default value, and usage string. -// The argument p points to a uint32 variable in which to store the value of the flag. -func Uint32Var(p *uint32, name string, value uint32, usage string) { - CommandLine.VarP(newUint32Value(value, p), name, "", usage) -} - -// Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. -func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { - CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) -} - -// Uint32 defines a uint32 flag with specified name, default value, and usage string. -// The return value is the address of a uint32 variable that stores the value of the flag. -func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 { - p := new(uint32) - f.Uint32VarP(p, name, "", value, usage) - return p -} - -// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { - p := new(uint32) - f.Uint32VarP(p, name, shorthand, value, usage) - return p -} - -// Uint32 defines a uint32 flag with specified name, default value, and usage string. -// The return value is the address of a uint32 variable that stores the value of the flag. -func Uint32(name string, value uint32, usage string) *uint32 { - return CommandLine.Uint32P(name, "", value, usage) -} - -// Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. -func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { - return CommandLine.Uint32P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint64.go b/vendor/github.com/spf13/pflag/uint64.go deleted file mode 100644 index f62240f2..00000000 --- a/vendor/github.com/spf13/pflag/uint64.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint64 Value -type uint64Value uint64 - -func newUint64Value(val uint64, p *uint64) *uint64Value { - *p = val - return (*uint64Value)(p) -} - -func (i *uint64Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 64) - *i = uint64Value(v) - return err -} - -func (i *uint64Value) Type() string { - return "uint64" -} - -func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint64Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 64) - if err != nil { - return 0, err - } - return uint64(v), nil -} - -// GetUint64 return the uint64 value of a flag with the given name -func (f *FlagSet) GetUint64(name string) (uint64, error) { - val, err := f.getFlagType(name, "uint64", uint64Conv) - if err != nil { - return 0, err - } - return val.(uint64), nil -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { - f.VarP(newUint64Value(value, p), name, "", usage) -} - -// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { - f.VarP(newUint64Value(value, p), name, shorthand, usage) -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func Uint64Var(p *uint64, name string, value uint64, usage string) { - CommandLine.VarP(newUint64Value(value, p), name, "", usage) -} - -// Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. -func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { - CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { - p := new(uint64) - f.Uint64VarP(p, name, "", value, usage) - return p -} - -// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { - p := new(uint64) - f.Uint64VarP(p, name, shorthand, value, usage) - return p -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func Uint64(name string, value uint64, usage string) *uint64 { - return CommandLine.Uint64P(name, "", value, usage) -} - -// Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. -func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { - return CommandLine.Uint64P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint8.go b/vendor/github.com/spf13/pflag/uint8.go deleted file mode 100644 index bb0e83c1..00000000 --- a/vendor/github.com/spf13/pflag/uint8.go +++ /dev/null @@ -1,88 +0,0 @@ -package pflag - -import "strconv" - -// -- uint8 Value -type uint8Value uint8 - -func newUint8Value(val uint8, p *uint8) *uint8Value { - *p = val - return (*uint8Value)(p) -} - -func (i *uint8Value) Set(s string) error { - v, err := strconv.ParseUint(s, 0, 8) - *i = uint8Value(v) - return err -} - -func (i *uint8Value) Type() string { - return "uint8" -} - -func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } - -func uint8Conv(sval string) (interface{}, error) { - v, err := strconv.ParseUint(sval, 0, 8) - if err != nil { - return 0, err - } - return uint8(v), nil -} - -// GetUint8 return the uint8 value of a flag with the given name -func (f *FlagSet) GetUint8(name string) (uint8, error) { - val, err := f.getFlagType(name, "uint8", uint8Conv) - if err != nil { - return 0, err - } - return val.(uint8), nil -} - -// Uint8Var defines a uint8 flag with specified name, default value, and usage string. -// The argument p points to a uint8 variable in which to store the value of the flag. -func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { - f.VarP(newUint8Value(value, p), name, "", usage) -} - -// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { - f.VarP(newUint8Value(value, p), name, shorthand, usage) -} - -// Uint8Var defines a uint8 flag with specified name, default value, and usage string. -// The argument p points to a uint8 variable in which to store the value of the flag. -func Uint8Var(p *uint8, name string, value uint8, usage string) { - CommandLine.VarP(newUint8Value(value, p), name, "", usage) -} - -// Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. -func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { - CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) -} - -// Uint8 defines a uint8 flag with specified name, default value, and usage string. -// The return value is the address of a uint8 variable that stores the value of the flag. -func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { - p := new(uint8) - f.Uint8VarP(p, name, "", value, usage) - return p -} - -// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { - p := new(uint8) - f.Uint8VarP(p, name, shorthand, value, usage) - return p -} - -// Uint8 defines a uint8 flag with specified name, default value, and usage string. -// The return value is the address of a uint8 variable that stores the value of the flag. -func Uint8(name string, value uint8, usage string) *uint8 { - return CommandLine.Uint8P(name, "", value, usage) -} - -// Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. -func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { - return CommandLine.Uint8P(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint_slice.go b/vendor/github.com/spf13/pflag/uint_slice.go deleted file mode 100644 index edd94c60..00000000 --- a/vendor/github.com/spf13/pflag/uint_slice.go +++ /dev/null @@ -1,126 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" -) - -// -- uintSlice Value -type uintSliceValue struct { - value *[]uint - changed bool -} - -func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue { - uisv := new(uintSliceValue) - uisv.value = p - *uisv.value = val - return uisv -} - -func (s *uintSliceValue) Set(val string) error { - ss := strings.Split(val, ",") - out := make([]uint, len(ss)) - for i, d := range ss { - u, err := strconv.ParseUint(d, 10, 0) - if err != nil { - return err - } - out[i] = uint(u) - } - if !s.changed { - *s.value = out - } else { - *s.value = append(*s.value, out...) - } - s.changed = true - return nil -} - -func (s *uintSliceValue) Type() string { - return "uintSlice" -} - -func (s *uintSliceValue) String() string { - out := make([]string, len(*s.value)) - for i, d := range *s.value { - out[i] = fmt.Sprintf("%d", d) - } - return "[" + strings.Join(out, ",") + "]" -} - -func uintSliceConv(val string) (interface{}, error) { - val = strings.Trim(val, "[]") - // Empty string would cause a slice with one (empty) entry - if len(val) == 0 { - return []uint{}, nil - } - ss := strings.Split(val, ",") - out := make([]uint, len(ss)) - for i, d := range ss { - u, err := strconv.ParseUint(d, 10, 0) - if err != nil { - return nil, err - } - out[i] = uint(u) - } - return out, nil -} - -// GetUintSlice returns the []uint value of a flag with the given name. -func (f *FlagSet) GetUintSlice(name string) ([]uint, error) { - val, err := f.getFlagType(name, "uintSlice", uintSliceConv) - if err != nil { - return []uint{}, err - } - return val.([]uint), nil -} - -// UintSliceVar defines a uintSlice flag with specified name, default value, and usage string. -// The argument p points to a []uint variable in which to store the value of the flag. -func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) { - f.VarP(newUintSliceValue(value, p), name, "", usage) -} - -// UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { - f.VarP(newUintSliceValue(value, p), name, shorthand, usage) -} - -// UintSliceVar defines a uint[] flag with specified name, default value, and usage string. -// The argument p points to a uint[] variable in which to store the value of the flag. -func UintSliceVar(p *[]uint, name string, value []uint, usage string) { - CommandLine.VarP(newUintSliceValue(value, p), name, "", usage) -} - -// UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash. -func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { - CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage) -} - -// UintSlice defines a []uint flag with specified name, default value, and usage string. -// The return value is the address of a []uint variable that stores the value of the flag. -func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint { - p := []uint{} - f.UintSliceVarP(&p, name, "", value, usage) - return &p -} - -// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. -func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { - p := []uint{} - f.UintSliceVarP(&p, name, shorthand, value, usage) - return &p -} - -// UintSlice defines a []uint flag with specified name, default value, and usage string. -// The return value is the address of a []uint variable that stores the value of the flag. -func UintSlice(name string, value []uint, usage string) *[]uint { - return CommandLine.UintSliceP(name, "", value, usage) -} - -// UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. -func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { - return CommandLine.UintSliceP(name, shorthand, value, usage) -} diff --git a/vendor/github.com/spf13/pflag/uint_slice_test.go b/vendor/github.com/spf13/pflag/uint_slice_test.go deleted file mode 100644 index db1a19dc..00000000 --- a/vendor/github.com/spf13/pflag/uint_slice_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package pflag - -import ( - "fmt" - "strconv" - "strings" - "testing" -) - -func setUpUISFlagSet(uisp *[]uint) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.UintSliceVar(uisp, "uis", []uint{}, "Command separated list!") - return f -} - -func setUpUISFlagSetWithDefault(uisp *[]uint) *FlagSet { - f := NewFlagSet("test", ContinueOnError) - f.UintSliceVar(uisp, "uis", []uint{0, 1}, "Command separated list!") - return f -} - -func TestEmptyUIS(t *testing.T) { - var uis []uint - f := setUpUISFlagSet(&uis) - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - - getUIS, err := f.GetUintSlice("uis") - if err != nil { - t.Fatal("got an error from GetUintSlice():", err) - } - if len(getUIS) != 0 { - t.Fatalf("got is %v with len=%d but expected length=0", getUIS, len(getUIS)) - } -} - -func TestUIS(t *testing.T) { - var uis []uint - f := setUpUISFlagSet(&uis) - - vals := []string{"1", "2", "4", "3"} - arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range uis { - u, err := strconv.ParseUint(vals[i], 10, 0) - if err != nil { - t.Fatalf("got error: %v", err) - } - if uint(u) != v { - t.Fatalf("expected uis[%d] to be %s but got %d", i, vals[i], v) - } - } - getUIS, err := f.GetUintSlice("uis") - if err != nil { - t.Fatalf("got error: %v", err) - } - for i, v := range getUIS { - u, err := strconv.ParseUint(vals[i], 10, 0) - if err != nil { - t.Fatalf("got error: %v", err) - } - if uint(u) != v { - t.Fatalf("expected uis[%d] to be %s but got: %d from GetUintSlice", i, vals[i], v) - } - } -} - -func TestUISDefault(t *testing.T) { - var uis []uint - f := setUpUISFlagSetWithDefault(&uis) - - vals := []string{"0", "1"} - - err := f.Parse([]string{}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range uis { - u, err := strconv.ParseUint(vals[i], 10, 0) - if err != nil { - t.Fatalf("got error: %v", err) - } - if uint(u) != v { - t.Fatalf("expect uis[%d] to be %d but got: %d", i, u, v) - } - } - - getUIS, err := f.GetUintSlice("uis") - if err != nil { - t.Fatal("got an error from GetUintSlice():", err) - } - for i, v := range getUIS { - u, err := strconv.ParseUint(vals[i], 10, 0) - if err != nil { - t.Fatal("got an error from GetIntSlice():", err) - } - if uint(u) != v { - t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) - } - } -} - -func TestUISWithDefault(t *testing.T) { - var uis []uint - f := setUpUISFlagSetWithDefault(&uis) - - vals := []string{"1", "2"} - arg := fmt.Sprintf("--uis=%s", strings.Join(vals, ",")) - err := f.Parse([]string{arg}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range uis { - u, err := strconv.ParseUint(vals[i], 10, 0) - if err != nil { - t.Fatalf("got error: %v", err) - } - if uint(u) != v { - t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) - } - } - - getUIS, err := f.GetUintSlice("uis") - if err != nil { - t.Fatal("got an error from GetUintSlice():", err) - } - for i, v := range getUIS { - u, err := strconv.ParseUint(vals[i], 10, 0) - if err != nil { - t.Fatalf("got error: %v", err) - } - if uint(u) != v { - t.Fatalf("expected uis[%d] to be %d from GetUintSlice but got: %d", i, u, v) - } - } -} - -func TestUISCalledTwice(t *testing.T) { - var uis []uint - f := setUpUISFlagSet(&uis) - - in := []string{"1,2", "3"} - expected := []int{1, 2, 3} - argfmt := "--uis=%s" - arg1 := fmt.Sprintf(argfmt, in[0]) - arg2 := fmt.Sprintf(argfmt, in[1]) - err := f.Parse([]string{arg1, arg2}) - if err != nil { - t.Fatal("expected no error; got", err) - } - for i, v := range uis { - if uint(expected[i]) != v { - t.Fatalf("expected uis[%d] to be %d but got: %d", i, expected[i], v) - } - } -} diff --git a/vendor/github.com/spf13/pflag/verify/all.sh b/vendor/github.com/spf13/pflag/verify/all.sh deleted file mode 100755 index 739f89c0..00000000 --- a/vendor/github.com/spf13/pflag/verify/all.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -ROOT=$(dirname "${BASH_SOURCE}")/.. - -# Some useful colors. -if [[ -z "${color_start-}" ]]; then - declare -r color_start="\033[" - declare -r color_red="${color_start}0;31m" - declare -r color_yellow="${color_start}0;33m" - declare -r color_green="${color_start}0;32m" - declare -r color_norm="${color_start}0m" -fi - -SILENT=true - -function is-excluded { - for e in $EXCLUDE; do - if [[ $1 -ef ${BASH_SOURCE} ]]; then - return - fi - if [[ $1 -ef "$ROOT/hack/$e" ]]; then - return - fi - done - return 1 -} - -while getopts ":v" opt; do - case $opt in - v) - SILENT=false - ;; - \?) - echo "Invalid flag: -$OPTARG" >&2 - exit 1 - ;; - esac -done - -if $SILENT ; then - echo "Running in the silent mode, run with -v if you want to see script logs." -fi - -EXCLUDE="all.sh" - -ret=0 -for t in `ls $ROOT/verify/*.sh` -do - if is-excluded $t ; then - echo "Skipping $t" - continue - fi - if $SILENT ; then - echo -e "Verifying $t" - if bash "$t" &> /dev/null; then - echo -e "${color_green}SUCCESS${color_norm}" - else - echo -e "${color_red}FAILED${color_norm}" - ret=1 - fi - else - bash "$t" || ret=1 - fi -done -exit $ret diff --git a/vendor/github.com/spf13/pflag/verify/gofmt.sh b/vendor/github.com/spf13/pflag/verify/gofmt.sh deleted file mode 100755 index f66acf80..00000000 --- a/vendor/github.com/spf13/pflag/verify/gofmt.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -ROOT=$(dirname "${BASH_SOURCE}")/.. - -pushd "${ROOT}" > /dev/null - -GOFMT=${GOFMT:-"gofmt"} -bad_files=$(find . -name '*.go' | xargs $GOFMT -s -l) -if [[ -n "${bad_files}" ]]; then - echo "!!! '$GOFMT' needs to be run on the following files: " - echo "${bad_files}" - exit 1 -fi - -# ex: ts=2 sw=2 et filetype=sh diff --git a/vendor/github.com/spf13/pflag/verify/golint.sh b/vendor/github.com/spf13/pflag/verify/golint.sh deleted file mode 100755 index 685c1778..00000000 --- a/vendor/github.com/spf13/pflag/verify/golint.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -ROOT=$(dirname "${BASH_SOURCE}")/.. -GOLINT=${GOLINT:-"golint"} - -pushd "${ROOT}" > /dev/null - bad_files=$($GOLINT -min_confidence=0.9 ./...) - if [[ -n "${bad_files}" ]]; then - echo "!!! '$GOLINT' problems: " - echo "${bad_files}" - exit 1 - fi -popd > /dev/null - -# ex: ts=2 sw=2 et filetype=sh