435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
332 lines
8.1 KiB
Go
332 lines
8.1 KiB
Go
package util
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/url"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// change instance=["a", "b"]
|
|
// to instance.1="a" instance.2="b"
|
|
func FlattenFn(fieldName string, field reflect.Value, values *url.Values) {
|
|
l := field.Len()
|
|
if l > 0 {
|
|
for i := 0; i < l; i++ {
|
|
str := field.Index(i).String()
|
|
values.Set(fieldName+"."+strconv.Itoa(i+1), str)
|
|
}
|
|
}
|
|
}
|
|
|
|
func Underline2Dot(name string) string {
|
|
return strings.Replace(name, "_", ".", -1)
|
|
}
|
|
|
|
//ConvertToQueryValues converts the struct to url.Values
|
|
func ConvertToQueryValues(ifc interface{}) url.Values {
|
|
values := url.Values{}
|
|
SetQueryValues(ifc, &values)
|
|
return values
|
|
}
|
|
|
|
//SetQueryValues sets the struct to existing url.Values following ECS encoding rules
|
|
func SetQueryValues(ifc interface{}, values *url.Values) {
|
|
setQueryValues(ifc, values, "")
|
|
}
|
|
|
|
func SetQueryValueByFlattenMethod(ifc interface{}, values *url.Values) {
|
|
setQueryValuesByFlattenMethod(ifc, values, "")
|
|
}
|
|
|
|
func setQueryValues(i interface{}, values *url.Values, prefix string) {
|
|
// add to support url.Values
|
|
mapValues, ok := i.(url.Values)
|
|
if ok {
|
|
for k, _ := range mapValues {
|
|
values.Set(k, mapValues.Get(k))
|
|
}
|
|
return
|
|
}
|
|
|
|
elem := reflect.ValueOf(i)
|
|
if elem.Kind() == reflect.Ptr {
|
|
elem = elem.Elem()
|
|
}
|
|
elemType := elem.Type()
|
|
for i := 0; i < elem.NumField(); i++ {
|
|
|
|
fieldName := elemType.Field(i).Name
|
|
anonymous := elemType.Field(i).Anonymous
|
|
tag := elemType.Field(i).Tag.Get("query")
|
|
argName := elemType.Field(i).Tag.Get("ArgName")
|
|
field := elem.Field(i)
|
|
// TODO Use Tag for validation
|
|
// tag := typ.Field(i).Tag.Get("tagname")
|
|
kind := field.Kind()
|
|
isPtr := false
|
|
if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
|
|
continue
|
|
}
|
|
if kind == reflect.Ptr {
|
|
field = field.Elem()
|
|
kind = field.Kind()
|
|
isPtr = true
|
|
}
|
|
var value string
|
|
//switch field.Interface().(type) {
|
|
switch kind {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
i := field.Int()
|
|
if i != 0 || isPtr {
|
|
value = strconv.FormatInt(i, 10)
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
i := field.Uint()
|
|
if i != 0 || isPtr {
|
|
value = strconv.FormatUint(i, 10)
|
|
}
|
|
case reflect.Float32:
|
|
value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
|
|
case reflect.Float64:
|
|
value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
|
|
case reflect.Bool:
|
|
value = strconv.FormatBool(field.Bool())
|
|
case reflect.String:
|
|
value = field.String()
|
|
case reflect.Map:
|
|
ifc := field.Interface()
|
|
m := ifc.(map[string]string)
|
|
if m != nil {
|
|
j := 0
|
|
for k, v := range m {
|
|
j++
|
|
keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
|
|
values.Set(keyName, k)
|
|
valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
|
|
values.Set(valueName, v)
|
|
}
|
|
}
|
|
case reflect.Slice:
|
|
switch field.Type().Elem().Kind() {
|
|
case reflect.Uint8:
|
|
value = string(field.Bytes())
|
|
case reflect.String:
|
|
l := field.Len()
|
|
if l > 0 {
|
|
if tag == "list" {
|
|
name := argName
|
|
if argName == "" {
|
|
name = fieldName
|
|
}
|
|
for i := 0; i < l; i++ {
|
|
valueName := fmt.Sprintf("%s.%d", name, (i + 1))
|
|
values.Set(valueName, field.Index(i).String())
|
|
}
|
|
} else {
|
|
strArray := make([]string, l)
|
|
for i := 0; i < l; i++ {
|
|
strArray[i] = field.Index(i).String()
|
|
}
|
|
bytes, err := json.Marshal(strArray)
|
|
if err == nil {
|
|
value = string(bytes)
|
|
} else {
|
|
log.Printf("Failed to convert JSON: %v", err)
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
l := field.Len()
|
|
for j := 0; j < l; j++ {
|
|
prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
|
|
ifc := field.Index(j).Interface()
|
|
//log.Printf("%s : %v", prefixName, ifc)
|
|
if ifc != nil {
|
|
setQueryValues(ifc, values, prefixName)
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
|
|
default:
|
|
switch field.Interface().(type) {
|
|
case ISO6801Time:
|
|
t := field.Interface().(ISO6801Time)
|
|
value = t.String()
|
|
case time.Time:
|
|
t := field.Interface().(time.Time)
|
|
value = GetISO8601TimeStamp(t)
|
|
default:
|
|
ifc := field.Interface()
|
|
if ifc != nil {
|
|
if anonymous {
|
|
SetQueryValues(ifc, values)
|
|
} else {
|
|
prefixName := fieldName + "."
|
|
setQueryValues(ifc, values, prefixName)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
if value != "" {
|
|
name := argName
|
|
if argName == "" {
|
|
name = fieldName
|
|
}
|
|
if prefix != "" {
|
|
name = prefix + name
|
|
}
|
|
values.Set(name, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func setQueryValuesByFlattenMethod(i interface{}, values *url.Values, prefix string) {
|
|
// add to support url.Values
|
|
mapValues, ok := i.(url.Values)
|
|
if ok {
|
|
for k, _ := range mapValues {
|
|
values.Set(k, mapValues.Get(k))
|
|
}
|
|
return
|
|
}
|
|
|
|
elem := reflect.ValueOf(i)
|
|
if elem.Kind() == reflect.Ptr {
|
|
elem = elem.Elem()
|
|
}
|
|
elemType := elem.Type()
|
|
for i := 0; i < elem.NumField(); i++ {
|
|
|
|
fieldName := elemType.Field(i).Name
|
|
anonymous := elemType.Field(i).Anonymous
|
|
field := elem.Field(i)
|
|
|
|
// TODO Use Tag for validation
|
|
// tag := typ.Field(i).Tag.Get("tagname")
|
|
kind := field.Kind()
|
|
|
|
isPtr := false
|
|
if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
|
|
continue
|
|
}
|
|
if kind == reflect.Ptr {
|
|
field = field.Elem()
|
|
kind = field.Kind()
|
|
isPtr = true
|
|
}
|
|
|
|
var value string
|
|
//switch field.Interface().(type) {
|
|
switch kind {
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
i := field.Int()
|
|
if i != 0 || isPtr {
|
|
value = strconv.FormatInt(i, 10)
|
|
}
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
i := field.Uint()
|
|
if i != 0 || isPtr {
|
|
value = strconv.FormatUint(i, 10)
|
|
}
|
|
case reflect.Float32:
|
|
value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
|
|
case reflect.Float64:
|
|
value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
|
|
case reflect.Bool:
|
|
value = strconv.FormatBool(field.Bool())
|
|
case reflect.String:
|
|
value = field.String()
|
|
case reflect.Map:
|
|
ifc := field.Interface()
|
|
m := ifc.(map[string]string)
|
|
if m != nil {
|
|
j := 0
|
|
for k, v := range m {
|
|
j++
|
|
keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
|
|
values.Set(keyName, k)
|
|
valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
|
|
values.Set(valueName, v)
|
|
}
|
|
}
|
|
case reflect.Slice:
|
|
if field.Type().Name() == "FlattenArray" {
|
|
FlattenFn(fieldName, field, values)
|
|
} else {
|
|
switch field.Type().Elem().Kind() {
|
|
case reflect.Uint8:
|
|
value = string(field.Bytes())
|
|
case reflect.String:
|
|
l := field.Len()
|
|
if l > 0 {
|
|
strArray := make([]string, l)
|
|
for i := 0; i < l; i++ {
|
|
strArray[i] = field.Index(i).String()
|
|
}
|
|
bytes, err := json.Marshal(strArray)
|
|
if err == nil {
|
|
value = string(bytes)
|
|
} else {
|
|
log.Printf("Failed to convert JSON: %v", err)
|
|
}
|
|
}
|
|
default:
|
|
l := field.Len()
|
|
for j := 0; j < l; j++ {
|
|
prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
|
|
ifc := field.Index(j).Interface()
|
|
//log.Printf("%s : %v", prefixName, ifc)
|
|
if ifc != nil {
|
|
setQueryValuesByFlattenMethod(ifc, values, prefixName)
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
|
|
default:
|
|
switch field.Interface().(type) {
|
|
case ISO6801Time:
|
|
t := field.Interface().(ISO6801Time)
|
|
value = t.String()
|
|
case time.Time:
|
|
t := field.Interface().(time.Time)
|
|
value = GetISO8601TimeStamp(t)
|
|
default:
|
|
|
|
ifc := field.Interface()
|
|
if ifc != nil {
|
|
if anonymous {
|
|
SetQueryValues(ifc, values)
|
|
} else {
|
|
prefixName := fieldName + "."
|
|
setQueryValuesByFlattenMethod(ifc, values, prefixName)
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
if value != "" {
|
|
name := elemType.Field(i).Tag.Get("ArgName")
|
|
if name == "" {
|
|
name = fieldName
|
|
}
|
|
if prefix != "" {
|
|
name = prefix + name
|
|
}
|
|
// NOTE: here we will change name to underline style when the type is UnderlineString
|
|
if field.Type().Name() == "UnderlineString" {
|
|
name = Underline2Dot(name)
|
|
}
|
|
values.Set(name, value)
|
|
}
|
|
}
|
|
}
|