diff options
| author | 2024-03-06 09:05:45 -0800 | |
|---|---|---|
| committer | 2024-03-06 18:05:45 +0100 | |
| commit | fc3741365c27f1d703e8a736af95b95ff811cc45 (patch) | |
| tree | 929f1d5e20d1469d63a3dfe81d38d89f9a073c5a /vendor/github.com/jessevdk | |
| parent | [chore/bugfix] Little DB fixes (#2726) (diff) | |
| download | gotosocial-fc3741365c27f1d703e8a736af95b95ff811cc45.tar.xz | |
[bugfix] Fix Swagger spec and add test script (#2698)
* Add Swagger spec test script
* Fix Swagger spec errors not related to statuses with polls
* Add API tests that post a status with a poll
* Fix creating a status with a poll from form params
* Fix Swagger spec errors related to statuses with polls (this is the last error)
* Fix Swagger spec warnings not related to unused definitions
* Suppress a duplicate list update params definition that was somehow causing wrong param names
* Add Swagger test to CI
- updates Drone config
- vendorizes go-swagger
- fixes a file extension issue that caused the test script to generate JSON instead of YAML with the vendorized version
* Put `Sample: ` on its own line everywhere
* Remove unused id param from emojiCategoriesGet
* Add 5 more pairs of profile fields to account update API Swagger
* Remove Swagger prefix from dummy fields
It makes the generated code look weird
* Manually annotate params for statusCreate operation
* Fix all remaining Swagger spec warnings
- Change some models into operation parameters
- Ignore models that already correspond to manually documented operation parameters but can't be trivially changed (those with file fields)
* Documented that creating a status with scheduled_at isn't implemented yet
* sign drone.yml
* Fix filter API Swagger errors
* fixup! Fix filter API Swagger errors
---------
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Diffstat (limited to 'vendor/github.com/jessevdk')
23 files changed, 5334 insertions, 0 deletions
| 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 000000000..2fc5e5f5b --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/.travis.yml @@ -0,0 +1,39 @@ +language: go + +os: +  - linux +  - osx + +go: +  - 1.16.x + +install: +  # go-flags +  - go build -v ./... + +  # linting +  - go get -v golang.org/x/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/jessevdk/go-flags/LICENSE b/vendor/github.com/jessevdk/go-flags/LICENSE new file mode 100644 index 000000000..bcca0d521 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2012 Jesse van den Kieboom. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +   * Redistributions of source code must retain the above copyright +     notice, this list of conditions and the following disclaimer. +   * Redistributions in binary form must reproduce the above +     copyright notice, this list of conditions and the following disclaimer +     in the documentation and/or other materials provided with the +     distribution. +   * Neither the name of Google Inc. nor the names of its +     contributors may be used to endorse or promote products derived from +     this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 000000000..f22650b20 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/README.md @@ -0,0 +1,139 @@ +go-flags: a go library for parsing command line arguments +========================================================= + +[](https://godoc.org/github.com/jessevdk/go-flags) [](https://travis-ci.org/jessevdk/go-flags) [](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 flag restricted to a pre-defined set of strings +	Animal string `long:"animal" choice:"cat" choice:"dog"` + +	// Example of a value name +	File string `short:"f" long:"file" description:"A file" value-name:"FILE"` + +	// Example of a pointer +	Ptr *int `short:"p" description:"A pointer to an integer"` + +	// Example of a slice of strings +	StringSlice []string `short:"s" description:"A slice of strings"` + +	// Example of a slice of pointers +	PtrSlice []*string `long:"ptrslice" description:"A slice of pointers to string"` + +	// Example of a map +	IntMap map[string]int `long:"intmap" description:"A map from string to int"` +} + +// Callback which will invoke callto:<argument> to call a number. +// Note that this works just on OS X (and probably only with +// Skype) but it shows the idea. +opts.Call = func(num string) { +	cmd := exec.Command("open", "callto:"+num) +	cmd.Start() +	cmd.Process.Release() +} + +// Make some fake arguments to parse. +args := []string{ +	"-vv", +	"--offset=5", +	"-n", "Me", +	"--animal", "dog", // anything other than "cat" or "dog" will raise an error +	"-p", "3", +	"-s", "hello", +	"-s", "world", +	"--ptrslice", "hello", +	"--ptrslice", "world", +	"--intmap", "a:1", +	"--intmap", "b:5", +	"arg1", +	"arg2", +	"arg3", +} + +// Parse flags from `args'. Note that here we use flags.ParseArgs for +// the sake of making a working example. Normally, you would simply use +// flags.Parse(&opts) which uses os.Args +args, err := flags.ParseArgs(&opts, args) + +if err != nil { +	panic(err) +} + +fmt.Printf("Verbosity: %v\n", opts.Verbose) +fmt.Printf("Offset: %d\n", opts.Offset) +fmt.Printf("Name: %s\n", opts.Name) +fmt.Printf("Animal: %s\n", opts.Animal) +fmt.Printf("Ptr: %d\n", *opts.Ptr) +fmt.Printf("StringSlice: %v\n", opts.StringSlice) +fmt.Printf("PtrSlice: [%v %v]\n", *opts.PtrSlice[0], *opts.PtrSlice[1]) +fmt.Printf("IntMap: [a:%v b:%v]\n", opts.IntMap["a"], opts.IntMap["b"]) +fmt.Printf("Remaining args: %s\n", strings.Join(args, " ")) + +// Output: Verbosity: [true true] +// Offset: 5 +// Name: Me +// Ptr: 3 +// StringSlice: [hello world] +// PtrSlice: [hello world] +// IntMap: [a:1 b:5] +// Remaining args: arg1 arg2 arg3 +``` + +More information can be found in the godocs: <http://godoc.org/github.com/jessevdk/go-flags> 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 000000000..8ec62048f --- /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/check_crosscompile.sh b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh new file mode 100644 index 000000000..5edc430ed --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/check_crosscompile.sh @@ -0,0 +1,20 @@ +#!/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 +echo '# aix ppc64' +GOARCH=ppc64 GOOS=aix go build +echo '# solaris amd64' +GOARCH=amd64 GOOS=solaris 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 000000000..3b518757c --- /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 000000000..879465d7a --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/command.go @@ -0,0 +1,465 @@ +package flags + +import ( +	"reflect" +	"sort" +	"strconv" +	"strings" +) + +// Command represents an application command. Commands can be added to the +// parser (which itself is a command) and are selected/executed when its name +// is specified on the command line. The Command type embeds a Group and +// therefore also carries a set of command specific options. +type Command struct { +	// Embedded, see Group for more information +	*Group + +	// The name by which the command can be invoked +	Name string + +	// The active sub command (set by parsing) or nil +	Active *Command + +	// Whether subcommands are optional +	SubcommandsOptional bool + +	// Aliases for the command +	Aliases []string + +	// Whether positional arguments are required +	ArgsRequired bool + +	commands            []*Command +	hasBuiltinHelpGroup bool +	args                []*Arg +} + +// Commander is an interface which can be implemented by any command added in +// the options. When implemented, the Execute method will be called for the last +// specified (sub)command providing the remaining command line arguments. +type Commander interface { +	// Execute will be called for the last active (sub)command. The +	// args argument contains the remaining command line arguments. The +	// error that Execute returns will be eventually passed out of the +	// Parse method of the Parser. +	Execute(args []string) error +} + +// Usage is an interface which can be implemented to show a custom usage string +// in the help message shown for a command. +type Usage interface { +	// Usage is called for commands to allow customized printing of command +	// usage in the generated help message. +	Usage() string +} + +type lookup struct { +	shortNames map[string]*Option +	longNames  map[string]*Option + +	commands map[string]*Command +} + +// AddCommand adds a new command to the parser with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the command. The provided data can implement the Command and +// Usage interfaces. +func (c *Command) AddCommand(command string, shortDescription string, longDescription string, data interface{}) (*Command, error) { +	cmd := newCommand(command, shortDescription, longDescription, data) + +	cmd.parent = c + +	if err := cmd.scan(); err != nil { +		return nil, err +	} + +	c.commands = append(c.commands, cmd) +	return cmd, nil +} + +// AddGroup adds a new group to the command with the given name and data. The +// data needs to be a pointer to a struct from which the fields indicate which +// options are in the group. +func (c *Command) AddGroup(shortDescription string, longDescription string, data interface{}) (*Group, error) { +	group := newGroup(shortDescription, longDescription, data) + +	group.parent = c + +	if err := group.scanType(c.scanSubcommandHandler(group)); err != nil { +		return nil, err +	} + +	c.groups = append(c.groups, group) +	return group, nil +} + +// Commands returns a list of subcommands of this command. +func (c *Command) Commands() []*Command { +	return c.commands +} + +// Find locates the subcommand with the given name and returns it. If no such +// command can be found Find will return nil. +func (c *Command) Find(name string) *Command { +	for _, cc := range c.commands { +		if cc.match(name) { +			return cc +		} +	} + +	return nil +} + +// FindOptionByLongName finds an option that is part of the command, or any of +// its parent commands, by matching its long name (including the option +// namespace). +func (c *Command) FindOptionByLongName(longName string) (option *Option) { +	for option == nil && c != nil { +		option = c.Group.FindOptionByLongName(longName) + +		c, _ = c.parent.(*Command) +	} + +	return option +} + +// FindOptionByShortName finds an option that is part of the command, or any of +// its parent commands, by matching its long name (including the option +// namespace). +func (c *Command) FindOptionByShortName(shortName rune) (option *Option) { +	for option == nil && c != nil { +		option = c.Group.FindOptionByShortName(shortName) + +		c, _ = c.parent.(*Command) +	} + +	return option +} + +// Args returns a list of positional arguments associated with this command. +func (c *Command) Args() []*Arg { +	ret := make([]*Arg, len(c.args)) +	copy(ret, c.args) + +	return ret +} + +func newCommand(name string, shortDescription string, longDescription string, data interface{}) *Command { +	return &Command{ +		Group: newGroup(shortDescription, longDescription, data), +		Name:  name, +	} +} + +func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler { +	f := func(realval reflect.Value, sfield *reflect.StructField) (bool, error) { +		mtag := newMultiTag(string(sfield.Tag)) + +		if err := mtag.Parse(); err != nil { +			return true, err +		} + +		positional := mtag.Get("positional-args") + +		if len(positional) != 0 { +			stype := realval.Type() + +			for i := 0; i < stype.NumField(); i++ { +				field := stype.Field(i) + +				m := newMultiTag((string(field.Tag))) + +				if err := m.Parse(); err != nil { +					return true, err +				} + +				name := m.Get("positional-arg-name") + +				if len(name) == 0 { +					name = field.Name +				} + +				required := -1 +				requiredMaximum := -1 + +				sreq := m.Get("required") + +				if sreq != "" { +					required = 1 + +					rng := strings.SplitN(sreq, "-", 2) + +					if len(rng) > 1 { +						if preq, err := strconv.ParseInt(rng[0], 10, 32); err == nil { +							required = int(preq) +						} + +						if preq, err := strconv.ParseInt(rng[1], 10, 32); err == nil { +							requiredMaximum = int(preq) +						} +					} else { +						if preq, err := strconv.ParseInt(sreq, 10, 32); err == nil { +							required = int(preq) +						} +					} +				} + +				arg := &Arg{ +					Name:            name, +					Description:     m.Get("description"), +					Required:        required, +					RequiredMaximum: requiredMaximum, + +					value: realval.Field(i), +					tag:   m, +				} + +				c.args = append(c.args, arg) + +				if len(mtag.Get("required")) != 0 { +					c.ArgsRequired = true +				} +			} + +			return true, nil +		} + +		subcommand := mtag.Get("command") + +		if len(subcommand) != 0 { +			var ptrval reflect.Value + +			if realval.Kind() == reflect.Ptr { +				ptrval = realval + +				if ptrval.IsNil() { +					ptrval.Set(reflect.New(ptrval.Type().Elem())) +				} +			} else { +				ptrval = realval.Addr() +			} + +			shortDescription := mtag.Get("description") +			longDescription := mtag.Get("long-description") +			subcommandsOptional := mtag.Get("subcommands-optional") +			aliases := mtag.GetMany("alias") + +			subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface()) + +			if err != nil { +				return true, err +			} + +			subc.Hidden = mtag.Get("hidden") != "" + +			if len(subcommandsOptional) > 0 { +				subc.SubcommandsOptional = true +			} + +			if len(aliases) > 0 { +				subc.Aliases = aliases +			} + +			return true, nil +		} + +		return parentg.scanSubGroupHandler(realval, sfield) +	} + +	return f +} + +func (c *Command) scan() error { +	return c.scanType(c.scanSubcommandHandler(c.Group)) +} + +func (c *Command) eachOption(f func(*Command, *Group, *Option)) { +	c.eachCommand(func(c *Command) { +		c.eachGroup(func(g *Group) { +			for _, option := range g.options { +				f(c, g, option) +			} +		}) +	}, true) +} + +func (c *Command) eachCommand(f func(*Command), recurse bool) { +	f(c) + +	for _, cc := range c.commands { +		if recurse { +			cc.eachCommand(f, true) +		} else { +			f(cc) +		} +	} +} + +func (c *Command) eachActiveGroup(f func(cc *Command, g *Group)) { +	c.eachGroup(func(g *Group) { +		f(c, g) +	}) + +	if c.Active != nil { +		c.Active.eachActiveGroup(f) +	} +} + +func (c *Command) addHelpGroups(showHelp func() error) { +	if !c.hasBuiltinHelpGroup { +		c.addHelpGroup(showHelp) +		c.hasBuiltinHelpGroup = true +	} + +	for _, cc := range c.commands { +		cc.addHelpGroups(showHelp) +	} +} + +func (c *Command) makeLookup() lookup { +	ret := lookup{ +		shortNames: make(map[string]*Option), +		longNames:  make(map[string]*Option), +		commands:   make(map[string]*Command), +	} + +	parent := c.parent + +	var parents []*Command + +	for parent != nil { +		if cmd, ok := parent.(*Command); ok { +			parents = append(parents, cmd) +			parent = cmd.parent +		} else { +			parent = nil +		} +	} + +	for i := len(parents) - 1; i >= 0; i-- { +		parents[i].fillLookup(&ret, true) +	} + +	c.fillLookup(&ret, false) +	return ret +} + +func (c *Command) fillLookup(ret *lookup, onlyOptions bool) { +	c.eachGroup(func(g *Group) { +		for _, option := range g.options { +			if option.ShortName != 0 { +				ret.shortNames[string(option.ShortName)] = option +			} + +			if len(option.LongName) > 0 { +				ret.longNames[option.LongNameWithNamespace()] = option +			} +		} +	}) + +	if onlyOptions { +		return +	} + +	for _, subcommand := range c.commands { +		ret.commands[subcommand.Name] = subcommand + +		for _, a := range subcommand.Aliases { +			ret.commands[a] = subcommand +		} +	} +} + +func (c *Command) groupByName(name string) *Group { +	if grp := c.Group.groupByName(name); grp != nil { +		return grp +	} + +	for _, subc := range c.commands { +		prefix := subc.Name + "." + +		if strings.HasPrefix(name, prefix) { +			if grp := subc.groupByName(name[len(prefix):]); grp != nil { +				return grp +			} +		} else if name == subc.Name { +			return subc.Group +		} +	} + +	return nil +} + +type commandList []*Command + +func (c commandList) Less(i, j int) bool { +	return c[i].Name < c[j].Name +} + +func (c commandList) Len() int { +	return len(c) +} + +func (c commandList) Swap(i, j int) { +	c[i], c[j] = c[j], c[i] +} + +func (c *Command) sortedVisibleCommands() []*Command { +	ret := commandList(c.visibleCommands()) +	sort.Sort(ret) + +	return []*Command(ret) +} + +func (c *Command) visibleCommands() []*Command { +	ret := make([]*Command, 0, len(c.commands)) + +	for _, cmd := range c.commands { +		if !cmd.Hidden { +			ret = append(ret, cmd) +		} +	} + +	return ret +} + +func (c *Command) match(name string) bool { +	if c.Name == name { +		return true +	} + +	for _, v := range c.Aliases { +		if v == name { +			return true +		} +	} + +	return false +} + +func (c *Command) hasHelpOptions() bool { +	ret := false + +	c.eachGroup(func(g *Group) { +		if g.isBuiltinHelp { +			return +		} + +		for _, opt := range g.options { +			if opt.showInHelp() { +				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/completion.go b/vendor/github.com/jessevdk/go-flags/completion.go new file mode 100644 index 000000000..8ed61f1db --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/completion.go @@ -0,0 +1,315 @@ +package flags + +import ( +	"fmt" +	"os" +	"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 + "*") +	if len(ret) == 1 { +		if info, err := os.Stat(ret[0]); err == nil && info.IsDir() { +			ret[0] = ret[0] + "/" +		} +	} +	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{ +			{ +				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 && !cmd.Hidden && 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/convert.go b/vendor/github.com/jessevdk/go-flags/convert.go new file mode 100644 index 000000000..cda29b2f0 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/convert.go @@ -0,0 +1,357 @@ +// 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 +} + +// ValueValidator is the interface implemented by types that can validate a +// flag argument themselves. The provided value is directly passed from the +// command line. +type ValueValidator interface { +	// IsValidValue returns an error if the provided string value is valid for +	// the flag. +	IsValidValue(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/error.go b/vendor/github.com/jessevdk/go-flags/error.go new file mode 100644 index 000000000..73e07cfc2 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/error.go @@ -0,0 +1,138 @@ +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" +} + +func (e ErrorType) Error() string { +	return e.String() +} + +// 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/flags.go b/vendor/github.com/jessevdk/go-flags/flags.go new file mode 100644 index 000000000..ac2157dd6 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/flags.go @@ -0,0 +1,263 @@ +// 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. +                    Repeat this tag once for each allowable value. +                    e.g. `long:"animal" choice:"cat" choice:"dog"` +    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) +    env-namespace:        when specified on a group struct field, the env-namespace +                          gets prepended to every option's env key and +                          subgroup's env-namespace of this group, separated by +                          the parser's env-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 000000000..181caabb2 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/group.go @@ -0,0 +1,429 @@ +// Copyright 2012 Jesse van den Kieboom. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +import ( +	"errors" +	"reflect" +	"strings" +	"unicode/utf8" +) + +// ErrNotPointerToStruct indicates that a provided data container is not +// a pointer to a struct. Only pointers to structs are valid data containers +// for options. +var ErrNotPointerToStruct = errors.New("provided data is not a pointer to struct") + +// Group represents an option group. Option groups can be used to logically +// group options together under a description. Groups are only used to provide +// more structure to options both for the user (as displayed in the help message) +// and for you, since groups can be nested. +type Group struct { +	// A short description of the group. The +	// short description is primarily used in the built-in generated help +	// message +	ShortDescription string + +	// A long description of the group. The long +	// description is primarily used to present information on commands +	// (Command embeds Group) in the built-in generated help and man pages. +	LongDescription string + +	// The namespace of the group +	Namespace string + +	// The environment namespace of the group +	EnvNamespace 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 +} + +// AddOption adds a new option to this group. +func (g *Group) AddOption(option *Option, data interface{}) { +	option.value = reflect.ValueOf(data) +	option.group = g +	g.options = append(g.options, option) +} + +// 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) showInHelp() bool { +	if g.Hidden { +		return false +	} +	for _, opt := range g.options { +		if opt.showInHelp() { +			return true +		} +	} +	return false +} + +func (g *Group) eachGroup(f func(*Group)) { +	f(g) + +	for _, gg := range g.groups { +		gg.eachGroup(f) +	} +} + +func isStringFalsy(s string) bool { +	return s == "" || s == "false" || s == "no" || s == "0" +} + +func (g *Group) scanStruct(realval reflect.Value, sfield *reflect.StructField, handler scanHandler) error { +	stype := realval.Type() + +	if sfield != nil { +		if ok, err := handler(realval, sfield); err != nil { +			return err +		} else if ok { +			return nil +		} +	} + +	for i := 0; i < stype.NumField(); i++ { +		field := stype.Field(i) + +		// PkgName is set only for non-exported fields, which we ignore +		if field.PkgPath != "" && !field.Anonymous { +			continue +		} + +		mtag := newMultiTag(string(field.Tag)) + +		if err := mtag.Parse(); err != nil { +			return err +		} + +		// Skip fields with the no-flag tag +		if mtag.Get("no-flag") != "" { +			continue +		} + +		// Dive deep into structs or pointers to structs +		kind := field.Type.Kind() +		fld := realval.Field(i) + +		if kind == reflect.Struct { +			if err := g.scanStruct(fld, &field, handler); err != nil { +				return err +			} +		} else if kind == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct { +			flagCountBefore := len(g.options) + len(g.groups) + +			if fld.IsNil() { +				fld = reflect.New(fld.Type().Elem()) +			} + +			if err := g.scanStruct(reflect.Indirect(fld), &field, handler); err != nil { +				return err +			} + +			if len(g.options)+len(g.groups) != flagCountBefore { +				realval.Field(i).Set(fld) +			} +		} + +		longname := mtag.Get("long") +		shortname := mtag.Get("short") + +		// Need at least either a short or long name +		if longname == "" && shortname == "" && mtag.Get("ini-name") == "" { +			continue +		} + +		short := rune(0) +		rc := utf8.RuneCountInString(shortname) + +		if rc > 1 { +			return newErrorf(ErrShortNameTooLong, +				"short names can only be 1 character long, not `%s'", +				shortname) + +		} else if rc == 1 { +			short, _ = utf8.DecodeRuneInString(shortname) +		} + +		description := mtag.Get("description") +		def := mtag.GetMany("default") + +		optionalValue := mtag.GetMany("optional-value") +		valueName := mtag.Get("value-name") +		defaultMask := mtag.Get("default-mask") + +		optional := !isStringFalsy(mtag.Get("optional")) +		required := !isStringFalsy(mtag.Get("required")) +		choices := mtag.GetMany("choice") +		hidden := !isStringFalsy(mtag.Get("hidden")) + +		option := &Option{ +			Description:      description, +			ShortName:        short, +			LongName:         longname, +			Default:          def, +			EnvDefaultKey:    mtag.Get("env"), +			EnvDefaultDelim:  mtag.Get("env-delim"), +			OptionalArgument: optional, +			OptionalValue:    optionalValue, +			Required:         required, +			ValueName:        valueName, +			DefaultMask:      defaultMask, +			Choices:          choices, +			Hidden:           hidden, + +			group: g, + +			field: field, +			value: realval.Field(i), +			tag:   mtag, +		} + +		if option.isBool() && option.Default != nil { +			return newErrorf(ErrInvalidTag, +				"boolean flag `%s' may not have default values, they always default to `false' and can only be turned on", +				option.shortAndLongName()) +		} + +		g.options = append(g.options, option) +	} + +	return nil +} + +func (g *Group) checkForDuplicateFlags() *Error { +	shortNames := make(map[rune]*Option) +	longNames := make(map[string]*Option) + +	var duplicateError *Error + +	g.eachGroup(func(g *Group) { +		for _, option := range g.options { +			if option.LongName != "" { +				longName := option.LongNameWithNamespace() + +				if otherOption, ok := longNames[longName]; ok { +					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same long name as option `%s'", option, otherOption) +					return +				} +				longNames[longName] = option +			} +			if option.ShortName != 0 { +				if otherOption, ok := shortNames[option.ShortName]; ok { +					duplicateError = newErrorf(ErrDuplicatedFlag, "option `%s' uses the same short name as option `%s'", option, otherOption) +					return +				} +				shortNames[option.ShortName] = option +			} +		} +	}) + +	return duplicateError +} + +func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.StructField) (bool, error) { +	mtag := newMultiTag(string(sfield.Tag)) + +	if err := mtag.Parse(); err != nil { +		return true, err +	} + +	subgroup := mtag.Get("group") + +	if len(subgroup) != 0 { +		var ptrval reflect.Value + +		if realval.Kind() == reflect.Ptr { +			ptrval = realval + +			if ptrval.IsNil() { +				ptrval.Set(reflect.New(ptrval.Type())) +			} +		} else { +			ptrval = realval.Addr() +		} + +		description := mtag.Get("description") + +		group, err := g.AddGroup(subgroup, description, ptrval.Interface()) + +		if err != nil { +			return true, err +		} + +		group.Namespace = mtag.Get("namespace") +		group.EnvNamespace = mtag.Get("env-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/help.go b/vendor/github.com/jessevdk/go-flags/help.go new file mode 100644 index 000000000..068fce152 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/help.go @@ -0,0 +1,514 @@ +// 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 !grp.showInHelp() { +			return +		} +		if c != prevcmd { +			for _, arg := range c.args { +				ret.updateLen(arg.Name, c != p.Command) +			} +		} + +		for _, info := range grp.options { +			if !info.showInHelp() { +				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.EnvKeyWithNamespace() != "" { +			var envPrintable string +			if runtime.GOOS == "windows" { +				envPrintable = "%" + option.EnvKeyWithNamespace() + "%" +			} else { +				envPrintable = "$" + option.EnvKeyWithNamespace() +			} +			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.hasHelpOptions() { +				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.showInHelp() { +					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() +} + +// WroteHelp is a helper to test the error from ParseArgs() to +// determine if the help message was written. It is safe to +// call without first checking that error is nil. +func WroteHelp(err error) bool { +	if err == nil { // No error +		return false +	} + +	flagError, ok := err.(*Error) +	if !ok { // Not a go-flag error +		return false +	} + +	if flagError.Type != ErrHelp { // Did not print the help message +		return false +	} + +	return true +} 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 000000000..60b36c79c --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/ini.go @@ -0,0 +1,615 @@ +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 fqn string + +		if c.Hidden { +			continue +		} + +		if len(namespace) != 0 { +			fqn = namespace + "." + c.Name +		} else { +			fqn = c.Name +		} + +		writeCommandIni(c, fqn, 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 + +	p.eachOption(func(cmd *Command, group *Group, option *Option) { +		option.clearReferenceBeforeSet = true +	}) + +	var quotesLookup = make(map[*Option]bool) + +	for name, section := range ini.Sections { +		groups := i.matchingGroups(name) + +		if len(groups) == 0 { +			if (p.Options & IgnoreUnknown) == None { +				return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name) +			} + +			continue +		} + +		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 parsed as default but defaults are prevented +			if i.ParseAsDefaults && opt.preventDefault { +				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 +					} +				} +			} + +			var err error + +			if i.ParseAsDefaults { +				err = opt.setDefault(pval) +			} else { +				err = opt.set(pval) +			} + +			if err != nil { +				return &IniError{ +					Message:    err.Error(), +					File:       ini.File, +					LineNumber: inival.LineNumber, +				} +			} + +			// Defaults from ini files take precendence over defaults from parser +			opt.preventDefault = true + +			// 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/man.go b/vendor/github.com/jessevdk/go-flags/man.go new file mode 100644 index 000000000..82572f9a7 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/man.go @@ -0,0 +1,223 @@ +package flags + +import ( +	"fmt" +	"io" +	"os" +	"runtime" +	"strconv" +	"strings" +	"time" +) + +func manQuoteLines(s string) string { +	lines := strings.Split(s, "\n") +	parts := []string{} + +	for _, line := range lines { +		parts = append(parts, manQuote(line)) +	} + +	return strings.Join(parts, "\n") +} + +func manQuote(s string) string { +	return strings.Replace(s, "\\", "\\\\", -1) +} + +func formatForMan(wr io.Writer, s string, quoter func(s string) string) { +	for { +		idx := strings.IndexRune(s, '`') + +		if idx < 0 { +			fmt.Fprintf(wr, "%s", quoter(s)) +			break +		} + +		fmt.Fprintf(wr, "%s", quoter(s[:idx])) + +		s = s[idx+1:] +		idx = strings.IndexRune(s, '\'') + +		if idx < 0 { +			fmt.Fprintf(wr, "%s", quoter(s)) +			break +		} + +		fmt.Fprintf(wr, "\\fB%s\\fP", quoter(s[:idx])) +		s = s[idx+1:] +	} +} + +func writeManPageOptions(wr io.Writer, grp *Group) { +	grp.eachGroup(func(group *Group) { +		if !group.showInHelp() { +			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, manQuoteLines) +				fmt.Fprintln(wr, "") +			} +		} + +		for _, opt := range group.options { +			if !opt.showInHelp() { +				continue +			} + +			fmt.Fprintln(wr, ".TP") +			fmt.Fprintf(wr, "\\fB") + +			if opt.ShortName != 0 { +				fmt.Fprintf(wr, "\\fB\\-%c\\fR", opt.ShortName) +			} + +			if len(opt.LongName) != 0 { +				if opt.ShortName != 0 { +					fmt.Fprintf(wr, ", ") +				} + +				fmt.Fprintf(wr, "\\fB\\-\\-%s\\fR", manQuote(opt.LongNameWithNamespace())) +			} + +			if len(opt.ValueName) != 0 || opt.OptionalArgument { +				if opt.OptionalArgument { +					fmt.Fprintf(wr, " [\\fI%s=%s\\fR]", manQuote(opt.ValueName), manQuote(strings.Join(quoteV(opt.OptionalValue), ", "))) +				} else { +					fmt.Fprintf(wr, " \\fI%s\\fR", manQuote(opt.ValueName)) +				} +			} + +			if len(opt.Default) != 0 { +				fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", "))) +			} else if len(opt.EnvKeyWithNamespace()) != 0 { +				if runtime.GOOS == "windows" { +					fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvKeyWithNamespace())) +				} else { +					fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvKeyWithNamespace())) +				} +			} + +			if opt.Required { +				fmt.Fprintf(wr, " (\\fIrequired\\fR)") +			} + +			fmt.Fprintln(wr, "\\fP") + +			if len(opt.Description) != 0 { +				formatForMan(wr, opt.Description, manQuoteLines) +				fmt.Fprintln(wr, "") +			} +		} +	}) +} + +func writeManPageSubcommands(wr io.Writer, name string, usagePrefix 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, usagePrefix, c) +	} +} + +func writeManPageCommand(wr io.Writer, name string, usagePrefix string, 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):], manQuoteLines) +			fmt.Fprintln(wr, "") +		} else { +			formatForMan(wr, command.LongDescription, manQuoteLines) +			fmt.Fprintln(wr, "") +		} +	} + +	var pre = usagePrefix + " " + command.Name + +	var usage string +	if us, ok := command.data.(Usage); ok { +		usage = us.Usage() +	} else if command.hasHelpOptions() { +		usage = fmt.Sprintf("[%s-OPTIONS]", command.Name) +	} + +	var nextPrefix = pre +	if len(usage) > 0 { +		fmt.Fprintf(wr, "\n\\fBUsage\\fP: %s %s\n.TP\n", manQuote(pre), manQuote(usage)) +		nextPrefix = pre + " " + 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, nextPrefix, command) +} + +// WriteManPage writes a basic man page in groff format to the specified +// writer. +func (p *Parser) WriteManPage(wr io.Writer) { +	t := time.Now() +	source_date_epoch := os.Getenv("SOURCE_DATE_EPOCH") +	if source_date_epoch != "" { +		sde, err := strconv.ParseInt(source_date_epoch, 10, 64) +		if err != nil { +			panic(fmt.Sprintf("Invalid SOURCE_DATE_EPOCH: %s", err)) +		} +		t = time.Unix(sde, 0) +	} + +	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), manQuoteLines(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, manQuoteLines) +	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.Name+" "+usage, p.Command) +	} +} 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 000000000..96bb1a31d --- /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 000000000..f6d694181 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/option.go @@ -0,0 +1,569 @@ +package flags + +import ( +	"bytes" +	"fmt" +	"os" +	"reflect" +	"strings" +	"unicode/utf8" +) + +// Option flag information. Contains a description of the option, short and +// long name as well as a default value and whether an argument for this +// flag is optional. +type Option struct { +	// The description of the option flag. This description is shown +	// automatically in the built-in help. +	Description string + +	// The short name of the option (a single character). If not 0, the +	// option flag can be 'activated' using -<ShortName>. Either ShortName +	// or LongName needs to be non-empty. +	ShortName rune + +	// The long name of the option. If not "", the option flag can be +	// activated using --<LongName>. Either ShortName or LongName needs +	// to be non-empty. +	LongName string + +	// The default value of the option. +	Default []string + +	// The optional environment default value key name. +	EnvDefaultKey string + +	// The optional delimiter string for EnvDefaultKey values. +	EnvDefaultDelim string + +	// If true, specifies that the argument to an option flag is optional. +	// When no argument to the flag is specified on the command line, the +	// value of OptionalValue will be set in the field this option represents. +	// This is only valid for non-boolean options. +	OptionalArgument bool + +	// The optional value of the option. The optional value is used when +	// the option flag is marked as having an OptionalArgument. This means +	// that when the flag is specified, but no option argument is given, +	// the value of the field this option represents will be set to +	// OptionalValue. This is only valid for non-boolean options. +	OptionalValue []string + +	// If true, the option _must_ be specified on the command line. If the +	// option is not specified, the parser will generate an ErrRequired type +	// error. +	Required bool + +	// A name for the value of an option shown in the Help as --flag [ValueName] +	ValueName string + +	// A mask value to show in the help instead of the default value. This +	// is useful for hiding sensitive information in the help, such as +	// passwords. +	DefaultMask string + +	// If non empty, only a certain set of values is allowed for an option. +	Choices []string + +	// If true, the option is not displayed in the help or man page +	Hidden bool + +	// The group which the option belongs to +	group *Group + +	// The struct field which the option represents. +	field reflect.StructField + +	// The struct field value which the option represents. +	value reflect.Value + +	// Determines if the option will be always quoted in the INI output +	iniQuote bool + +	tag                     multiTag +	isSet                   bool +	isSetDefault            bool +	preventDefault          bool +	clearReferenceBeforeSet 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 +} + +// EnvKeyWithNamespace returns the option's env key with the group namespaces +// prepended by walking up the option's group tree. Namespaces and the env key +// itself are separated by the parser's namespace delimiter. If the env key is +// empty an empty string is returned. +func (option *Option) EnvKeyWithNamespace() string { +	if len(option.EnvDefaultKey) == 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.EnvNamespaceDelimiter + +			break +		} + +		switch i := g.parent.(type) { +		case *Command: +			g = i.Group +		case *Group: +			g = i +		} +	} + +	// concatenate long name with namespace +	key := option.EnvDefaultKey +	g = option.group + +	for g != nil { +		if g.EnvNamespace != "" { +			key = g.EnvNamespace + namespaceDelimiter + key +		} + +		switch i := g.parent.(type) { +		case *Command: +			g = i.Group +		case *Group: +			g = i +		case *Parser: +			g = nil +		} +	} + +	return key +} + +// 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.clearReferenceBeforeSet { +		option.empty() +	} + +	option.isSet = true +	option.preventDefault = true +	option.clearReferenceBeforeSet = false + +	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) setDefault(value *string) error { +	if option.preventDefault { +		return nil +	} + +	if err := option.set(value); err != nil { +		return err +	} + +	option.isSetDefault = true +	option.preventDefault = false + +	return nil +} + +func (option *Option) showInHelp() bool { +	return !option.Hidden && (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() error { +	if option.preventDefault { +		return nil +	} + +	usedDefault := option.Default + +	if envKey := option.EnvKeyWithNamespace(); envKey != "" { +		if value, ok := os.LookupEnv(envKey); ok { +			if option.EnvDefaultDelim != "" { +				usedDefault = strings.Split(value, option.EnvDefaultDelim) +			} else { +				usedDefault = []string{value} +			} +		} +	} + +	option.isSetDefault = true + +	if len(usedDefault) > 0 { +		option.empty() + +		for _, d := range usedDefault { +			err := option.setDefault(&d) + +			if err != nil { +				return err +			} +		} +	} 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() +			} +		} +	} + +	return nil +} + +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) isValueValidator() ValueValidator { +	v := option.value + +	for { +		if !v.CanInterface() { +			break +		} + +		i := v.Interface() + +		if u, ok := i.(ValueValidator); 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() +} + +func (option *Option) isValidValue(arg string) error { +	if validator := option.isValueValidator(); validator != nil { +		return validator.IsValidValue(arg) +	} +	if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') { +		return fmt.Errorf("expected argument for flag `%s', but got option `%s'", option, arg) +	} +	return nil +} 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 000000000..56dfdae12 --- /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 000000000..f3f28aeef --- /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 000000000..3fc3f7ba1 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/parser.go @@ -0,0 +1,714 @@ +// 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" +	"reflect" +	"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 + +	// EnvNamespaceDelimiter separates group env namespaces and env keys +	EnvNamespaceDelimiter 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:    ".", +		EnvNamespaceDelimiter: "_", +	} + +	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.clearReferenceBeforeSet = true +		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() { +		var err error +		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) { +			if (p.Options&PassAfterNonOption) != None && s.lookup.commands[arg] == nil { +				// If PassAfterNonOption is set then all remaining arguments +				// are considered positional +				if err = s.addArgs(s.arg); err != nil { +					break +				} + +				if err = s.addArgs(s.args...); err != nil { +					break +				} + +				break +			} + +			// 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 +		} + +		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) { +			err := option.clearDefault() +			if err != nil { +				if _, ok := err.(*Error); !ok { +					err = p.marshalError(option, err) +				} +				s.err = err +			} +		}) + +		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 validationErr := option.isValidValue(arg); validationErr != nil { +				return newErrorf(ErrExpectedArgument, validationErr.Error()) +			} 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 = p.marshalError(option, err) +		} +	} + +	return err +} + +func (p *Parser) marshalError(option *Option, err error) *Error { +	s := "invalid argument for flag `%s'" + +	expected := p.expectedType(option) + +	if expected != "" { +		s = s + " (expected " + expected + ")" +	} + +	return newErrorf(ErrMarshal, s+": %s", +		option, +		err.Error()) +} + +func (p *Parser) expectedType(option *Option) string { +	valueType := option.value.Type() + +	if valueType.Kind() == reflect.Func { +		return "" +	} + +	return valueType.String() +} + +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) +		} +	} + +	return s.addArgs(s.arg) +} + +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 +} 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 000000000..829e477ad --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize.go @@ -0,0 +1,15 @@ +// +build !windows,!plan9,!appengine,!wasm + +package flags + +import ( +	"golang.org/x/sys/unix" +) + +func getTerminalColumns() int { +	ws, err := unix.IoctlGetWinsize(0, unix.TIOCGWINSZ) +	if err != nil { +		return 80 +	} +	return int(ws.Col) +} 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 000000000..c1ff18673 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go @@ -0,0 +1,7 @@ +// +build plan9 appengine wasm + +package flags + +func getTerminalColumns() int { +	return 80 +} diff --git a/vendor/github.com/jessevdk/go-flags/termsize_windows.go b/vendor/github.com/jessevdk/go-flags/termsize_windows.go new file mode 100644 index 000000000..5c0fa6ba2 --- /dev/null +++ b/vendor/github.com/jessevdk/go-flags/termsize_windows.go @@ -0,0 +1,85 @@ +// +build windows + +package flags + +import ( +	"syscall" +	"unsafe" +) + +type ( +	SHORT int16 +	WORD  uint16 + +	SMALL_RECT struct { +		Left   SHORT +		Top    SHORT +		Right  SHORT +		Bottom SHORT +	} + +	COORD struct { +		X SHORT +		Y SHORT +	} + +	CONSOLE_SCREEN_BUFFER_INFO struct { +		Size              COORD +		CursorPosition    COORD +		Attributes        WORD +		Window            SMALL_RECT +		MaximumWindowSize COORD +	} +) + +var kernel32DLL = syscall.NewLazyDLL("kernel32.dll") +var getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo") + +func getError(r1, r2 uintptr, lastErr error) error { +	// If the function fails, the return value is zero. +	if r1 == 0 { +		if lastErr != nil { +			return lastErr +		} +		return syscall.EINVAL +	} +	return nil +} + +func getStdHandle(stdhandle int) (uintptr, error) { +	handle, err := syscall.GetStdHandle(stdhandle) +	if err != nil { +		return 0, err +	} +	return uintptr(handle), nil +} + +// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer. +// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx +func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) { +	var info CONSOLE_SCREEN_BUFFER_INFO +	if err := getError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0)); err != nil { +		return nil, err +	} +	return &info, nil +} + +func getTerminalColumns() int { +	defaultWidth := 80 + +	stdoutHandle, err := getStdHandle(syscall.STD_OUTPUT_HANDLE) +	if err != nil { +		return defaultWidth +	} + +	info, err := GetConsoleScreenBufferInfo(stdoutHandle) +	if err != nil { +		return defaultWidth +	} + +	if info.MaximumWindowSize.X > 0 { +		return int(info.MaximumWindowSize.X) +	} + +	return defaultWidth +} | 
