1
0
Fork 0
forked from forgejo/forgejo

[Vendor] Update directly used dependencys (#15593)

* update github.com/blevesearch/bleve v2.0.2 -> v2.0.3

* github.com/denisenkom/go-mssqldb v0.9.0 -> v0.10.0

* github.com/editorconfig/editorconfig-core-go v2.4.1 -> v2.4.2

* github.com/go-chi/cors v1.1.1 -> v1.2.0

* github.com/go-git/go-billy v5.0.0 -> v5.1.0

* github.com/go-git/go-git v5.2.0 -> v5.3.0

* github.com/go-ldap/ldap v3.2.4 -> v3.3.0

* github.com/go-redis/redis v8.6.0 -> v8.8.2

* github.com/go-sql-driver/mysql v1.5.0 -> v1.6.0

* github.com/go-swagger/go-swagger v0.26.1 -> v0.27.0

* github.com/lib/pq v1.9.0 -> v1.10.1

* github.com/mattn/go-sqlite3 v1.14.6 -> v1.14.7

* github.com/go-testfixtures/testfixtures v3.5.0 -> v3.6.0

* github.com/issue9/identicon v1.0.1 -> v1.2.0

* github.com/klauspost/compress v1.11.8 -> v1.12.1

* github.com/mgechev/revive v1.0.3 -> v1.0.6

* github.com/microcosm-cc/bluemonday v1.0.7 -> v1.0.8

* github.com/niklasfasching/go-org v1.4.0 -> v1.5.0

* github.com/olivere/elastic v7.0.22 -> v7.0.24

* github.com/pelletier/go-toml v1.8.1 -> v1.9.0

* github.com/prometheus/client_golang v1.9.0 -> v1.10.0

* github.com/xanzy/go-gitlab v0.44.0 -> v0.48.0

* github.com/yuin/goldmark v1.3.3 -> v1.3.5

* github.com/6543/go-version v1.2.4 -> v1.3.1

* do github.com/lib/pq v1.10.0 -> v1.10.1 again ...
This commit is contained in:
6543 2021-04-23 02:08:53 +02:00 committed by GitHub
parent 834fc74873
commit 792b4dba2c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
558 changed files with 32080 additions and 24669 deletions

View file

@ -5,19 +5,14 @@ os:
- osx
go:
- 1.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.16.x
install:
# go-flags
- go get -d -v ./...
- go build -v ./...
# linting
- go get github.com/golang/lint/golint
- go get -v golang.org/x/lint/golint
# code coverage
- go get golang.org/x/tools/cmd/cover

View file

@ -61,6 +61,9 @@ var opts struct {
// 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"`
@ -91,6 +94,7 @@ 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",
@ -115,6 +119,7 @@ if err != nil {
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])

View file

@ -14,3 +14,7 @@ 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

View file

@ -438,7 +438,7 @@ func (c *Command) match(name string) bool {
return false
}
func (c *Command) hasCliOptions() bool {
func (c *Command) hasHelpOptions() bool {
ret := false
c.eachGroup(func(g *Group) {
@ -447,7 +447,7 @@ func (c *Command) hasCliOptions() bool {
}
for _, opt := range g.options {
if opt.canCli() {
if opt.showInHelp() {
ret = true
}
}

View file

@ -2,6 +2,7 @@ package flags
import (
"fmt"
"os"
"path/filepath"
"reflect"
"sort"
@ -62,6 +63,11 @@ func completionsWithoutDescriptions(items []string) []Completion {
// 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)
}
@ -76,7 +82,7 @@ func (c *completion) skipPositional(s *parseState, n int) {
func (c *completion) completeOptionNames(s *parseState, prefix string, match string, short bool) []Completion {
if short && len(match) != 0 {
return []Completion{
Completion{
{
Item: prefix + match,
},
}
@ -124,7 +130,7 @@ func (c *completion) completeCommands(s *parseState, match string) []Completion
n := make([]Completion, 0, len(s.command.commands))
for _, cmd := range s.command.commands {
if cmd.data != c && strings.HasPrefix(cmd.Name, match) {
if cmd.data != c && !cmd.Hidden && strings.HasPrefix(cmd.Name, match) {
n = append(n, Completion{
Item: cmd.Name,
Description: cmd.ShortDescription,

View file

@ -28,6 +28,15 @@ type Unmarshaler interface {
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")

View file

@ -97,6 +97,10 @@ func (e ErrorType) String() string {
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 {

View file

@ -109,7 +109,8 @@ The following is a list of tags for struct fields supported by go-flags:
value-name: the name of the argument value (to be shown in the help)
(optional)
choice: limits the values for an option to a set of values.
This tag can be specified multiple times (optional)
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
@ -125,6 +126,10 @@ The following is a list of tags for struct fields supported by go-flags:
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

5
vendor/github.com/jessevdk/go-flags/go.mod generated vendored Normal file
View file

@ -0,0 +1,5 @@
module github.com/jessevdk/go-flags
go 1.15
require golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4

2
vendor/github.com/jessevdk/go-flags/go.sum generated vendored Normal file
View file

@ -0,0 +1,2 @@
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View file

@ -34,6 +34,9 @@ type Group struct {
// 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
@ -70,6 +73,13 @@ func (g *Group) AddGroup(shortDescription string, longDescription string, data i
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
@ -165,6 +175,18 @@ func (g *Group) optionByName(name string, namematch func(*Option, string) bool)
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)
@ -358,6 +380,7 @@ func (g *Group) scanSubGroupHandler(realval reflect.Value, sfield *reflect.Struc
}
group.Namespace = mtag.Get("namespace")
group.EnvNamespace = mtag.Get("env-namespace")
group.Hidden = mtag.Get("hidden") != ""
return true, nil

View file

@ -72,6 +72,9 @@ func (p *Parser) getAlignmentInfo() alignmentInfo {
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)
@ -79,7 +82,7 @@ func (p *Parser) getAlignmentInfo() alignmentInfo {
}
for _, info := range grp.options {
if !info.canCli() {
if !info.showInHelp() {
continue
}
@ -225,12 +228,12 @@ func (p *Parser) writeHelpOption(writer *bufio.Writer, option *Option, info alig
}
var envDef string
if option.EnvDefaultKey != "" {
if option.EnvKeyWithNamespace() != "" {
var envPrintable string
if runtime.GOOS == "windows" {
envPrintable = "%" + option.EnvDefaultKey + "%"
envPrintable = "%" + option.EnvKeyWithNamespace() + "%"
} else {
envPrintable = "$" + option.EnvDefaultKey
envPrintable = "$" + option.EnvKeyWithNamespace()
}
envDef = fmt.Sprintf(" [%s]", envPrintable)
}
@ -305,7 +308,7 @@ func (p *Parser) WriteHelp(writer io.Writer) {
}
} else if us, ok := allcmd.data.(Usage); ok {
usage = us.Usage()
} else if allcmd.hasCliOptions() {
} else if allcmd.hasHelpOptions() {
usage = fmt.Sprintf("[%s-OPTIONS]", allcmd.Name)
}
@ -393,7 +396,7 @@ func (p *Parser) WriteHelp(writer io.Writer) {
}
for _, info := range grp.options {
if !info.canCli() || info.Hidden {
if !info.showInHelp() {
continue
}
@ -489,3 +492,23 @@ func (p *Parser) WriteHelp(writer io.Writer) {
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
}

View file

@ -325,19 +325,19 @@ func writeCommandIni(command *Command, namespace string, writer io.Writer, optio
})
for _, c := range command.commands {
var nns string
var fqn string
if c.Hidden {
continue
}
if len(namespace) != 0 {
nns = c.Name + "." + nns
fqn = namespace + "." + c.Name
} else {
nns = c.Name
fqn = c.Name
}
writeCommandIni(c, nns, writer, options)
writeCommandIni(c, fqn, writer, options)
}
}
@ -499,13 +499,21 @@ func (i *IniParser) matchingGroups(name string) []*Group {
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 {
return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name)
if (p.Options & IgnoreUnknown) == None {
return newErrorf(ErrUnknownGroup, "could not find option group `%s'", name)
}
continue
}
for _, inival := range section {
@ -537,9 +545,8 @@ func (i *IniParser) parse(ini *ini) error {
continue
}
// ini value is ignored if override is set and
// value was previously set from non default
if i.ParseAsDefaults && !opt.isSetDefault {
// ini value is ignored if parsed as default but defaults are prevented
if i.ParseAsDefaults && opt.preventDefault {
continue
}
@ -572,7 +579,15 @@ func (i *IniParser) parse(ini *ini) error {
}
}
if err := opt.set(pval); err != nil {
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,
@ -580,6 +595,9 @@ func (i *IniParser) parse(ini *ini) error {
}
}
// 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

View file

@ -3,42 +3,55 @@ 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) {
func formatForMan(wr io.Writer, s string, quoter func(s string) string) {
for {
idx := strings.IndexRune(s, '`')
if idx < 0 {
fmt.Fprintf(wr, "%s", manQuote(s))
fmt.Fprintf(wr, "%s", quoter(s))
break
}
fmt.Fprintf(wr, "%s", manQuote(s[:idx]))
fmt.Fprintf(wr, "%s", quoter(s[:idx]))
s = s[idx+1:]
idx = strings.IndexRune(s, '\'')
if idx < 0 {
fmt.Fprintf(wr, "%s", manQuote(s))
fmt.Fprintf(wr, "%s", quoter(s))
break
}
fmt.Fprintf(wr, "\\fB%s\\fP", manQuote(s[:idx]))
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.Hidden || len(group.options) == 0 {
if !group.showInHelp() {
return
}
@ -48,13 +61,13 @@ func writeManPageOptions(wr io.Writer, grp *Group) {
fmt.Fprintf(wr, ".SS %s\n", group.ShortDescription)
if group.LongDescription != "" {
formatForMan(wr, group.LongDescription)
formatForMan(wr, group.LongDescription, manQuoteLines)
fmt.Fprintln(wr, "")
}
}
for _, opt := range group.options {
if !opt.canCli() || opt.Hidden {
if !opt.showInHelp() {
continue
}
@ -83,11 +96,11 @@ func writeManPageOptions(wr io.Writer, grp *Group) {
if len(opt.Default) != 0 {
fmt.Fprintf(wr, " <default: \\fI%s\\fR>", manQuote(strings.Join(quoteV(opt.Default), ", ")))
} else if len(opt.EnvDefaultKey) != 0 {
} else if len(opt.EnvKeyWithNamespace()) != 0 {
if runtime.GOOS == "windows" {
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvDefaultKey))
fmt.Fprintf(wr, " <default: \\fI%%%s%%\\fR>", manQuote(opt.EnvKeyWithNamespace()))
} else {
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvDefaultKey))
fmt.Fprintf(wr, " <default: \\fI$%s\\fR>", manQuote(opt.EnvKeyWithNamespace()))
}
}
@ -98,14 +111,14 @@ func writeManPageOptions(wr io.Writer, grp *Group) {
fmt.Fprintln(wr, "\\fP")
if len(opt.Description) != 0 {
formatForMan(wr, opt.Description)
formatForMan(wr, opt.Description, manQuoteLines)
fmt.Fprintln(wr, "")
}
}
})
}
func writeManPageSubcommands(wr io.Writer, name string, root *Command) {
func writeManPageSubcommands(wr io.Writer, name string, usagePrefix string, root *Command) {
commands := root.sortedVisibleCommands()
for _, c := range commands {
@ -121,11 +134,11 @@ func writeManPageSubcommands(wr io.Writer, name string, root *Command) {
nn = c.Name
}
writeManPageCommand(wr, nn, root, c)
writeManPageCommand(wr, nn, usagePrefix, c)
}
}
func writeManPageCommand(wr io.Writer, name string, root *Command, command *Command) {
func writeManPageCommand(wr io.Writer, name string, usagePrefix string, command *Command) {
fmt.Fprintf(wr, ".SS %s\n", name)
fmt.Fprintln(wr, command.ShortDescription)
@ -137,30 +150,27 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm
if strings.HasPrefix(command.LongDescription, cmdstart) {
fmt.Fprintf(wr, "The \\fI%s\\fP command", manQuote(command.Name))
formatForMan(wr, command.LongDescription[len(cmdstart):])
formatForMan(wr, command.LongDescription[len(cmdstart):], manQuoteLines)
fmt.Fprintln(wr, "")
} else {
formatForMan(wr, command.LongDescription)
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.hasCliOptions() {
} else if command.hasHelpOptions() {
usage = fmt.Sprintf("[%s-OPTIONS]", command.Name)
}
var pre string
if root.hasCliOptions() {
pre = fmt.Sprintf("%s [OPTIONS] %s", root.Name, command.Name)
} else {
pre = fmt.Sprintf("%s %s", root.Name, command.Name)
}
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 {
@ -168,17 +178,25 @@ func writeManPageCommand(wr io.Writer, name string, root *Command, command *Comm
}
writeManPageOptions(wr, command.Group)
writeManPageSubcommands(wr, name, command)
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), manQuote(p.ShortDescription))
fmt.Fprintf(wr, "%s \\- %s\n", manQuote(p.Name), manQuoteLines(p.ShortDescription))
fmt.Fprintln(wr, ".SH SYNOPSIS")
usage := p.Usage
@ -190,7 +208,7 @@ func (p *Parser) WriteManPage(wr io.Writer) {
fmt.Fprintf(wr, "\\fB%s\\fP %s\n", manQuote(p.Name), manQuote(usage))
fmt.Fprintln(wr, ".SH DESCRIPTION")
formatForMan(wr, p.LongDescription)
formatForMan(wr, p.LongDescription, manQuoteLines)
fmt.Fprintln(wr, "")
fmt.Fprintln(wr, ".SH OPTIONS")
@ -200,6 +218,6 @@ func (p *Parser) WriteManPage(wr io.Writer) {
if len(p.visibleCommands()) > 0 {
fmt.Fprintln(wr, ".SH COMMANDS")
writeManPageSubcommands(wr, "", p.Command)
writeManPageSubcommands(wr, "", p.Name+" "+usage, p.Command)
}
}

View file

@ -80,10 +80,11 @@ type Option struct {
// Determines if the option will be always quoted in the INI output
iniQuote bool
tag multiTag
isSet bool
isSetDefault bool
preventDefault bool
tag multiTag
isSet bool
isSetDefault bool
preventDefault bool
clearReferenceBeforeSet bool
defaultLiteral string
}
@ -139,6 +140,57 @@ func (option *Option) LongNameWithNamespace() string {
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 {
@ -190,12 +242,13 @@ func (option *Option) IsSetDefault() bool {
func (option *Option) set(value *string) error {
kind := option.value.Type().Kind()
if (kind == reflect.Map || kind == reflect.Slice) && !option.isSet {
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
@ -229,8 +282,23 @@ func (option *Option) set(value *string) error {
return convert("", option.value, option.tag)
}
func (option *Option) canCli() bool {
return option.ShortName != 0 || len(option.LongName) != 0
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 {
@ -257,14 +325,17 @@ func (option *Option) empty() {
}
}
func (option *Option) clearDefault() {
func (option *Option) clearDefault() error {
if option.preventDefault {
return nil
}
usedDefault := option.Default
if envKey := option.EnvDefaultKey; envKey != "" {
if envKey := option.EnvKeyWithNamespace(); envKey != "" {
if value, ok := os.LookupEnv(envKey); ok {
if option.EnvDefaultDelim != "" {
usedDefault = strings.Split(value,
option.EnvDefaultDelim)
usedDefault = strings.Split(value, option.EnvDefaultDelim)
} else {
usedDefault = []string{value}
}
@ -277,8 +348,11 @@ func (option *Option) clearDefault() {
option.empty()
for _, d := range usedDefault {
option.set(&d)
option.isSetDefault = true
err := option.setDefault(&d)
if err != nil {
return err
}
}
} else {
tp := option.value.Type()
@ -294,6 +368,8 @@ func (option *Option) clearDefault() {
}
}
}
return nil
}
func (option *Option) valueIsDefault() bool {
@ -339,6 +415,30 @@ func (option *Option) isUnmarshaler() Unmarshaler {
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()
@ -457,3 +557,13 @@ func (option *Option) shortAndLongName() string {
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
}

View file

@ -9,6 +9,7 @@ import (
"fmt"
"os"
"path"
"reflect"
"sort"
"strings"
"unicode/utf8"
@ -29,6 +30,9 @@ type Parser struct {
// 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
@ -170,9 +174,10 @@ func NewParser(data interface{}, options Options) *Parser {
// 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: ".",
Command: newCommand(appname, "", "", nil),
Options: options,
NamespaceDelimiter: ".",
EnvNamespaceDelimiter: "_",
}
p.Command.parent = p
@ -203,8 +208,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) {
}
p.eachOption(func(c *Command, g *Group, option *Option) {
option.isSet = false
option.isSetDefault = false
option.clearReferenceBeforeSet = true
option.updateDefaultLiteral()
})
@ -237,6 +241,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) {
p.fillParseState(s)
for !s.eof() {
var err error
arg := s.pop()
// When PassDoubleDash is set and we encounter a --, then
@ -247,6 +252,20 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) {
}
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 {
@ -256,8 +275,6 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) {
continue
}
var err error
prefix, optname, islong := stripOptionPrefix(arg)
optname, _, argument := splitOption(prefix, optname, islong)
@ -293,11 +310,13 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) {
if s.err == nil {
p.eachOption(func(c *Command, g *Group, option *Option) {
if option.preventDefault {
return
err := option.clearDefault()
if err != nil {
if _, ok := err.(*Error); !ok {
err = p.marshalError(option, err)
}
s.err = err
}
option.clearDefault()
})
s.checkRequired(p)
@ -515,8 +534,8 @@ func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg
} else {
arg = s.pop()
if argumentIsOption(arg) && !(option.isSignedNumber() && len(arg) > 1 && arg[0] == '-' && arg[1] >= '0' && arg[1] <= '9') {
return newErrorf(ErrExpectedArgument, "expected argument for flag `%s', but got option `%s'", option, arg)
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)
}
@ -545,16 +564,37 @@ func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg
if err != nil {
if _, ok := err.(*Error); !ok {
err = newErrorf(ErrMarshal, "invalid argument for flag `%s' (expected %s): %s",
option,
option.value.Type(),
err.Error())
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
@ -649,23 +689,7 @@ func (p *Parser) parseNonOption(s *parseState) error {
}
}
if (p.Options & PassAfterNonOption) != None {
// If PassAfterNonOption is set then all remaining arguments
// are considered positional
if err := s.addArgs(s.arg); err != nil {
return err
}
if err := s.addArgs(s.args...); err != nil {
return err
}
s.args = []string{}
} else {
return s.addArgs(s.arg)
}
return nil
return s.addArgs(s.arg)
}
func (p *Parser) showBuiltinHelp() error {
@ -688,13 +712,3 @@ func (p *Parser) printError(err error) error {
return err
}
func (p *Parser) clearIsSet() {
p.eachCommand(func(c *Command) {
c.eachGroup(func(g *Group) {
for _, option := range g.options {
option.isSet = false
}
})
}, true)
}

View file

@ -1,28 +1,15 @@
// +build !windows,!plan9,!solaris,!appengine
// +build !windows,!plan9,!appengine,!wasm
package flags
import (
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
type winsize struct {
row, col uint16
xpixel, ypixel uint16
}
func getTerminalColumns() int {
ws := winsize{}
if tIOCGWINSZ != 0 {
syscall.Syscall(syscall.SYS_IOCTL,
uintptr(0),
uintptr(tIOCGWINSZ),
uintptr(unsafe.Pointer(&ws)))
return int(ws.col)
ws, err := unix.IoctlGetWinsize(0, unix.TIOCGWINSZ)
if err != nil {
return 80
}
return 80
return int(ws.Col)
}

View file

@ -1,4 +1,4 @@
// +build windows plan9 solaris appengine
// +build plan9 appengine wasm
package flags

View file

@ -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
}

View file

@ -1,7 +0,0 @@
// +build darwin freebsd netbsd openbsd
package flags
const (
tIOCGWINSZ = 0x40087468
)

View file

@ -1,7 +0,0 @@
// +build linux
package flags
const (
tIOCGWINSZ = 0x5413
)

View file

@ -1,7 +0,0 @@
// +build !darwin,!freebsd,!netbsd,!openbsd,!linux
package flags
const (
tIOCGWINSZ = 0
)