2015-08-29 12:41:20 +00:00
|
|
|
package secondly
|
2015-08-29 12:25:47 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"reflect"
|
|
|
|
)
|
|
|
|
|
|
|
|
type field struct {
|
2015-08-29 14:32:39 +00:00
|
|
|
Path string `json:"path"`
|
|
|
|
Name string `json:"name"`
|
2015-08-29 12:25:47 +00:00
|
|
|
Kind string `json:"kind"`
|
|
|
|
Val interface{} `json:"val"`
|
|
|
|
}
|
|
|
|
|
2015-08-29 14:32:39 +00:00
|
|
|
func extractFields(st interface{}, path string) []field {
|
|
|
|
var res []field
|
2015-08-29 13:23:53 +00:00
|
|
|
|
2015-08-29 12:25:47 +00:00
|
|
|
val := reflect.ValueOf(st)
|
2015-08-29 13:23:53 +00:00
|
|
|
if val.Kind() == reflect.Ptr {
|
|
|
|
val = reflect.Indirect(val)
|
|
|
|
}
|
|
|
|
typ := val.Type()
|
|
|
|
|
2015-08-29 12:25:47 +00:00
|
|
|
for i := 0; i < val.NumField(); i++ {
|
|
|
|
ftyp := typ.Field(i)
|
|
|
|
fval := val.Field(i)
|
|
|
|
|
|
|
|
switch kind := fval.Kind(); kind {
|
|
|
|
case reflect.Struct:
|
|
|
|
sub := extractFields(fval.Interface(), ftyp.Name+".")
|
2015-08-29 14:32:39 +00:00
|
|
|
res = append(res, sub...)
|
2015-08-29 12:25:47 +00:00
|
|
|
case reflect.Bool,
|
|
|
|
reflect.Int,
|
|
|
|
reflect.Int8,
|
|
|
|
reflect.Int16,
|
|
|
|
reflect.Int32,
|
|
|
|
reflect.Int64,
|
|
|
|
reflect.Uint,
|
|
|
|
reflect.Uint8,
|
|
|
|
reflect.Uint16,
|
|
|
|
reflect.Uint32,
|
|
|
|
reflect.Uint64,
|
|
|
|
reflect.Float32,
|
|
|
|
reflect.Float64,
|
|
|
|
reflect.String:
|
2015-08-29 14:32:39 +00:00
|
|
|
res = append(res, field{
|
|
|
|
Path: path + ftyp.Name,
|
|
|
|
Name: ftyp.Name,
|
2015-08-29 12:25:47 +00:00
|
|
|
Kind: kind.String(),
|
|
|
|
Val: fval.Interface(),
|
2015-08-29 14:32:39 +00:00
|
|
|
})
|
2015-08-29 12:25:47 +00:00
|
|
|
default:
|
|
|
|
log.Printf("Field type %q not supported for field %q\n", kind, path+ftyp.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
2015-08-29 12:25:59 +00:00
|
|
|
|
|
|
|
func diff(a, b interface{}) map[string][]interface{} {
|
2015-08-29 14:32:39 +00:00
|
|
|
af := indexFields(extractFields(a, ""))
|
|
|
|
bf := indexFields(extractFields(b, ""))
|
2015-08-29 12:25:59 +00:00
|
|
|
|
|
|
|
res := make(map[string][]interface{})
|
|
|
|
for name, f := range af {
|
|
|
|
if bf[name].Val != f.Val {
|
|
|
|
res[name] = []interface{}{f.Val, bf[name].Val}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
2015-08-29 14:32:39 +00:00
|
|
|
|
|
|
|
func indexFields(fields []field) map[string]field {
|
|
|
|
res := make(map[string]field)
|
|
|
|
for _, f := range fields {
|
|
|
|
res[f.Path] = f
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|