mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-26 15:12:06 +00:00
Fixed bug where jsonpath expression with a nested range does not process subsequent nodes
Kubernetes-commit: 852e661f3dd0f7be9b9b1469316d9947c4b5a5c0
This commit is contained in:
parent
386829fa6b
commit
1ade84933e
@ -29,12 +29,12 @@ import (
|
||||
type JSONPath struct {
|
||||
name string
|
||||
parser *Parser
|
||||
stack [][]reflect.Value // push and pop values in different scopes
|
||||
cur []reflect.Value // current scope values
|
||||
beginRange int
|
||||
inRange int
|
||||
endRange int
|
||||
|
||||
lastEndNode *Node
|
||||
|
||||
allowMissingKeys bool
|
||||
}
|
||||
|
||||
@ -81,12 +81,12 @@ func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) {
|
||||
return nil, fmt.Errorf("%s is an incomplete jsonpath template", j.name)
|
||||
}
|
||||
|
||||
j.cur = []reflect.Value{reflect.ValueOf(data)}
|
||||
cur := []reflect.Value{reflect.ValueOf(data)}
|
||||
nodes := j.parser.Root.Nodes
|
||||
fullResult := [][]reflect.Value{}
|
||||
for i := 0; i < len(nodes); i++ {
|
||||
node := nodes[i]
|
||||
results, err := j.walk(j.cur, node)
|
||||
results, err := j.walk(cur, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -94,24 +94,31 @@ func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) {
|
||||
// encounter an end node, break the current block
|
||||
if j.endRange > 0 && j.endRange <= j.inRange {
|
||||
j.endRange--
|
||||
j.lastEndNode = &nodes[i]
|
||||
break
|
||||
}
|
||||
// encounter a range node, start a range loop
|
||||
if j.beginRange > 0 {
|
||||
j.beginRange--
|
||||
j.inRange++
|
||||
for k, value := range results {
|
||||
for _, value := range results {
|
||||
j.parser.Root.Nodes = nodes[i+1:]
|
||||
if k == len(results)-1 {
|
||||
j.inRange--
|
||||
}
|
||||
nextResults, err := j.FindResults(value.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fullResult = append(fullResult, nextResults...)
|
||||
}
|
||||
break
|
||||
j.inRange--
|
||||
|
||||
// Fast forward to resume processing after the most recent end node that was encountered
|
||||
for k := i + 1; k < len(nodes); k++ {
|
||||
if &nodes[k] == j.lastEndNode {
|
||||
i = k
|
||||
break
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
fullResult = append(fullResult, results)
|
||||
}
|
||||
@ -212,17 +219,11 @@ func (j *JSONPath) evalIdentifier(input []reflect.Value, node *IdentifierNode) (
|
||||
results := []reflect.Value{}
|
||||
switch node.Name {
|
||||
case "range":
|
||||
j.stack = append(j.stack, j.cur)
|
||||
j.beginRange++
|
||||
results = input
|
||||
case "end":
|
||||
if j.endRange < j.inRange { // inside a loop, break the current block
|
||||
if j.inRange > 0 {
|
||||
j.endRange++
|
||||
break
|
||||
}
|
||||
// the loop is about to end, pop value and continue the following execution
|
||||
if len(j.stack) > 0 {
|
||||
j.cur, j.stack = j.stack[len(j.stack)-1], j.stack[:len(j.stack)-1]
|
||||
} else {
|
||||
return results, fmt.Errorf("not in range, nothing to end")
|
||||
}
|
||||
|
@ -298,6 +298,133 @@ func TestKubernetes(t *testing.T) {
|
||||
testJSONPathSortOutput(randomPrintOrderTests, t)
|
||||
}
|
||||
|
||||
func TestNestedRanges(t *testing.T) {
|
||||
var input = []byte(`{
|
||||
"items": [
|
||||
{
|
||||
"metadata": {
|
||||
"name": "pod1"
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "foo",
|
||||
"another": [
|
||||
{ "name": "value1" },
|
||||
{ "name": "value2" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bar",
|
||||
"another": [
|
||||
{ "name": "value1" },
|
||||
{ "name": "value2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "pod2"
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "baz",
|
||||
"another": [
|
||||
{ "name": "value1" },
|
||||
{ "name": "value2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}`)
|
||||
var data interface{}
|
||||
err := json.Unmarshal(input, &data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
testJSONPath(
|
||||
[]jsonpathTest{
|
||||
{
|
||||
"nested range with a trailing newline",
|
||||
`{range .items[*]}` +
|
||||
`{.metadata.name}` +
|
||||
`{":"}` +
|
||||
`{range @.spec.containers[*]}` +
|
||||
`{.name}` +
|
||||
`{","}` +
|
||||
`{end}` +
|
||||
`{"+"}` +
|
||||
`{end}`,
|
||||
data,
|
||||
"pod1:foo,bar,+pod2:baz,+",
|
||||
false,
|
||||
},
|
||||
},
|
||||
false,
|
||||
t,
|
||||
)
|
||||
|
||||
testJSONPath(
|
||||
[]jsonpathTest{
|
||||
{
|
||||
"nested range with a trailing character within another nested range with a trailing newline",
|
||||
`{range .items[*]}` +
|
||||
`{.metadata.name}` +
|
||||
`{"~"}` +
|
||||
`{range @.spec.containers[*]}` +
|
||||
`{.name}` +
|
||||
`{":"}` +
|
||||
`{range @.another[*]}` +
|
||||
`{.name}` +
|
||||
`{","}` +
|
||||
`{end}` +
|
||||
`{"+"}` +
|
||||
`{end}` +
|
||||
`{"#"}` +
|
||||
`{end}`,
|
||||
data,
|
||||
"pod1~foo:value1,value2,+bar:value1,value2,+#pod2~baz:value1,value2,+#",
|
||||
false,
|
||||
},
|
||||
},
|
||||
false,
|
||||
t,
|
||||
)
|
||||
|
||||
testJSONPath(
|
||||
[]jsonpathTest{
|
||||
{
|
||||
"two nested ranges at the same level with a trailing newline",
|
||||
`{range .items[*]}` +
|
||||
`{.metadata.name}` +
|
||||
`{"\t"}` +
|
||||
`{range @.spec.containers[*]}` +
|
||||
`{.name}` +
|
||||
`{" "}` +
|
||||
`{end}` +
|
||||
`{"\t"}` +
|
||||
`{range @.spec.containers[*]}` +
|
||||
`{.name}` +
|
||||
`{" "}` +
|
||||
`{end}` +
|
||||
`{"\n"}` +
|
||||
`{end}`,
|
||||
data,
|
||||
"pod1\tfoo bar \tfoo bar \npod2\tbaz \tbaz \n",
|
||||
false,
|
||||
},
|
||||
},
|
||||
false,
|
||||
t,
|
||||
)
|
||||
}
|
||||
|
||||
func TestFilterPartialMatchesSometimesMissingAnnotations(t *testing.T) {
|
||||
// for https://issues.k8s.io/45546
|
||||
var input = []byte(`{
|
||||
|
Loading…
Reference in New Issue
Block a user