From 49fe03c626dc10781f2d3241a489c95515af9db4 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Wed, 4 Jul 2018 14:10:06 +0200 Subject: urfave/cli: fix parsing of short opts Vendor an updated version of urfave/cli to fix the parsing of short options. Until the fix is merged upstream, vendor the code from github.com/vrothberg/cli containing both, the latest urfave/cli and the bug fix. Fixes: #714 Signed-off-by: Valentin Rothberg Closes: #1046 Approved by: rhatdan --- vendor/github.com/urfave/cli/README.md | 164 +++++++++++++++++++++++--------- vendor/github.com/urfave/cli/command.go | 57 +++++++++-- vendor/github.com/urfave/cli/flag.go | 16 ++-- vendor/github.com/urfave/cli/help.go | 10 +- 4 files changed, 187 insertions(+), 60 deletions(-) (limited to 'vendor/github.com/urfave/cli') diff --git a/vendor/github.com/urfave/cli/README.md b/vendor/github.com/urfave/cli/README.md index 6096701d8..f2baef4f0 100644 --- a/vendor/github.com/urfave/cli/README.md +++ b/vendor/github.com/urfave/cli/README.md @@ -9,9 +9,9 @@ cli [![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) / [![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc) -**Notice:** This is the library formerly known as -`github.com/codegangsta/cli` -- Github will automatically redirect requests -to this repository, but we recommend updating your references for clarity. +This is the library formerly known as `github.com/codegangsta/cli` -- Github +will automatically redirect requests to this repository, but we recommend +updating your references for clarity. cli is a simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line @@ -141,13 +141,17 @@ discovery. So a cli app can be as little as one line of code in `main()`. package main import ( + "log" "os" "github.com/urfave/cli" ) func main() { - cli.NewApp().Run(os.Args) + err := cli.NewApp().Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -162,6 +166,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -176,7 +181,10 @@ func main() { return nil } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -200,6 +208,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -214,7 +223,10 @@ func main() { return nil } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -263,6 +275,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -276,7 +289,10 @@ func main() { return nil } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -292,6 +308,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -321,7 +338,10 @@ func main() { return nil } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -335,6 +355,7 @@ scanned. package main import ( + "log" "os" "fmt" @@ -368,7 +389,10 @@ func main() { return nil } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -389,6 +413,7 @@ For example this: package main import ( + "log" "os" "github.com/urfave/cli" @@ -404,7 +429,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -430,6 +458,7 @@ list for the `Name`. e.g. package main import ( + "log" "os" "github.com/urfave/cli" @@ -446,7 +475,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -470,6 +502,7 @@ For example this: package main import ( + "log" "os" "sort" @@ -513,7 +546,10 @@ func main() { sort.Sort(cli.FlagsByName(app.Flags)) sort.Sort(cli.CommandsByName(app.Commands)) - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -536,6 +572,7 @@ You can also have the default value set from the environment via `EnvVar`. e.g. package main import ( + "log" "os" "github.com/urfave/cli" @@ -553,7 +590,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -568,6 +608,7 @@ environment variable that resolves is used as the default. package main import ( + "log" "os" "github.com/urfave/cli" @@ -585,7 +626,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -601,6 +645,7 @@ You can also have the default value set from file via `FilePath`. e.g. package main import ( + "log" "os" "github.com/urfave/cli" @@ -617,7 +662,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -653,9 +701,9 @@ the yaml input source for any flags that are defined on that command. As a note the "load" flag used would also have to be defined on the command flags in order for this code snipped to work. -Currently only the aboved specified formats are supported but developers can -add support for other input sources by implementing the -altsrc.InputSourceContext for their given sources. +Currently only YAML and JSON files are supported but developers can add support +for other input sources by implementing the altsrc.InputSourceContext for their +given sources. Here is a more complete sample of a command using YAML support: @@ -668,6 +716,7 @@ package notmain import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -690,7 +739,10 @@ func main() { app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")) app.Flags = flags - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -716,6 +768,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -768,7 +821,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -784,6 +840,7 @@ E.g. package main import ( + "log" "os" "github.com/urfave/cli" @@ -806,7 +863,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -832,6 +892,7 @@ may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a package main import ( + "log" "os" "github.com/urfave/cli" @@ -852,7 +913,10 @@ func main() { return nil } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -872,6 +936,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -903,7 +968,10 @@ func main() { }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -943,6 +1011,7 @@ The default bash completion flag (`--generate-bash-completion`) is defined as package main import ( + "log" "os" "github.com/urfave/cli" @@ -961,7 +1030,10 @@ func main() { Name: "wat", }, } - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -987,6 +1059,7 @@ package main import ( "fmt" + "log" "io" "os" @@ -1030,7 +1103,10 @@ VERSION: fmt.Println("Ha HA. I pwnd the help!!1") } - cli.NewApp().Run(os.Args) + err := cli.NewApp().Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -1045,6 +1121,7 @@ setting `cli.HelpFlag`, e.g.: package main import ( + "log" "os" "github.com/urfave/cli" @@ -1057,7 +1134,10 @@ func main() { EnvVar: "SHOW_HALP,HALPPLZ", } - cli.NewApp().Run(os.Args) + err := cli.NewApp().Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -1080,6 +1160,7 @@ setting `cli.VersionFlag`, e.g.: package main import ( + "log" "os" "github.com/urfave/cli" @@ -1094,7 +1175,10 @@ func main() { app := cli.NewApp() app.Name = "partay" app.Version = "19.99.0" - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -1109,6 +1193,7 @@ package main import ( "fmt" + "log" "os" "github.com/urfave/cli" @@ -1126,7 +1211,10 @@ func main() { app := cli.NewApp() app.Name = "partay" app.Version = "19.99.0" - app.Run(os.Args) + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } } ``` @@ -1388,7 +1476,7 @@ func main() { ec := cli.NewExitError("ohwell", 86) fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode()) fmt.Printf("made it!\n") - return ec + return nil } if os.Getenv("HEXY") != "" { @@ -1402,7 +1490,9 @@ func main() { "whatever-values": 19.99, } - app.Run(os.Args) + + // ignore error so we don't exit non-zero and break gfmrun README example tests + _ = app.Run(os.Args) } func wopAction(c *cli.Context) error { @@ -1433,16 +1523,4 @@ with two leading dashes (such as **--options**) are still valid. ## Contribution Guidelines -Feel free to put up a pull request to fix a bug or maybe add a feature. I will -give it a code review and make sure that it does not break backwards -compatibility. If I or any other collaborators agree that it is in line with -the vision of the project, we will work with you to get the code into -a mergeable state and merge it into the master branch. - -If you have contributed something significant to the project, we will most -likely add you as a collaborator. As a collaborator you are given the ability -to merge others pull requests. It is very important that new code does not -break existing code, so be careful about what code you do choose to merge. - -If you feel like you have contributed to the project but have not yet been -added as a collaborator, we probably forgot to add you, please open an issue. +See [./CONTRIBUTING.md](./CONTRIBUTING.md) diff --git a/vendor/github.com/urfave/cli/command.go b/vendor/github.com/urfave/cli/command.go index 66a58b5a8..c9ba5ec68 100644 --- a/vendor/github.com/urfave/cli/command.go +++ b/vendor/github.com/urfave/cli/command.go @@ -178,19 +178,47 @@ func (c *Command) parseFlags(args Args) (*flag.FlagSet, error) { set.SetOutput(ioutil.Discard) if c.SkipFlagParsing { - return set, set.Parse(append([]string{c.Name, "--"}, args...)) - } - - if c.UseShortOptionHandling { - args = translateShortOptions(args) + return set, set.Parse(append([]string{"--"}, args...)) } if !c.SkipArgReorder { args = reorderArgs(args) } +PARSE: err = set.Parse(args) if err != nil { + if c.UseShortOptionHandling { + // To enable short-option handling (e.g., "-it" vs "-i -t") + // we have to iteratively catch parsing errors. This way + // we achieve LR parsing without transforming any arguments. + // Otherwise, there is no way we can discriminate combined + // short options from common arguments that should be left + // untouched. + errStr := err.Error() + trimmed := strings.TrimPrefix(errStr, "flag provided but not defined: ") + if errStr == trimmed { + return nil, err + } + // regenerate the initial args with the split short opts + newArgs := Args{} + for i, arg := range args { + if arg != trimmed { + newArgs = append(newArgs, trimmed) + continue + } + shortOpts := translateShortOptions(set, Args{trimmed}) + if len(shortOpts) == 1 { + return nil, err + } + // add each short option and all remaining arguments + newArgs = append(newArgs, shortOpts...) + newArgs = append(newArgs, args[i+1:]...) + args = newArgs + // now parse again + goto PARSE + } + } return nil, err } @@ -213,11 +241,12 @@ func reorderArgs(args []string) []string { break } - if readFlagValue { + if readFlagValue && !strings.HasPrefix(arg, "-") && !strings.HasPrefix(arg, "--") { readFlagValue = false flags = append(flags, arg) continue } + readFlagValue = false if arg != "-" && strings.HasPrefix(arg, "-") { flags = append(flags, arg) @@ -231,11 +260,25 @@ func reorderArgs(args []string) []string { return append(flags, nonflags...) } -func translateShortOptions(flagArgs Args) []string { +func translateShortOptions(set *flag.FlagSet, flagArgs Args) []string { + allCharsFlags := func (s string) bool { + for i := range s { + f := set.Lookup(string(s[i])) + if f == nil { + return false + } + } + return true + } + // separate combined flags var flagArgsSeparated []string for _, flagArg := range flagArgs { if strings.HasPrefix(flagArg, "-") && strings.HasPrefix(flagArg, "--") == false && len(flagArg) > 2 { + if !allCharsFlags(flagArg[1:]) { + flagArgsSeparated = append(flagArgsSeparated, flagArg) + continue + } for _, flagChar := range flagArg[1:] { flagArgsSeparated = append(flagArgsSeparated, "-"+string(flagChar)) } diff --git a/vendor/github.com/urfave/cli/flag.go b/vendor/github.com/urfave/cli/flag.go index d4a4d41a2..b0cffc006 100644 --- a/vendor/github.com/urfave/cli/flag.go +++ b/vendor/github.com/urfave/cli/flag.go @@ -636,7 +636,7 @@ func withEnvHint(envVar, str string) string { suffix = "%" sep = "%, %" } - envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix) + envText = " [" + prefix + strings.Join(strings.Split(envVar, ","), sep) + suffix + "]" } return str + envText } @@ -709,13 +709,13 @@ func stringifyFlag(f Flag) string { placeholder = defaultPlaceholder } - usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString)) + usageWithDefault := strings.TrimSpace(usage + defaultValueString) return FlagFileHinter( fv.FieldByName("FilePath").String(), FlagEnvHinter( fv.FieldByName("EnvVar").String(), - fmt.Sprintf("%s\t%s", FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder), usageWithDefault), + FlagNamePrefixer(fv.FieldByName("Name").String(), placeholder)+"\t"+usageWithDefault, ), ) } @@ -724,7 +724,7 @@ func stringifyIntSliceFlag(f IntSliceFlag) string { defaultVals := []string{} if f.Value != nil && len(f.Value.Value()) > 0 { for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) + defaultVals = append(defaultVals, strconv.Itoa(i)) } } @@ -735,7 +735,7 @@ func stringifyInt64SliceFlag(f Int64SliceFlag) string { defaultVals := []string{} if f.Value != nil && len(f.Value.Value()) > 0 { for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) + defaultVals = append(defaultVals, strconv.FormatInt(i, 10)) } } @@ -747,7 +747,7 @@ func stringifyStringSliceFlag(f StringSliceFlag) string { if f.Value != nil && len(f.Value.Value()) > 0 { for _, s := range f.Value.Value() { if len(s) > 0 { - defaultVals = append(defaultVals, fmt.Sprintf("%q", s)) + defaultVals = append(defaultVals, strconv.Quote(s)) } } } @@ -766,8 +766,8 @@ func stringifySliceFlag(usage, name string, defaultVals []string) string { defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) } - usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) - return fmt.Sprintf("%s\t%s", FlagNamePrefixer(name, placeholder), usageWithDefault) + usageWithDefault := strings.TrimSpace(usage + defaultVal) + return FlagNamePrefixer(name, placeholder) + "\t" + usageWithDefault } func flagFromFileEnv(filePath, envName string) (val string, ok bool) { diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/help.go index ed084fc1d..65874fa2f 100644 --- a/vendor/github.com/urfave/cli/help.go +++ b/vendor/github.com/urfave/cli/help.go @@ -158,8 +158,14 @@ func DefaultAppComplete(c *Context) { if command.Hidden { continue } - for _, name := range command.Names() { - fmt.Fprintln(c.App.Writer, name) + if os.Getenv("_CLI_ZSH_AUTOCOMPLETE_HACK") == "1" { + for _, name := range command.Names() { + fmt.Fprintf(c.App.Writer, "%s:%s\n", name, command.Usage) + } + } else { + for _, name := range command.Names() { + fmt.Fprintf(c.App.Writer, "%s\n", name) + } } } } -- cgit v1.2.3-54-g00ecf