pkg/sdk/value/flatmap/flatmap.go (72 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package flatmap
import (
"fmt"
"path"
"reflect"
"github.com/elastic/harp/pkg/bundle"
)
// -----------------------------------------------------------------------------
// Flatten takes a structure and turns into a flat map[string]string.
func Flatten(thing map[string]interface{}) map[string]bundle.KV {
result := make(map[string]string)
// Flatten recursively the map
for k, raw := range thing {
flatten(result, k, reflect.ValueOf(raw))
}
// Unpack leaf as secrets
jsonMap := map[string]bundle.KV{}
for k, v := range result {
// Get last element as secret name
packageName, secretName := path.Split(k)
// Remove trailing path separator
packageName = path.Clean(packageName)
// Check if package already is registered
p, ok := jsonMap[packageName]
if !ok {
p = bundle.KV{}
}
// Assign secret
p[secretName] = v
// Re-assign to map
jsonMap[packageName] = p
}
// Return json map
return jsonMap
}
func flatten(result map[string]string, prefix string, v reflect.Value) {
if v.Kind() == reflect.Interface {
v = v.Elem()
}
switch v.Kind() {
case reflect.Bool:
if v.Bool() {
result[prefix] = "true"
} else {
result[prefix] = "false"
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
result[prefix] = fmt.Sprintf("%d", v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
result[prefix] = fmt.Sprintf("%d", v.Uint())
case reflect.Float32, reflect.Float64:
result[prefix] = fmt.Sprintf("%f", v.Float())
case reflect.Map:
flattenMap(result, prefix, v)
case reflect.Slice, reflect.Array:
flattenSlice(result, prefix, v)
case reflect.String:
result[prefix] = v.String()
case reflect.Chan, reflect.Complex128, reflect.Complex64, reflect.Func, reflect.Interface:
// ignore
case reflect.Invalid, reflect.Ptr, reflect.Struct, reflect.Uintptr, reflect.UnsafePointer:
// ignore
default:
panic(fmt.Sprintf("Unknown: %s", v))
}
}
func flattenMap(result map[string]string, prefix string, v reflect.Value) {
for _, k := range v.MapKeys() {
if k.Kind() == reflect.Interface {
k = k.Elem()
}
if k.Kind() != reflect.String {
panic(fmt.Sprintf("%s: map key is not string: %s", prefix, k))
}
flatten(result, fmt.Sprintf("%s/%s", prefix, k.String()), v.MapIndex(k))
}
}
func flattenSlice(result map[string]string, prefix string, v reflect.Value) {
prefix += "/"
result[prefix+"#"] = fmt.Sprintf("%d", v.Len())
for i := 0; i < v.Len(); i++ {
flatten(result, fmt.Sprintf("%s%d", prefix, i), v.Index(i))
}
}