From a7fa2aef8deb40eb1d159dbf7f0d8ea7d6d10dac Mon Sep 17 00:00:00 2001 From: Xing Zhou Date: Tue, 20 Dec 2016 17:45:37 +0800 Subject: [PATCH] Added bool type support for jsonpath. Added keywords "true" and "false" for supporting bool type in jsonpath. --- .../k8s.io/client-go/util/jsonpath/jsonpath.go | 11 +++++++++++ .../client-go/util/jsonpath/jsonpath_test.go | 18 +++++++++++++----- .../src/k8s.io/client-go/util/jsonpath/node.go | 16 ++++++++++++++++ .../k8s.io/client-go/util/jsonpath/parser.go | 18 +++++++++++++++++- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go index 7158de7c70b..decbec0bbd6 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go @@ -148,6 +148,8 @@ func (j *JSONPath) walk(value []reflect.Value, node Node) ([]reflect.Value, erro return j.evalFilter(value, node) case *IntNode: return j.evalInt(value, node) + case *BoolNode: + return j.evalBool(value, node) case *FloatNode: return j.evalFloat(value, node) case *WildcardNode: @@ -181,6 +183,15 @@ func (j *JSONPath) evalFloat(input []reflect.Value, node *FloatNode) ([]reflect. return result, nil } +// evalBool evaluates BoolNode +func (j *JSONPath) evalBool(input []reflect.Value, node *BoolNode) ([]reflect.Value, error) { + result := make([]reflect.Value, len(input)) + for i := range input { + result[i] = reflect.ValueOf(node.Value) + } + return result, nil +} + // evalList evaluates ListNode func (j *JSONPath) evalList(value []reflect.Value, node *ListNode) ([]reflect.Value, error) { var err error diff --git a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go index 72d547104bc..3f38aa839da 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go @@ -113,13 +113,14 @@ func (b book) String() string { type bicycle struct { Color string Price float32 + IsNew bool } type empName string type job string type store struct { Book []book - Bicycle bicycle + Bicycle []bicycle Name string Labels map[string]int Employees map[empName]job @@ -134,7 +135,10 @@ func TestStructInput(t *testing.T) { {"fiction", "Evelyn Waugh", "Sword of Honour", 12.99}, {"fiction", "Herman Melville", "Moby Dick", 8.99}, }, - Bicycle: bicycle{"red", 19.95}, + Bicycle: []bicycle{ + {"red", 19.95, true}, + {"green", 20.01, false}, + }, Labels: map[string]int{ "engieer": 10, "web/html": 15, @@ -158,14 +162,15 @@ func TestStructInput(t *testing.T) { {"dict/", "{$.Employees.jason}", storeData, "manager"}, {"dict/", "{$.Employees.dan}", storeData, "clerk"}, {"dict-", "{.Labels.k8s-app}", storeData, "20"}, - {"nest", "{.Bicycle.Color}", storeData, "red"}, + {"nest", "{.Bicycle[*].Color}", storeData, "red green"}, {"allarray", "{.Book[*].Author}", storeData, "Nigel Rees Evelyn Waugh Herman Melville"}, - {"allfileds", "{.Bicycle.*}", storeData, "red 19.95"}, - {"recurfileds", "{..Price}", storeData, "8.95 12.99 8.99 19.95"}, + {"allfileds", "{.Bicycle.*}", storeData, "{red 19.95 true} {green 20.01 false}"}, + {"recurfileds", "{..Price}", storeData, "8.95 12.99 8.99 19.95 20.01"}, {"lastarray", "{.Book[-1:]}", storeData, "{Category: fiction, Author: Herman Melville, Title: Moby Dick, Price: 8.99}"}, {"recurarray", "{..Book[2]}", storeData, "{Category: fiction, Author: Herman Melville, Title: Moby Dick, Price: 8.99}"}, + {"bool", "{.Bicycle[?(@.IsNew==true)]}", storeData, "{red 19.95 true}"}, } testJSONPath(storeTests, false, t) @@ -220,6 +225,7 @@ func TestKubernetes(t *testing.T) { }, "status":{ "capacity":{"cpu":"4"}, + "ready": true, "addresses":[{"type": "LegacyHostIP", "address":"127.0.0.1"}] } }, @@ -233,6 +239,7 @@ func TestKubernetes(t *testing.T) { }, "status":{ "capacity":{"cpu":"8"}, + "ready": false, "addresses":[ {"type": "LegacyHostIP", "address":"127.0.0.2"}, {"type": "another", "address":"127.0.0.3"} @@ -272,6 +279,7 @@ func TestKubernetes(t *testing.T) { {"user password", `{.users[?(@.name=="e2e")].user.password}`, &nodesData, "secret"}, {"hostname", `{.items[0].metadata.labels.kubernetes\.io/hostname}`, &nodesData, "127.0.0.1"}, {"hostname filter", `{.items[?(@.metadata.labels.kubernetes\.io/hostname=="127.0.0.1")].kind}`, &nodesData, "None"}, + {"bool item", `{.items[?(@..ready==true)].metadata.name}`, &nodesData, "127.0.0.1"}, } testJSONPath(nodesTests, false, t) diff --git a/staging/src/k8s.io/client-go/util/jsonpath/node.go b/staging/src/k8s.io/client-go/util/jsonpath/node.go index f0a27853d84..be74c4fe244 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/node.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/node.go @@ -42,6 +42,7 @@ const ( NodeWildcard NodeRecursive NodeUnion + NodeBool ) var NodeTypeName = map[NodeType]string{ @@ -56,6 +57,7 @@ var NodeTypeName = map[NodeType]string{ NodeWildcard: "NodeWildcard", NodeRecursive: "NodeRecursive", NodeUnion: "NodeUnion", + NodeBool: "NodeBool", } type Node interface { @@ -237,3 +239,17 @@ func newUnion(nodes []*ListNode) *UnionNode { func (u *UnionNode) String() string { return fmt.Sprintf("%s", u.Type()) } + +// BoolNode holds bool value +type BoolNode struct { + NodeType + Value bool +} + +func newBool(value bool) *BoolNode { + return &BoolNode{NodeType: NodeBool, Value: value} +} + +func (b *BoolNode) String() string { + return fmt.Sprintf("%s: %t", b.Type(), b.Value) +} diff --git a/staging/src/k8s.io/client-go/util/jsonpath/parser.go b/staging/src/k8s.io/client-go/util/jsonpath/parser.go index 7dc38d31fc3..39782afc6ea 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/parser.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/parser.go @@ -194,7 +194,18 @@ func (p *Parser) parseIdentifier(cur *ListNode) error { } } value := p.consumeText() - cur.append(newIdentifier(value)) + + if isBool(value) { + v, err := strconv.ParseBool(value) + if err != nil { + return fmt.Errorf("can not parse bool '%s': %s", value, err.Error()) + } + + cur.append(newBool(v)) + } else { + cur.append(newIdentifier(value)) + } + return p.parseInsideAction(cur) } @@ -431,3 +442,8 @@ func isEndOfLine(r rune) bool { func isAlphaNumeric(r rune) bool { return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) } + +// isBool reports whether s is a boolean value. +func isBool(s string) bool { + return s == "true" || s == "false" +}