Match to last After keyword for parser (#4383)

* Made parser able to skip over subcommands
* Edge case coverage, reworked regex with groups
Signed-off-by: Derek Nola <derek.nola@suse.com>
pull/4427/head
Derek Nola 3 years ago committed by GitHub
parent 8915e4c7f7
commit 7bd65047c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,7 +7,7 @@ import (
func MustParse(args []string) []string { func MustParse(args []string) []string {
parser := &Parser{ parser := &Parser{
After: []string{"server", "agent", "etcd-snapshot"}, After: []string{"server", "agent", "etcd-snapshot:1"},
FlagNames: []string{"--config", "-c"}, FlagNames: []string{"--config", "-c"},
EnvName: version.ProgramUpper + "_CONFIG_FILE", EnvName: version.ProgramUpper + "_CONFIG_FILE",
DefaultConfig: "/etc/rancher/" + version.Program + "/config.yaml", DefaultConfig: "/etc/rancher/" + version.Program + "/config.yaml",

@ -7,6 +7,8 @@ import (
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"strconv"
"strings" "strings"
"github.com/rancher/k3s/pkg/agent/util" "github.com/rancher/k3s/pkg/agent/util"
@ -101,14 +103,36 @@ func (p *Parser) findStart(args []string) ([]string, []string, bool) {
return []string{}, args, true return []string{}, args, true
} }
afterIndex := make(map[string]int)
re, err := regexp.Compile(`(.+):(\d+)`)
if err != nil {
return args, nil, false
}
// After keywords ending with ":<NUM>" can set + NUM of arguments as the split point.
// used for matching on subcommmands
for i, arg := range p.After {
if match := re.FindAllStringSubmatch(arg, -1); match != nil {
p.After[i] = match[0][1]
afterIndex[match[0][1]], err = strconv.Atoi(match[0][2])
if err != nil {
return args, nil, false
}
}
}
for i, val := range args { for i, val := range args {
for _, test := range p.After { for _, test := range p.After {
if val == test { if val == test {
if skip := afterIndex[test]; skip != 0 {
if len(args) <= i+skip || strings.HasPrefix(args[i+skip], "-") {
return args[0 : i+1], args[i+1:], true
}
return args[0 : i+skip+1], args[i+skip+1:], true
}
return args[0 : i+1], args[i+1:], true return args[0 : i+1], args[i+1:], true
} }
} }
} }
return args, nil, false return args, nil, false
} }

@ -48,11 +48,46 @@ func Test_UnitParser_findStart(t *testing.T) {
prefix: []string{"not-server", "foo", "bar"}, prefix: []string{"not-server", "foo", "bar"},
found: false, found: false,
}, },
{
name: "command (with optional subcommands) but no flags",
args: []string{"etcd-snapshot"},
prefix: []string{"etcd-snapshot"},
suffix: []string{},
found: true,
},
{
name: "command (with optional subcommands) and flags",
args: []string{"etcd-snapshot", "-f"},
prefix: []string{"etcd-snapshot"},
suffix: []string{"-f"},
found: true,
},
{
name: "command and subcommand with no flags",
args: []string{"etcd-snapshot", "list"},
prefix: []string{"etcd-snapshot", "list"},
suffix: []string{},
found: true,
},
{
name: "command and subcommand with flags",
args: []string{"etcd-snapshot", "list", "-f"},
prefix: []string{"etcd-snapshot", "list"},
suffix: []string{"-f"},
found: true,
},
{
name: "command and too many subcommands",
args: []string{"etcd-snapshot", "list", "delete", "foo", "bar"},
prefix: []string{"etcd-snapshot", "list"},
suffix: []string{"delete", "foo", "bar"},
found: true,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
p := Parser{ p := Parser{
After: []string{"server", "agent"}, After: []string{"server", "agent", "etcd-snapshot:1"},
} }
prefix, suffix, found := p.findStart(tt.args) prefix, suffix, found := p.findStart(tt.args)
if !reflect.DeepEqual(prefix, tt.prefix) { if !reflect.DeepEqual(prefix, tt.prefix) {

Loading…
Cancel
Save