1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 15:47:14 +01:00
Files
Sid Shukla 345e855c90 Update Nutanix terraform version to 1.5.0 for installer
The updated versions include bugfixes for various components.
2022-05-23 11:52:08 +02:00

204 lines
4.2 KiB
Go

package jsonpath
import (
"context"
"fmt"
"strconv"
"github.com/PaesslerAG/gval"
)
//plainSelector evaluate exactly one result
type plainSelector func(c context.Context, r, v interface{}) (interface{}, error)
//ambiguousSelector evaluate wildcard
type ambiguousSelector func(c context.Context, r, v interface{}, match ambiguousMatcher)
//@
func currentElementSelector() plainSelector {
return func(c context.Context, r, v interface{}) (interface{}, error) {
return c.Value(currentElement{}), nil
}
}
type currentElement struct{}
func currentContext(c context.Context, v interface{}) context.Context {
return context.WithValue(c, currentElement{}, v)
}
//.x, [x]
func directSelector(key gval.Evaluable) plainSelector {
return func(c context.Context, r, v interface{}) (interface{}, error) {
e, _, err := selectValue(c, key, r, v)
if err != nil {
return nil, err
}
return e, nil
}
}
// * / [*]
func starSelector() ambiguousSelector {
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
visitAll(v, func(key string, val interface{}) { match(key, val) })
}
}
// [x, ...]
func multiSelector(keys []gval.Evaluable) ambiguousSelector {
if len(keys) == 0 {
return starSelector()
}
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
for _, k := range keys {
e, wildcard, err := selectValue(c, k, r, v)
if err != nil {
continue
}
match(wildcard, e)
}
}
}
func selectValue(c context.Context, key gval.Evaluable, r, v interface{}) (value interface{}, jkey string, err error) {
c = currentContext(c, v)
switch o := v.(type) {
case []interface{}:
i, err := key.EvalInt(c, r)
if err != nil {
return nil, "", fmt.Errorf("could not select value, invalid key: %s", err)
}
if i < 0 || i >= len(o) {
return nil, "", fmt.Errorf("index %d out of bounds", i)
}
return o[i], strconv.Itoa(i), nil
case map[string]interface{}:
k, err := key.EvalString(c, r)
if err != nil {
return nil, "", fmt.Errorf("could not select value, invalid key: %s", err)
}
if r, ok := o[k]; ok {
return r, k, nil
}
return nil, "", fmt.Errorf("unknown key %s", k)
default:
return nil, "", fmt.Errorf("unsupported value type %T for select, expected map[string]interface{} or []interface{}", o)
}
}
//..
func mapperSelector() ambiguousSelector {
return mapper
}
func mapper(c context.Context, r, v interface{}, match ambiguousMatcher) {
match([]interface{}{}, v)
visitAll(v, func(wildcard string, v interface{}) {
mapper(c, r, v, func(key interface{}, v interface{}) {
match(append([]interface{}{wildcard}, key.([]interface{})...), v)
})
})
}
func visitAll(v interface{}, visit func(key string, v interface{})) {
switch v := v.(type) {
case []interface{}:
for i, e := range v {
k := strconv.Itoa(i)
visit(k, e)
}
case map[string]interface{}:
for k, e := range v {
visit(k, e)
}
}
}
//[? ]
func filterSelector(filter gval.Evaluable) ambiguousSelector {
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
visitAll(v, func(wildcard string, v interface{}) {
condition, err := filter.EvalBool(currentContext(c, v), r)
if err != nil {
return
}
if condition {
match(wildcard, v)
}
})
}
}
//[::]
func rangeSelector(min, max, step gval.Evaluable) ambiguousSelector {
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
cs, ok := v.([]interface{})
if !ok {
return
}
c = currentContext(c, v)
min, err := min.EvalInt(c, r)
if err != nil {
return
}
max, err := max.EvalInt(c, r)
if err != nil {
return
}
step, err := step.EvalInt(c, r)
if err != nil {
return
}
if min > max {
return
}
n := len(cs)
min = negmax(min, n)
max = negmax(max, n)
if step == 0 {
step = 1
}
if step > 0 {
for i := min; i < max; i += step {
match(strconv.Itoa(i), cs[i])
}
} else {
for i := max - 1; i >= min; i += step {
match(strconv.Itoa(i), cs[i])
}
}
}
}
func negmax(n, max int) int {
if n < 0 {
n = max + n
if n < 0 {
n = 0
}
} else if n > max {
return max
}
return n
}
// ()
func newScript(script gval.Evaluable) plainSelector {
return func(c context.Context, r, v interface{}) (interface{}, error) {
return script(currentContext(c, v), r)
}
}