Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
75f2efb5
Commit
75f2efb5
authored
Feb 25, 2015
by
Salvatore Dario Minonne
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
moving ParseSelector to Parse for labels only.
parent
00989f22
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
189 additions
and
151 deletions
+189
-151
test.sh
hack/lib/test.sh
+1
-1
test-cmd.sh
hack/test-cmd.sh
+6
-6
resthandler.go
pkg/apiserver/resthandler.go
+1
-1
listwatch_test.go
pkg/client/cache/listwatch_test.go
+1
-1
client_test.go
pkg/client/client_test.go
+15
-1
request.go
pkg/client/request.go
+10
-1
request_test.go
pkg/client/request_test.go
+1
-1
builder.go
pkg/kubectl/resource/builder.go
+1
-1
selector.go
pkg/labels/selector.go
+121
-107
selector_test.go
pkg/labels/selector_test.go
+30
-29
registry_test.go
pkg/registry/generic/registry_test.go
+1
-1
etcd_test.go
pkg/registry/pod/etcd/etcd_test.go
+1
-1
No files found.
hack/lib/test.sh
View file @
75f2efb5
...
...
@@ -31,7 +31,7 @@ kube::test::get_object_assert() {
local
request
=
$2
local
expected
=
$3
res
=
$(
kubectl get
"
${
kube_flags
[@]
}
"
$object
-o
template
-t
"
$request
"
)
res
=
$(
eval
kubectl get
"
${
kube_flags
[@]
}
"
$object
-o
template
-t
"
$request
"
)
if
[[
"
$res
"
=
~ ^
$expected$
]]
;
then
echo
-n
${
green
}
...
...
hack/test-cmd.sh
View file @
75f2efb5
...
...
@@ -194,11 +194,11 @@ for version in "${kube_api_versions[@]}"; do
### Delete POD valid-pod with label
# Pre-condition: valid-pod POD is running
kube::test::get_object_assert
'pods -l name=valid-pod'
"{{range.items}}{{.
$id_field
}}:{{end}}"
'valid-pod:'
kube::test::get_object_assert
"pods -l'name in (valid-pod)'"
'{{range.items}}{{.$id_field}}:{{end}}'
'valid-pod:'
# Command
kubectl delete pods
-l
name
=
valid-pod
"
${
kube_flags
[@]
}
"
kubectl delete pods
-l
'name in (valid-pod)'
"
${
kube_flags
[@]
}
"
# Post-condition: no POD is running
kube::test::get_object_assert
'pods -l name=valid-pod'
"{{range.items}}{{.
$id_field
}}:{{end}}"
''
kube::test::get_object_assert
"pods -l'name in (valid-pod)'"
'{{range.items}}{{.$id_field}}:{{end}}'
''
### Create POD valid-pod from JSON
# Pre-condition: no POD is running
...
...
@@ -220,7 +220,7 @@ for version in "${kube_api_versions[@]}"; do
# Pre-condition: valid-pod POD is running
kube::test::get_object_assert pods
"{{range.items}}{{.
$id_field
}}:{{end}}"
'valid-pod:'
# Command
!
kubectl delete
--all
pods
-l
name
=
valid-pod
"
${
kube_flags
[@]
}
"
!
kubectl delete
--all
pods
-l
'name in (valid-pod)'
"
${
kube_flags
[@]
}
"
# Post-condition: valid-pod POD is running
kube::test::get_object_assert pods
"{{range.items}}{{.
$id_field
}}:{{end}}"
'valid-pod:'
...
...
@@ -230,7 +230,7 @@ for version in "${kube_api_versions[@]}"; do
# Command
kubectl delete
--all
pods
"
${
kube_flags
[@]
}
"
# --all remove all the pods
# Post-condition: no POD is running
kube::test::get_object_assert
'pods -l name=valid-pod'
"{{range.items}}{{.
$id_field
}}:{{end}}"
''
kube::test::get_object_assert
"pods -l'name in (valid-pod)'"
'{{range.items}}{{.$id_field}}:{{end}}'
''
### Create two PODs
# Pre-condition: no POD is running
...
...
@@ -318,7 +318,7 @@ for version in "${kube_api_versions[@]}"; do
# Pre-condition: valid-pod POD is running
kube::test::get_object_assert pods
"{{range.items}}{{.
$id_field
}}:{{end}}"
'valid-pod:'
# Command
kubectl delete pods
-l
name
=
valid-pod-super-sayan
"
${
kube_flags
[@]
}
"
kubectl delete pods
-l
'name in (valid-pod-super-sayan)'
"
${
kube_flags
[@]
}
"
# Post-condition: no POD is running
kube::test::get_object_assert pods
"{{range.items}}{{.
$id_field
}}:{{end}}"
''
...
...
pkg/apiserver/resthandler.go
View file @
75f2efb5
...
...
@@ -81,7 +81,7 @@ func GetResource(r RESTGetter, ctxFn ContextFunc, namer ScopeNamer, codec runtim
}
func
parseSelectorQueryParams
(
query
url
.
Values
,
version
,
apiResource
string
)
(
label
,
field
labels
.
Selector
,
err
error
)
{
label
,
err
=
labels
.
Parse
Selector
(
query
.
Get
(
"labels"
))
label
,
err
=
labels
.
Parse
(
query
.
Get
(
"labels"
))
if
err
!=
nil
{
return
nil
,
nil
,
err
}
...
...
pkg/client/cache/listwatch_test.go
View file @
75f2efb5
...
...
@@ -30,7 +30,7 @@ import (
)
func
parseSelectorOrDie
(
s
string
)
labels
.
Selector
{
selector
,
err
:=
labels
.
Parse
Selector
(
s
)
selector
,
err
:=
labels
.
Parse
(
s
)
if
err
!=
nil
{
panic
(
err
)
}
...
...
pkg/client/client_test.go
View file @
75f2efb5
...
...
@@ -139,8 +139,10 @@ func (c *testClient) ValidateCommon(t *testing.T, err error) {
validator
,
ok
:=
c
.
QueryValidator
[
key
]
if
!
ok
{
switch
key
{
case
"labels"
,
"fields"
:
case
"labels"
:
validator
=
validateLabels
case
"fields"
:
validator
=
validateFields
default
:
validator
=
func
(
a
,
b
string
)
bool
{
return
a
==
b
}
}
...
...
@@ -227,6 +229,18 @@ func TestListPods(t *testing.T) {
}
func
validateLabels
(
a
,
b
string
)
bool
{
sA
,
eA
:=
labels
.
Parse
(
a
)
if
eA
!=
nil
{
return
false
}
sB
,
eB
:=
labels
.
Parse
(
b
)
if
eB
!=
nil
{
return
false
}
return
sA
.
String
()
==
sB
.
String
()
}
func
validateFields
(
a
,
b
string
)
bool
{
sA
,
_
:=
labels
.
ParseSelector
(
a
)
sB
,
_
:=
labels
.
ParseSelector
(
b
)
return
sA
.
String
()
==
sB
.
String
()
...
...
pkg/client/request.go
View file @
75f2efb5
...
...
@@ -236,7 +236,16 @@ func (r *Request) ParseSelectorParam(paramName, item string) *Request {
if
r
.
err
!=
nil
{
return
r
}
sel
,
err
:=
labels
.
ParseSelector
(
item
)
var
sel
labels
.
Selector
var
err
error
switch
paramName
{
case
"labels"
:
sel
,
err
=
labels
.
Parse
(
item
)
case
"fields"
:
sel
,
err
=
labels
.
ParseSelector
(
item
)
default
:
err
=
fmt
.
Errorf
(
"unknown parameter name '%s'"
,
paramName
)
}
if
err
!=
nil
{
r
.
err
=
err
return
r
...
...
pkg/client/request_test.go
View file @
75f2efb5
...
...
@@ -142,7 +142,7 @@ func TestRequestSetTwiceError(t *testing.T) {
}
func
TestRequestParseSelectorParam
(
t
*
testing
.
T
)
{
r
:=
(
&
Request
{})
.
ParseSelectorParam
(
"foo"
,
"a"
)
r
:=
(
&
Request
{})
.
ParseSelectorParam
(
"foo"
,
"a
=
"
)
if
r
.
err
==
nil
||
r
.
params
!=
nil
{
t
.
Errorf
(
"should have set err and left params nil: %#v"
,
r
)
}
...
...
pkg/kubectl/resource/builder.go
View file @
75f2efb5
...
...
@@ -164,7 +164,7 @@ func (b *Builder) ResourceTypes(types ...string) *Builder {
// This will not affect files loaded from disk or URL. If the parameter is empty it is
// a no-op - to select all resources invoke `b.Selector(labels.Everything)`.
func
(
b
*
Builder
)
SelectorParam
(
s
string
)
*
Builder
{
selector
,
err
:=
labels
.
Parse
Selector
(
s
)
selector
,
err
:=
labels
.
Parse
(
s
)
if
err
!=
nil
{
b
.
errs
=
append
(
b
.
errs
,
fmt
.
Errorf
(
"the provided selector %q is not valid: %v"
,
s
,
err
))
return
b
...
...
pkg/labels/selector.go
View file @
75f2efb5
...
...
@@ -193,7 +193,7 @@ func NewRequirement(key string, op Operator, vals util.StringSet) (*Requirement,
switch
op
{
case
InOperator
,
NotInOperator
:
if
len
(
vals
)
==
0
{
return
nil
,
fmt
.
Errorf
(
"for
In,NotIn
operators, values set can't be empty"
)
return
nil
,
fmt
.
Errorf
(
"for
'in', 'notin'
operators, values set can't be empty"
)
}
case
EqualsOperator
,
DoubleEqualsOperator
,
NotEqualsOperator
:
if
len
(
vals
)
!=
1
{
...
...
@@ -336,31 +336,30 @@ func (lsel LabelSelector) String() string {
type
Token
int
const
(
ERROR
Token
=
iota
EOS
// end of string
CPAR
COMMA
EEQUAL
EQUAL
IDENTIFIER
IN
NEQUAL
NOTIN
OPAR
OR
ErrorToken
Token
=
iota
EndOfStringToken
ClosedParToken
CommaToken
DoubleEqualsToken
EqualsToken
IdentifierToken
// to represent keys and values
InToken
NotEqualsToken
NotInToken
OpenParToken
)
// string2token contains the mapping between lexer Token and token literal
// (except I
DENTIFIER, EOS and ERROR
since it makes no sense)
// (except I
dentifierToken, EndOfStringToken and ErrorToken
since it makes no sense)
var
string2token
=
map
[
string
]
Token
{
")"
:
C
PAR
,
","
:
C
OMMA
,
"=="
:
EEQUAL
,
"="
:
E
QUAL
,
"in"
:
I
N
,
"!="
:
N
EQUAL
,
"notin"
:
N
OTIN
,
"("
:
O
PAR
,
")"
:
C
losedParToken
,
","
:
C
ommaToken
,
"=="
:
DoubleEqualsToken
,
"="
:
E
qualsToken
,
"in"
:
I
nToken
,
"!="
:
N
otEqualsToken
,
"notin"
:
N
otInToken
,
"("
:
O
penParToken
,
}
// The item produced by the lexer. It contains the Token and the literal.
...
...
@@ -383,11 +382,12 @@ func isSpecialSymbol(ch byte) bool {
return
false
}
// Lexer struct
// Lexer represents the Lexer struct for label selector.
// It contains necessary informationt to tokenize the input string
type
Lexer
struct
{
// s stores the string to be
lex
ed
// s stores the string to be
tokeniz
ed
s
string
// pos is the position currently
lex
ed
// pos is the position currently
tokeniz
ed
pos
int
}
...
...
@@ -402,21 +402,23 @@ func (l *Lexer) read() (b byte) {
return
b
}
//
no return simply unread
//
unread 'undoes' the last read character
func
(
l
*
Lexer
)
unread
()
{
l
.
pos
--
}
//
func return a literal token (for example IN) and
or an identifier.
//
scanIdOrKeyword scans string to recognize literal token (for example 'in')
or an identifier.
func
(
l
*
Lexer
)
scanIdOrKeyword
()
(
tok
Token
,
lit
string
)
{
var
buffer
[]
byte
IdentifierLoop
:
for
{
if
ch
:=
l
.
read
();
ch
==
0
{
// end of string found
break
}
else
if
isSpecialSymbol
(
ch
)
||
isWhitespace
(
ch
)
{
l
.
unread
()
// stop scanning and unread
break
}
else
{
switch
ch
:=
l
.
read
();
{
case
ch
==
0
:
break
IdentifierLoop
case
isSpecialSymbol
(
ch
)
||
isWhitespace
(
ch
)
:
l
.
unread
()
break
IdentifierLoop
default
:
buffer
=
append
(
buffer
,
ch
)
}
}
...
...
@@ -424,64 +426,75 @@ func (l *Lexer) scanIdOrKeyword() (tok Token, lit string) {
if
val
,
ok
:=
string2token
[
s
];
ok
{
// is a literal token?
return
val
,
s
}
return
I
DENTIFIER
,
s
// otherwise is an identifier
return
I
dentifierToken
,
s
// otherwise is an identifier
}
// scan
string starting with specail symbol. At the moment this special symbols
//
identify not literal operators
// scan
SpecialSymbol scans string starting with special symbol.
//
special symbol identify non literal operators. "!=", "==", "="
func
(
l
*
Lexer
)
scanSpecialSymbol
()
(
Token
,
string
)
{
lastScannedItem
:=
ScannedItem
{}
var
buffer
[]
byte
SpecialSymbolLoop
:
for
{
if
ch
:=
l
.
read
();
ch
==
0
{
break
}
else
if
isSpecialSymbol
(
ch
)
{
switch
ch
:=
l
.
read
();
{
case
ch
==
0
:
break
SpecialSymbolLoop
case
isSpecialSymbol
(
ch
)
:
buffer
=
append
(
buffer
,
ch
)
if
token
,
ok
:=
string2token
[
string
(
buffer
)];
ok
{
lastScannedItem
=
ScannedItem
{
tok
:
token
,
literal
:
string
(
buffer
)}
}
else
if
lastScannedItem
.
tok
!=
0
{
l
.
unread
()
break
break
SpecialSymbolLoop
}
}
else
{
// in any other cases (identifer or whitespace) stop
default
:
l
.
unread
()
break
break
SpecialSymbolLoop
}
}
if
lastScannedItem
.
tok
==
0
{
return
ERROR
,
fmt
.
Sprintf
(
"error expected keyword found '%s'"
,
buffer
)
}
else
{
return
lastScannedItem
.
tok
,
lastScannedItem
.
literal
return
ErrorToken
,
fmt
.
Sprintf
(
"error expected: keyword found '%s'"
,
buffer
)
}
return
lastScannedItem
.
tok
,
lastScannedItem
.
literal
}
//
func Lex return Token and the literal (meaningfull only in case of IDENTIFIER)
func
(
l
*
Lexer
)
Lex
()
(
tok
Token
,
lit
string
)
{
ch
:=
l
.
read
()
for
{
// consume spaces until no more spaces
//
skipWhiteSpaces consumes all blank characters
// returning the first non blank character
func
(
l
*
Lexer
)
skipWhiteSpaces
(
ch
byte
)
byte
{
for
{
if
!
isWhitespace
(
ch
)
{
break
return
ch
}
ch
=
l
.
read
()
}
if
ch
==
0
{
// end of the string?
return
EOS
,
""
}
else
if
isSpecialSymbol
(
ch
)
{
}
// Lex returns a pair of Token and the literal
// literal is meaningfull only for IdentifierToken token
func
(
l
*
Lexer
)
Lex
()
(
tok
Token
,
lit
string
)
{
switch
ch
:=
l
.
skipWhiteSpaces
(
l
.
read
());
{
case
ch
==
0
:
return
EndOfStringToken
,
""
case
isSpecialSymbol
(
ch
)
:
l
.
unread
()
return
l
.
scanSpecialSymbol
()
// can be an operator
}
else
{
return
l
.
scanSpecialSymbol
()
default
:
l
.
unread
()
return
l
.
scanIdOrKeyword
()
}
}
// Parser data structure contains the label selector parser data
and algos
// Parser data structure contains the label selector parser data
strucutre
type
Parser
struct
{
l
*
Lexer
scannedItems
[]
ScannedItem
position
int
}
// Parser context represents context during parsing:
// some literal for example 'in' and 'notin' can be
// recognized as operator for example 'x in (a)' but
// it can be recognized as value for example 'value in (in)'
type
ParserContext
int
const
(
...
...
@@ -494,40 +507,40 @@ func (p *Parser) lookahead(context ParserContext) (Token, string) {
tok
,
lit
:=
p
.
scannedItems
[
p
.
position
]
.
tok
,
p
.
scannedItems
[
p
.
position
]
.
literal
if
context
==
Values
{
switch
tok
{
case
I
N
,
NOTIN
:
tok
=
I
DENTIFIER
case
I
nToken
,
NotInToken
:
tok
=
I
dentifierToken
}
}
return
tok
,
lit
}
//
return
current token and string. Increments the the position
//
consume returns
current token and string. Increments the the position
func
(
p
*
Parser
)
consume
(
context
ParserContext
)
(
Token
,
string
)
{
p
.
position
++
tok
,
lit
:=
p
.
scannedItems
[
p
.
position
-
1
]
.
tok
,
p
.
scannedItems
[
p
.
position
-
1
]
.
literal
if
context
==
Values
{
switch
tok
{
case
I
N
,
NOTIN
:
tok
=
I
DENTIFIER
case
I
nToken
,
NotInToken
:
tok
=
I
dentifierToken
}
}
return
tok
,
lit
}
// scan method scan all the input string and storin <token, literal> pairs in
// scanned items slice.
// The Parser can now lookahead and consume the tokens
// scan runs through the input string and stores the ScannedItem in an array
// Parser can now lookahead and consume the tokens
func
(
p
*
Parser
)
scan
()
{
for
{
token
,
literal
:=
p
.
l
.
Lex
()
p
.
scannedItems
=
append
(
p
.
scannedItems
,
ScannedItem
{
token
,
literal
})
if
token
==
E
OS
{
if
token
==
E
ndOfStringToken
{
break
}
}
}
// the entry function to parse list of requirements
// parse runs the left recursive descending algorithm
// on input string. It returns a list of Requirement objects.
func
(
p
*
Parser
)
parse
()
([]
Requirement
,
error
)
{
p
.
scan
()
// init scannedItems
...
...
@@ -535,34 +548,33 @@ func (p *Parser) parse() ([]Requirement, error) {
for
{
tok
,
lit
:=
p
.
lookahead
(
Values
)
switch
tok
{
case
I
DENTIFIER
:
case
I
dentifierToken
:
r
,
err
:=
p
.
parseRequirement
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"
Error
: "
,
err
)
return
nil
,
fmt
.
Errorf
(
"
unable to parse requiremnt
: "
,
err
)
}
requirements
=
append
(
requirements
,
*
r
)
t
,
l
:=
p
.
consume
(
Values
)
switch
t
{
case
E
OS
:
case
E
ndOfStringToken
:
return
requirements
,
nil
case
C
OMMA
:
case
C
ommaToken
:
t2
,
l2
:=
p
.
lookahead
(
Values
)
if
t2
!=
I
DENTIFIER
{
return
nil
,
fmt
.
Errorf
(
"
Expected identifier after comma, found '%s
'"
,
l2
)
if
t2
!=
I
dentifierToken
{
return
nil
,
fmt
.
Errorf
(
"
found '%s', expected: identifier after ',
'"
,
l2
)
}
default
:
return
nil
,
fmt
.
Errorf
(
"
Bad value '%s', expetected comma
or 'end of string'"
,
l
)
return
nil
,
fmt
.
Errorf
(
"
found '%s', expected: ','
or 'end of string'"
,
l
)
}
case
E
OS
:
case
E
ndOfStringToken
:
return
requirements
,
nil
default
:
return
nil
,
fmt
.
Errorf
(
"
Bad value %s. Expected
identifier or 'end of string'"
,
lit
)
return
nil
,
fmt
.
Errorf
(
"
found '%s', expected:
identifier or 'end of string'"
,
lit
)
}
}
return
requirements
,
nil
}
// parse a Requirement data structure
func
(
p
*
Parser
)
parseRequirement
()
(
*
Requirement
,
error
)
{
key
,
operator
,
err
:=
p
.
parseKeyAndInferOperator
()
if
err
!=
nil
{
...
...
@@ -590,17 +602,19 @@ func (p *Parser) parseRequirement() (*Requirement, error) {
}
// parseKeyAndInferOperator parse literals.
// in case of no operator 'in, notin, ==, =, !=' are found
// the 'exists' operattor is inferred
func
(
p
*
Parser
)
parseKeyAndInferOperator
()
(
string
,
Operator
,
error
)
{
tok
,
literal
:=
p
.
consume
(
Values
)
if
tok
!=
I
DENTIFIER
{
err
:=
fmt
.
Errorf
(
"
Found '%s' instead of expected IDENTIFIER
"
,
literal
)
if
tok
!=
I
dentifierToken
{
err
:=
fmt
.
Errorf
(
"
found '%s', expected: identifier
"
,
literal
)
return
""
,
""
,
err
}
if
err
:=
validateLabelKey
(
literal
);
err
!=
nil
{
return
""
,
""
,
err
}
var
operator
Operator
if
t
,
_
:=
p
.
lookahead
(
Values
);
t
==
E
OS
||
t
==
COMMA
{
if
t
,
_
:=
p
.
lookahead
(
Values
);
t
==
E
ndOfStringToken
||
t
==
CommaToken
{
operator
=
ExistsOperator
}
return
literal
,
operator
,
nil
...
...
@@ -611,94 +625,94 @@ func (p *Parser) parseKeyAndInferOperator() (string, Operator, error) {
func
(
p
*
Parser
)
parseOperator
()
(
op
Operator
,
err
error
)
{
tok
,
lit
:=
p
.
consume
(
KeyAndOperator
)
switch
tok
{
case
I
N
:
case
I
nToken
:
op
=
InOperator
case
E
QUAL
:
case
E
qualsToken
:
op
=
EqualsOperator
case
EEQUAL
:
case
DoubleEqualsToken
:
op
=
DoubleEqualsOperator
case
N
OTIN
:
case
N
otInToken
:
op
=
NotInOperator
case
N
EQUAL
:
case
N
otEqualsToken
:
op
=
NotEqualsOperator
default
:
return
""
,
fmt
.
Errorf
(
"
Expected '=', '!=', '==', 'in', notin', found %s
"
,
lit
)
return
""
,
fmt
.
Errorf
(
"
found '%s', expected: '=', '!=', '==', 'in', notin'
"
,
lit
)
}
return
op
,
nil
}
// parse
values parse
the values for set based matching (x,y,z)
// parse
Values parses
the values for set based matching (x,y,z)
func
(
p
*
Parser
)
parseValues
()
(
util
.
StringSet
,
error
)
{
tok
,
lit
:=
p
.
consume
(
Values
)
if
tok
!=
O
PAR
{
return
nil
,
fmt
.
Errorf
(
"
Found '%s' expected
'('"
,
lit
)
if
tok
!=
O
penParToken
{
return
nil
,
fmt
.
Errorf
(
"
found '%s' expected:
'('"
,
lit
)
}
tok
,
lit
=
p
.
lookahead
(
Values
)
switch
tok
{
case
I
DENTIFIER
,
COMMA
:
case
I
dentifierToken
,
CommaToken
:
s
,
err
:=
p
.
parseIdentifiersList
()
// handles general cases
if
err
!=
nil
{
return
s
,
err
}
if
tok
,
_
=
p
.
consume
(
Values
);
tok
!=
C
PAR
{
return
nil
,
fmt
.
Errorf
(
"
Expected a ')', found '%s
'"
,
lit
)
if
tok
,
_
=
p
.
consume
(
Values
);
tok
!=
C
losedParToken
{
return
nil
,
fmt
.
Errorf
(
"
found '%s', expected: ')
'"
,
lit
)
}
return
s
,
nil
case
C
PAR
:
// handles "()"
case
C
losedParToken
:
// handles "()"
p
.
consume
(
Values
)
return
util
.
NewStringSet
(
""
),
nil
default
:
return
nil
,
fmt
.
Errorf
(
"
Expected ')' or ',' or identifier. Found '%s'
"
,
lit
)
return
nil
,
fmt
.
Errorf
(
"
found '%s', expected: ',', ')' or identifier
"
,
lit
)
}
return
util
.
NewStringSet
(),
nil
}
// parseIdentifiersList parse a (possibly empty) list of
// parseIdentifiersList parse
s
a (possibly empty) list of
// of comma separated (possibly empty) identifiers
func
(
p
*
Parser
)
parseIdentifiersList
()
(
util
.
StringSet
,
error
)
{
s
:=
util
.
NewStringSet
()
for
{
tok
,
lit
:=
p
.
consume
(
Values
)
switch
tok
{
case
I
DENTIFIER
:
case
I
dentifierToken
:
s
.
Insert
(
lit
)
tok2
,
lit2
:=
p
.
lookahead
(
Values
)
switch
tok2
{
case
C
OMMA
:
case
C
ommaToken
:
continue
case
C
PAR
:
case
C
losedParToken
:
return
s
,
nil
default
:
return
nil
,
fmt
.
Errorf
(
"
Found '%s', expected
',' or ')'"
,
lit2
)
return
nil
,
fmt
.
Errorf
(
"
found '%s', expected:
',' or ')'"
,
lit2
)
}
case
C
OMMA
:
// handled here since we can have "(,"
case
C
ommaToken
:
// handled here since we can have "(,"
if
s
.
Len
()
==
0
{
s
.
Insert
(
""
)
// to handle (,
}
tok2
,
_
:=
p
.
lookahead
(
Values
)
if
tok2
==
C
PAR
{
if
tok2
==
C
losedParToken
{
s
.
Insert
(
""
)
// to handle ,) Double "" removed by StringSet
return
s
,
nil
}
if
tok2
==
C
OMMA
{
if
tok2
==
C
ommaToken
{
p
.
consume
(
Values
)
s
.
Insert
(
""
)
// to handle ,, Double "" removed by StringSet
}
default
:
// it can be operator
return
s
,
fmt
.
Errorf
(
"
Found '%s', expected
',', or identifier"
,
lit
)
return
s
,
fmt
.
Errorf
(
"
found '%s', expected:
',', or identifier"
,
lit
)
}
}
}
// parse the only value for exact match style
// parse
ExactValue parses
the only value for exact match style
func
(
p
*
Parser
)
parseExactValue
()
(
util
.
StringSet
,
error
)
{
s
:=
util
.
NewStringSet
()
if
tok
,
lit
:=
p
.
consume
(
Values
);
tok
==
IDENTIFIER
{
tok
,
lit
:=
p
.
consume
(
Values
)
if
tok
==
IdentifierToken
{
s
.
Insert
(
lit
)
}
else
{
return
nil
,
fmt
.
Errorf
(
"Found '%s', expected identifier"
,
lit
)
return
s
,
nil
}
return
s
,
nil
return
nil
,
fmt
.
Errorf
(
"found '%s', expected: identifier"
,
lit
)
}
// Parse takes a string representing a selector and returns a selector
...
...
pkg/labels/selector_test.go
View file @
75f2efb5
...
...
@@ -302,17 +302,17 @@ func TestLexer(t *testing.T) {
s
string
t
Token
}{
{
""
,
E
OS
},
{
","
,
C
OMMA
},
{
"notin"
,
N
OTIN
},
{
"in"
,
I
N
},
{
"="
,
E
QUAL
},
{
"=="
,
EEQUAL
},
{
"!="
,
N
EQUAL
},
{
"("
,
O
PAR
},
{
")"
,
C
PAR
},
{
"||"
,
I
DENTIFIER
},
{
"!"
,
E
RROR
},
{
""
,
E
ndOfStringToken
},
{
","
,
C
ommaToken
},
{
"notin"
,
N
otInToken
},
{
"in"
,
I
nToken
},
{
"="
,
E
qualsToken
},
{
"=="
,
DoubleEqualsToken
},
{
"!="
,
N
otEqualsToken
},
{
"("
,
O
penParToken
},
{
")"
,
C
losedParToken
},
{
"||"
,
I
dentifierToken
},
{
"!"
,
E
rrorToken
},
}
for
_
,
v
:=
range
testcases
{
l
:=
&
Lexer
{
s
:
v
.
s
,
pos
:
0
}
...
...
@@ -320,7 +320,7 @@ func TestLexer(t *testing.T) {
if
token
!=
v
.
t
{
t
.
Errorf
(
"Got %d it should be %d for '%s'"
,
token
,
v
.
t
,
v
.
s
)
}
if
v
.
t
!=
E
RROR
&&
lit
!=
v
.
s
{
if
v
.
t
!=
E
rrorToken
&&
lit
!=
v
.
s
{
t
.
Errorf
(
"Got '%s' it should be '%s'"
,
lit
,
v
.
s
)
}
}
...
...
@@ -339,13 +339,13 @@ func TestLexerSequence(t *testing.T) {
s
string
t
[]
Token
}{
{
"key in ( value )"
,
[]
Token
{
I
DENTIFIER
,
IN
,
OPAR
,
IDENTIFIER
,
CPAR
}},
{
"key notin ( value )"
,
[]
Token
{
I
DENTIFIER
,
NOTIN
,
OPAR
,
IDENTIFIER
,
CPAR
}},
{
"key in ( value1, value2 )"
,
[]
Token
{
I
DENTIFIER
,
IN
,
OPAR
,
IDENTIFIER
,
COMMA
,
IDENTIFIER
,
CPAR
}},
{
"key"
,
[]
Token
{
I
DENTIFIER
}},
{
"()"
,
[]
Token
{
O
PAR
,
CPAR
}},
{
"x in (),y"
,
[]
Token
{
I
DENTIFIER
,
IN
,
OPAR
,
CPAR
,
COMMA
,
IDENTIFIER
}},
{
"== != (), = notin"
,
[]
Token
{
EEQUAL
,
NEQUAL
,
OPAR
,
CPAR
,
COMMA
,
EQUAL
,
NOTIN
}},
{
"key in ( value )"
,
[]
Token
{
I
dentifierToken
,
InToken
,
OpenParToken
,
IdentifierToken
,
ClosedParToken
}},
{
"key notin ( value )"
,
[]
Token
{
I
dentifierToken
,
NotInToken
,
OpenParToken
,
IdentifierToken
,
ClosedParToken
}},
{
"key in ( value1, value2 )"
,
[]
Token
{
I
dentifierToken
,
InToken
,
OpenParToken
,
IdentifierToken
,
CommaToken
,
IdentifierToken
,
ClosedParToken
}},
{
"key"
,
[]
Token
{
I
dentifierToken
}},
{
"()"
,
[]
Token
{
O
penParToken
,
ClosedParToken
}},
{
"x in (),y"
,
[]
Token
{
I
dentifierToken
,
InToken
,
OpenParToken
,
ClosedParToken
,
CommaToken
,
IdentifierToken
}},
{
"== != (), = notin"
,
[]
Token
{
DoubleEqualsToken
,
NotEqualsToken
,
OpenParToken
,
ClosedParToken
,
CommaToken
,
EqualsToken
,
NotInToken
}},
}
for
_
,
v
:=
range
testcases
{
var
literals
[]
string
...
...
@@ -353,7 +353,7 @@ func TestLexerSequence(t *testing.T) {
l
:=
&
Lexer
{
s
:
v
.
s
,
pos
:
0
}
for
{
token
,
lit
:=
l
.
Lex
()
if
token
==
E
OS
{
if
token
==
E
ndOfStringToken
{
break
}
tokens
=
append
(
tokens
,
token
)
...
...
@@ -374,14 +374,14 @@ func TestParserLookahead(t *testing.T) {
s
string
t
[]
Token
}{
{
"key in ( value )"
,
[]
Token
{
I
DENTIFIER
,
IN
,
OPAR
,
IDENTIFIER
,
CPAR
,
EOS
}},
{
"key notin ( value )"
,
[]
Token
{
I
DENTIFIER
,
NOTIN
,
OPAR
,
IDENTIFIER
,
CPAR
,
EOS
}},
{
"key in ( value1, value2 )"
,
[]
Token
{
I
DENTIFIER
,
IN
,
OPAR
,
IDENTIFIER
,
COMMA
,
IDENTIFIER
,
CPAR
,
EOS
}},
{
"key"
,
[]
Token
{
I
DENTIFIER
,
EOS
}},
{
"()"
,
[]
Token
{
O
PAR
,
CPAR
,
EOS
}},
{
""
,
[]
Token
{
E
OS
}},
{
"x in (),y"
,
[]
Token
{
I
DENTIFIER
,
IN
,
OPAR
,
CPAR
,
COMMA
,
IDENTIFIER
,
EOS
}},
{
"== != (), = notin"
,
[]
Token
{
EEQUAL
,
NEQUAL
,
OPAR
,
CPAR
,
COMMA
,
EQUAL
,
NOTIN
,
EOS
}},
{
"key in ( value )"
,
[]
Token
{
I
dentifierToken
,
InToken
,
OpenParToken
,
IdentifierToken
,
ClosedParToken
,
EndOfStringToken
}},
{
"key notin ( value )"
,
[]
Token
{
I
dentifierToken
,
NotInToken
,
OpenParToken
,
IdentifierToken
,
ClosedParToken
,
EndOfStringToken
}},
{
"key in ( value1, value2 )"
,
[]
Token
{
I
dentifierToken
,
InToken
,
OpenParToken
,
IdentifierToken
,
CommaToken
,
IdentifierToken
,
ClosedParToken
,
EndOfStringToken
}},
{
"key"
,
[]
Token
{
I
dentifierToken
,
EndOfStringToken
}},
{
"()"
,
[]
Token
{
O
penParToken
,
ClosedParToken
,
EndOfStringToken
}},
{
""
,
[]
Token
{
E
ndOfStringToken
}},
{
"x in (),y"
,
[]
Token
{
I
dentifierToken
,
InToken
,
OpenParToken
,
ClosedParToken
,
CommaToken
,
IdentifierToken
,
EndOfStringToken
}},
{
"== != (), = notin"
,
[]
Token
{
DoubleEqualsToken
,
NotEqualsToken
,
OpenParToken
,
ClosedParToken
,
CommaToken
,
EqualsToken
,
NotInToken
,
EndOfStringToken
}},
}
for
_
,
v
:=
range
testcases
{
p
:=
&
Parser
{
l
:
&
Lexer
{
s
:
v
.
s
,
pos
:
0
},
position
:
0
}
...
...
@@ -393,7 +393,7 @@ func TestParserLookahead(t *testing.T) {
token
,
lit
:=
p
.
lookahead
(
KeyAndOperator
)
token2
,
lit2
:=
p
.
consume
(
KeyAndOperator
)
if
token
==
E
OS
{
if
token
==
E
ndOfStringToken
{
break
}
if
token
!=
token2
||
lit
!=
lit2
{
...
...
@@ -597,6 +597,7 @@ func getRequirement(key string, op Operator, vals util.StringSet, t *testing.T)
req
,
err
:=
NewRequirement
(
key
,
op
,
vals
)
if
err
!=
nil
{
t
.
Errorf
(
"NewRequirement(%v, %v, %v) resulted in error:%v"
,
key
,
op
,
vals
,
err
)
return
Requirement
{}
}
return
*
req
}
pkg/registry/generic/registry_test.go
View file @
75f2efb5
...
...
@@ -73,7 +73,7 @@ func TestSelectionPredicate(t *testing.T) {
}
for
name
,
item
:=
range
table
{
parsedLabel
,
err
:=
labels
.
Parse
Selector
(
item
.
labelSelector
)
parsedLabel
,
err
:=
labels
.
Parse
(
item
.
labelSelector
)
if
err
!=
nil
{
panic
(
err
)
}
...
...
pkg/registry/pod/etcd/etcd_test.go
View file @
75f2efb5
...
...
@@ -351,7 +351,7 @@ func TestListPodListSelection(t *testing.T) {
}
for
index
,
item
:=
range
table
{
label
,
err
:=
labels
.
Parse
Selector
(
item
.
label
)
label
,
err
:=
labels
.
Parse
(
item
.
label
)
if
err
!=
nil
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
continue
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment