Merge pull request #2803 from ikaven1024/pr-improve-decodeValue
improve decodeValue for Lua
This commit is contained in:
commit
e7c9cd0ccf
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
lua "github.com/yuin/gopher-lua"
|
lua "github.com/yuin/gopher-lua"
|
||||||
|
@ -50,7 +51,10 @@ func (vm VM) GetReplicas(obj *unstructured.Unstructured, script string) (replica
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]lua.LValue, 1)
|
args := make([]lua.LValue, 1)
|
||||||
args[0] = decodeValue(l, obj.Object)
|
args[0], err = decodeValue(l, obj.Object)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: f, NRet: 2, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: f, NRet: 2, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
|
@ -108,8 +112,14 @@ func (vm VM) ReviseReplica(object *unstructured.Unstructured, replica int64, scr
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]lua.LValue, 2)
|
args := make([]lua.LValue, 2)
|
||||||
args[0] = decodeValue(l, object.Object)
|
args[0], err = decodeValue(l, object.Object)
|
||||||
args[1] = decodeValue(l, replica)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args[1], err = decodeValue(l, replica)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: reviseReplicaLuaFunc, NRet: 1, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: reviseReplicaLuaFunc, NRet: 1, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -178,8 +188,14 @@ func (vm VM) Retain(desired *unstructured.Unstructured, observed *unstructured.U
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]lua.LValue, 2)
|
args := make([]lua.LValue, 2)
|
||||||
args[0] = decodeValue(l, desired.Object)
|
args[0], err = decodeValue(l, desired.Object)
|
||||||
args[1] = decodeValue(l, observed.Object)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args[1], err = decodeValue(l, observed.Object)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: retainLuaFunc, NRet: 1, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: retainLuaFunc, NRet: 1, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -225,8 +241,14 @@ func (vm VM) AggregateStatus(object *unstructured.Unstructured, item []map[strin
|
||||||
return nil, fmt.Errorf("can't get function AggregateStatus pleace check the function ")
|
return nil, fmt.Errorf("can't get function AggregateStatus pleace check the function ")
|
||||||
}
|
}
|
||||||
args := make([]lua.LValue, 2)
|
args := make([]lua.LValue, 2)
|
||||||
args[0] = decodeValue(l, object.Object)
|
args[0], err = decodeValue(l, object.Object)
|
||||||
args[1] = decodeValue(l, item)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args[1], err = decodeValue(l, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -272,7 +294,10 @@ func (vm VM) InterpretHealth(object *unstructured.Unstructured, script string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]lua.LValue, 1)
|
args := make([]lua.LValue, 1)
|
||||||
args[0] = decodeValue(l, object.Object)
|
args[0], err = decodeValue(l, object.Object)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -315,7 +340,10 @@ func (vm VM) ReflectStatus(object *unstructured.Unstructured, script string) (st
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]lua.LValue, 1)
|
args := make([]lua.LValue, 1)
|
||||||
args[0] = decodeValue(l, object.Object)
|
args[0], err = decodeValue(l, object.Object)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: f, NRet: 2, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: f, NRet: 2, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -376,7 +404,10 @@ func (vm VM) GetDependencies(object *unstructured.Unstructured, script string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]lua.LValue, 1)
|
args := make([]lua.LValue, 1)
|
||||||
args[0] = decodeValue(l, object.Object)
|
args[0], err = decodeValue(l, object.Object)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
|
err = l.CallByParam(lua.P{Fn: f, NRet: 1, Protect: true}, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -398,46 +429,64 @@ func (vm VM) GetDependencies(object *unstructured.Unstructured, script string) (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Took logic from the link below and added the int, int32, and int64 types since the value would have type int64
|
// nolint:gocyclo
|
||||||
// while actually running in the controller and it was not reproducible through testing.
|
func decodeValue(L *lua.LState, value interface{}) (lua.LValue, error) {
|
||||||
// https://github.com/layeh/gopher-json/blob/97fed8db84274c421dbfffbb28ec859901556b97/json.go#L154
|
// We handle simple type without json for better performance.
|
||||||
func decodeValue(L *lua.LState, value interface{}) lua.LValue {
|
|
||||||
switch converted := value.(type) {
|
switch converted := value.(type) {
|
||||||
case bool:
|
|
||||||
return lua.LBool(converted)
|
|
||||||
case float64:
|
|
||||||
return lua.LNumber(converted)
|
|
||||||
case string:
|
|
||||||
return lua.LString(converted)
|
|
||||||
case json.Number:
|
|
||||||
return lua.LString(converted)
|
|
||||||
case int:
|
|
||||||
return lua.LNumber(converted)
|
|
||||||
case int32:
|
|
||||||
return lua.LNumber(converted)
|
|
||||||
case int64:
|
|
||||||
return lua.LNumber(converted)
|
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
arr := L.CreateTable(len(converted), 0)
|
arr := L.CreateTable(len(converted), 0)
|
||||||
for _, item := range converted {
|
for _, item := range converted {
|
||||||
arr.Append(decodeValue(L, item))
|
v, err := decodeValue(L, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return arr
|
arr.Append(v)
|
||||||
case []map[string]interface{}:
|
|
||||||
arr := L.CreateTable(len(converted), 0)
|
|
||||||
for _, item := range converted {
|
|
||||||
arr.Append(decodeValue(L, item))
|
|
||||||
}
|
}
|
||||||
return arr
|
return arr, nil
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
tbl := L.CreateTable(0, len(converted))
|
tbl := L.CreateTable(0, len(converted))
|
||||||
for key, item := range converted {
|
for key, item := range converted {
|
||||||
tbl.RawSetH(lua.LString(key), decodeValue(L, item))
|
v, err := decodeValue(L, item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return tbl
|
tbl.RawSetString(key, v)
|
||||||
|
}
|
||||||
|
return tbl, nil
|
||||||
case nil:
|
case nil:
|
||||||
return lua.LNil
|
return lua.LNil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return lua.LNil
|
v := reflect.ValueOf(value)
|
||||||
|
switch {
|
||||||
|
case v.CanInt():
|
||||||
|
return lua.LNumber(v.Int()), nil
|
||||||
|
case v.CanUint():
|
||||||
|
return lua.LNumber(v.Uint()), nil
|
||||||
|
case v.CanFloat():
|
||||||
|
return lua.LNumber(v.Float()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := v.Type(); t.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return lua.LString(v.String()), nil
|
||||||
|
case reflect.Bool:
|
||||||
|
return lua.LBool(v.Bool()), nil
|
||||||
|
case reflect.Pointer:
|
||||||
|
if v.IsNil() {
|
||||||
|
return lua.LNil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other types can't be handled, ask for help from json
|
||||||
|
data, err := json.Marshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("json Marshal obj %#v error: %v", value, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lv, err := luajson.Decode(L, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("lua Decode obj %#v error: %v", value, err)
|
||||||
|
}
|
||||||
|
return lv, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,14 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
lua "github.com/yuin/gopher-lua"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
|
||||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||||
"github.com/karmada-io/karmada/pkg/util/helper"
|
"github.com/karmada-io/karmada/pkg/util/helper"
|
||||||
|
@ -474,3 +476,174 @@ func TestGetDeployPodDependencies(t *testing.T) {
|
||||||
t.Logf("res %v", res)
|
t.Logf("res %v", res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_decodeValue(t *testing.T) {
|
||||||
|
L := lua.NewState()
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want lua.LValue
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil",
|
||||||
|
args: args{
|
||||||
|
value: nil,
|
||||||
|
},
|
||||||
|
want: lua.LNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nil pointer",
|
||||||
|
args: args{
|
||||||
|
value: (*struct{})(nil),
|
||||||
|
},
|
||||||
|
want: lua.LNil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "int pointer",
|
||||||
|
args: args{
|
||||||
|
value: pointer.Int(1),
|
||||||
|
},
|
||||||
|
want: lua.LNumber(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "int",
|
||||||
|
args: args{
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
want: lua.LNumber(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "uint",
|
||||||
|
args: args{
|
||||||
|
value: uint(1),
|
||||||
|
},
|
||||||
|
want: lua.LNumber(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "float",
|
||||||
|
args: args{
|
||||||
|
value: 1.0,
|
||||||
|
},
|
||||||
|
want: lua.LNumber(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bool",
|
||||||
|
args: args{
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
want: lua.LBool(true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "string",
|
||||||
|
args: args{
|
||||||
|
value: "foo",
|
||||||
|
},
|
||||||
|
want: lua.LString("foo"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "json number",
|
||||||
|
args: args{
|
||||||
|
value: json.Number("1"),
|
||||||
|
},
|
||||||
|
want: lua.LString("1"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "slice",
|
||||||
|
args: args{
|
||||||
|
value: []string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
want: func() lua.LValue {
|
||||||
|
v := L.CreateTable(2, 0)
|
||||||
|
v.Append(lua.LString("foo"))
|
||||||
|
v.Append(lua.LString("bar"))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "slice pointer",
|
||||||
|
args: args{
|
||||||
|
value: &[]string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
want: func() lua.LValue {
|
||||||
|
v := L.CreateTable(2, 0)
|
||||||
|
v.Append(lua.LString("foo"))
|
||||||
|
v.Append(lua.LString("bar"))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "struct",
|
||||||
|
args: args{
|
||||||
|
value: struct {
|
||||||
|
Foo string
|
||||||
|
}{
|
||||||
|
Foo: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: func() lua.LValue {
|
||||||
|
v := L.CreateTable(0, 1)
|
||||||
|
v.RawSetString("Foo", lua.LString("foo"))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "struct pointer",
|
||||||
|
args: args{
|
||||||
|
value: &struct {
|
||||||
|
Foo string
|
||||||
|
}{
|
||||||
|
Foo: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: func() lua.LValue {
|
||||||
|
v := L.CreateTable(0, 1)
|
||||||
|
v.RawSetString("Foo", lua.LString("foo"))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "[]interface{}",
|
||||||
|
args: args{
|
||||||
|
value: []interface{}{1, 2},
|
||||||
|
},
|
||||||
|
want: func() lua.LValue {
|
||||||
|
v := L.CreateTable(2, 0)
|
||||||
|
v.Append(lua.LNumber(1))
|
||||||
|
v.Append(lua.LNumber(2))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "map[string]interface{}",
|
||||||
|
args: args{
|
||||||
|
value: map[string]interface{}{
|
||||||
|
"foo": "foo1",
|
||||||
|
"bar": "bar1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: func() lua.LValue {
|
||||||
|
v := L.CreateTable(0, 2)
|
||||||
|
v.RawSetString("foo", lua.LString("foo1"))
|
||||||
|
v.RawSetString("bar", lua.LString("bar1"))
|
||||||
|
return v
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := decodeValue(L, tt.args.value)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("decodeValue() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("decodeValue() got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue