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  }