From 4764ca08e13c23414c22342c90af34a405cc821a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Matczuk?= Date: Tue, 1 Aug 2023 11:40:30 +0200 Subject: [PATCH] utils/cobrautil/templates: new value type search algorithm This patch replaces regexp with manual searching for matching bracket. The regexp implementation is not aware of the brackets semantics and matches the last closing bracket preventing the use of <> and [] later in usage. The current implementation finds the value type definition until the first upper case letter. --- .../cobrautil/templates/help_flags_printer.go | 60 +++++++++++++++++-- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/utils/cobrautil/templates/help_flags_printer.go b/utils/cobrautil/templates/help_flags_printer.go index 27f9736f..973eb823 100644 --- a/utils/cobrautil/templates/help_flags_printer.go +++ b/utils/cobrautil/templates/help_flags_printer.go @@ -20,8 +20,8 @@ import ( "bytes" "fmt" "io" - "regexp" "strings" + "unicode" "github.com/mitchellh/go-wordwrap" flag "github.com/spf13/pflag" @@ -95,13 +95,12 @@ func writeFlag(out io.Writer, f *flag.Flag, envPrefix string) { fmt.Fprintf(out, getFlagFormat(f), f.Shorthand, f.Name, name, def, env, usage, deprecated) } -var valueTypeRegex = regexp.MustCompile(`^[<|\[].+[>|\]]`) - func flagNameAndUsage(f *flag.Flag) (string, string) { name, usage := flag.UnquoteUsage(f) - if vt := valueTypeRegex.FindString(usage); vt != "" { - name = vt - usage = strings.TrimSpace(usage[len(vt):]) + + if vt := findValueType(usage); vt > 0 { + name = usage[:vt] + usage = strings.TrimSpace(usage[vt:]) } else { if name == "" || name == "string" { name = "value" @@ -115,6 +114,55 @@ func flagNameAndUsage(f *flag.Flag) (string, string) { return name, usage } +func findValueType(usage string) int { + runes := []rune(usage) + if len(runes) == 0 { + return 0 + } + + var ( + a, b rune + stack int + ) + update := func(r rune) { + switch r { + case '<': + a, b = '<', '>' + stack = 1 + case '[': + a, b = '[', ']' + stack = 1 + } + } + update(runes[0]) + + if stack == 0 { + return 0 + } + + for i := 1; i < len(runes); i++ { + if stack == 0 { + if unicode.IsUpper(runes[i]) { + return i + } + update(runes[i]) + } else { + switch runes[i] { + case a: + stack++ + case b: + stack-- + } + } + } + + if stack > 0 { + panic("unbalanced brackets in usage string") + } + + return len(runes) +} + var envReplacer = strings.NewReplacer(".", "_", "-", "_") func envName(envPrefix, flagName string) string {