github.com/profects/terraform@v0.9.0-beta1.0.20170227135739-92d4809db30d/flatmap/expand.go (about) 1 package flatmap 2 3 import ( 4 "fmt" 5 "sort" 6 "strconv" 7 "strings" 8 9 "github.com/hashicorp/hil" 10 ) 11 12 // Expand takes a map and a key (prefix) and expands that value into 13 // a more complex structure. This is the reverse of the Flatten operation. 14 func Expand(m map[string]string, key string) interface{} { 15 // If the key is exactly a key in the map, just return it 16 if v, ok := m[key]; ok { 17 if v == "true" { 18 return true 19 } else if v == "false" { 20 return false 21 } 22 23 return v 24 } 25 26 // Check if the key is an array, and if so, expand the array 27 if v, ok := m[key+".#"]; ok { 28 // If the count of the key is unknown, then just put the unknown 29 // value in the value itself. This will be detected by Terraform 30 // core later. 31 if v == hil.UnknownValue { 32 return v 33 } 34 35 return expandArray(m, key) 36 } 37 38 // Check if this is a prefix in the map 39 prefix := key + "." 40 for k, _ := range m { 41 if strings.HasPrefix(k, prefix) { 42 return expandMap(m, prefix) 43 } 44 } 45 46 return nil 47 } 48 49 func expandArray(m map[string]string, prefix string) []interface{} { 50 num, err := strconv.ParseInt(m[prefix+".#"], 0, 0) 51 if err != nil { 52 panic(err) 53 } 54 55 // The Schema "Set" type stores its values in an array format, but using 56 // numeric hash values instead of ordinal keys. Take the set of keys 57 // regardless of value, and expand them in numeric order. 58 // See GH-11042 for more details. 59 keySet := map[int]bool{} 60 for k := range m { 61 if !strings.HasPrefix(k, prefix+".") { 62 continue 63 } 64 65 key := k[len(prefix)+1:] 66 idx := strings.Index(key, ".") 67 if idx != -1 { 68 key = key[:idx] 69 } 70 71 // skip the count value 72 if key == "#" { 73 continue 74 } 75 76 k, err := strconv.Atoi(key) 77 if err != nil { 78 panic(err) 79 } 80 keySet[int(k)] = true 81 } 82 83 keysList := make([]int, 0, num) 84 for key := range keySet { 85 keysList = append(keysList, key) 86 } 87 sort.Ints(keysList) 88 89 result := make([]interface{}, num) 90 for i, key := range keysList { 91 result[i] = Expand(m, fmt.Sprintf("%s.%d", prefix, key)) 92 } 93 94 return result 95 } 96 97 func expandMap(m map[string]string, prefix string) map[string]interface{} { 98 result := make(map[string]interface{}) 99 for k, _ := range m { 100 if !strings.HasPrefix(k, prefix) { 101 continue 102 } 103 104 key := k[len(prefix):] 105 idx := strings.Index(key, ".") 106 if idx != -1 { 107 key = key[:idx] 108 } 109 if _, ok := result[key]; ok { 110 continue 111 } 112 113 // skip the map count value 114 if key == "%" { 115 continue 116 } 117 result[key] = Expand(m, k[:len(prefix)+len(key)]) 118 } 119 120 return result 121 }