mirror of https://github.com/k3s-io/k3s
multivalued requirement parser more whitespace tolerant
parent
162e4983b9
commit
763e48bc6f
|
@ -19,6 +19,7 @@ package labels
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -303,9 +304,11 @@ func (lsel *LabelSelector) String() (string, error) {
|
||||||
// The input will cause an error if it does not follow this form:
|
// The input will cause an error if it does not follow this form:
|
||||||
//
|
//
|
||||||
// <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax>
|
// <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax>
|
||||||
// <requirement> ::= KEY <set-restriction>
|
// <requirement> ::= WHITESPACE_OPT KEY <set-restriction>
|
||||||
// <set-restriction> ::= "" | <inclusion-exclusion> <value-set>
|
// <set-restriction> ::= "" | <inclusion-exclusion> <value-set>
|
||||||
// <inclusion-exclusion> ::= " in " | " not in "
|
// <inclusion-exclusion> ::= <inclusion> | <exclusion>
|
||||||
|
// <exclusion> ::= WHITESPACE "not" <inclusion>
|
||||||
|
// <inclusion> ::= WHITESPACE "in" WHITESPACE
|
||||||
// <value-set> ::= "(" <values> ")"
|
// <value-set> ::= "(" <values> ")"
|
||||||
// <values> ::= VALUE | VALUE "," <values>
|
// <values> ::= VALUE | VALUE "," <values>
|
||||||
//
|
//
|
||||||
|
@ -313,6 +316,10 @@ func (lsel *LabelSelector) String() (string, error) {
|
||||||
// [^, ]+
|
// [^, ]+
|
||||||
// VALUE is a sequence of zero or more characters that does not contain ',', ' ' or ')'
|
// VALUE is a sequence of zero or more characters that does not contain ',', ' ' or ')'
|
||||||
// [^, )]*
|
// [^, )]*
|
||||||
|
// WHITESPACE_OPT is a sequence of zero or more whitespace characters
|
||||||
|
// \s*
|
||||||
|
// WHITESPACE is a sequence of one or more whitespace characters
|
||||||
|
// \s+
|
||||||
//
|
//
|
||||||
// Example of valid syntax:
|
// Example of valid syntax:
|
||||||
// "x in (foo,,baz),y,z not in ()"
|
// "x in (foo,,baz),y,z not in ()"
|
||||||
|
@ -338,9 +345,15 @@ func Parse(selector string) (SetBasedSelector, error) {
|
||||||
waitOp
|
waitOp
|
||||||
inVals
|
inVals
|
||||||
)
|
)
|
||||||
const inPre = "in ("
|
|
||||||
const notInPre = "not in ("
|
|
||||||
const pos = "position %d:%s"
|
const pos = "position %d:%s"
|
||||||
|
inRegex, errIn := regexp.Compile("^\\s*in\\s+\\(")
|
||||||
|
if errIn != nil {
|
||||||
|
return nil, errIn
|
||||||
|
}
|
||||||
|
notInRegex, errNotIn := regexp.Compile("^\\s*not\\s+in\\s+\\(")
|
||||||
|
if errNotIn != nil {
|
||||||
|
return nil, errNotIn
|
||||||
|
}
|
||||||
|
|
||||||
state := startReq
|
state := startReq
|
||||||
strStart := 0
|
strStart := 0
|
||||||
|
@ -350,8 +363,7 @@ func Parse(selector string) (SetBasedSelector, error) {
|
||||||
switch selector[i] {
|
switch selector[i] {
|
||||||
case ',':
|
case ',':
|
||||||
return nil, fmt.Errorf("a requirement can't be empty. "+pos, i, selector)
|
return nil, fmt.Errorf("a requirement can't be empty. "+pos, i, selector)
|
||||||
case ' ':
|
case ' ', '\t', '\n', '\f', '\r':
|
||||||
return nil, fmt.Errorf("white space not allowed before key. "+pos, i, selector)
|
|
||||||
default:
|
default:
|
||||||
state = inKey
|
state = inKey
|
||||||
strStart = i
|
strStart = i
|
||||||
|
@ -365,17 +377,17 @@ func Parse(selector string) (SetBasedSelector, error) {
|
||||||
} else {
|
} else {
|
||||||
items = append(items, *req)
|
items = append(items, *req)
|
||||||
}
|
}
|
||||||
case ' ':
|
case ' ', '\t', '\n', '\f', '\r':
|
||||||
state = waitOp
|
state = waitOp
|
||||||
key = selector[strStart:i]
|
key = selector[strStart:i]
|
||||||
}
|
}
|
||||||
case waitOp:
|
case waitOp:
|
||||||
if len(selector)-i >= len(inPre) && selector[i:len(inPre)+i] == inPre {
|
if loc := inRegex.FindStringIndex(selector[i:]); loc != nil {
|
||||||
op = In
|
op = In
|
||||||
i += len(inPre) - 1
|
i += loc[1] - loc[0] - 1
|
||||||
} else if len(selector)-i >= len(notInPre) && selector[i:len(notInPre)+i] == notInPre {
|
} else if loc = notInRegex.FindStringIndex(selector[i:]); loc != nil {
|
||||||
op = NotIn
|
op = NotIn
|
||||||
i += len(notInPre) - 1
|
i += loc[1] - loc[0] - 1
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("expected \" in (\"/\" not in (\" after key. "+pos, i, selector)
|
return nil, fmt.Errorf("expected \" in (\"/\" not in (\" after key. "+pos, i, selector)
|
||||||
}
|
}
|
||||||
|
|
|
@ -309,16 +309,16 @@ func TestSetSelectorParser(t *testing.T) {
|
||||||
Valid bool
|
Valid bool
|
||||||
}{
|
}{
|
||||||
{"", &LabelSelector{Requirements: nil}, true, true},
|
{"", &LabelSelector{Requirements: nil}, true, true},
|
||||||
{"x", &LabelSelector{Requirements: []Requirement{
|
{"\rx", &LabelSelector{Requirements: []Requirement{
|
||||||
getRequirement("x", Exists, nil, t),
|
getRequirement("x", Exists, nil, t),
|
||||||
}}, true, true},
|
}}, true, true},
|
||||||
{"foo in (abc)", &LabelSelector{Requirements: []Requirement{
|
{"foo in (abc)", &LabelSelector{Requirements: []Requirement{
|
||||||
getRequirement("foo", In, util.NewStringSet("abc"), t),
|
getRequirement("foo", In, util.NewStringSet("abc"), t),
|
||||||
}}, true, true},
|
}}, true, true},
|
||||||
{"x not in (abc)", &LabelSelector{Requirements: []Requirement{
|
{"x not\n\tin (abc)", &LabelSelector{Requirements: []Requirement{
|
||||||
getRequirement("x", NotIn, util.NewStringSet("abc"), t),
|
getRequirement("x", NotIn, util.NewStringSet("abc"), t),
|
||||||
}}, true, true},
|
}}, true, true},
|
||||||
{"x not in (abc,def)", &LabelSelector{Requirements: []Requirement{
|
{"x not in \t (abc,def)", &LabelSelector{Requirements: []Requirement{
|
||||||
getRequirement("x", NotIn, util.NewStringSet("abc", "def"), t),
|
getRequirement("x", NotIn, util.NewStringSet("abc", "def"), t),
|
||||||
}}, true, true},
|
}}, true, true},
|
||||||
{"x in (abc,def)", &LabelSelector{Requirements: []Requirement{
|
{"x in (abc,def)", &LabelSelector{Requirements: []Requirement{
|
||||||
|
@ -342,7 +342,6 @@ func TestSetSelectorParser(t *testing.T) {
|
||||||
}}, false, true},
|
}}, false, true},
|
||||||
{"x,,y", nil, true, false},
|
{"x,,y", nil, true, false},
|
||||||
{",x,y", nil, true, false},
|
{",x,y", nil, true, false},
|
||||||
{"x, y", nil, true, false},
|
|
||||||
{"x nott in (y)", nil, true, false},
|
{"x nott in (y)", nil, true, false},
|
||||||
{"x not in ( )", nil, true, false},
|
{"x not in ( )", nil, true, false},
|
||||||
{"x not in (, a)", nil, true, false},
|
{"x not in (, a)", nil, true, false},
|
||||||
|
|
Loading…
Reference in New Issue