Created
February 18, 2023 11:30
-
-
Save xkisu/c57ccd54eb3509323af3ccca3aa2e08f to your computer and use it in GitHub Desktop.
Generate matrix combinations from a source set of maps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"sort" | |
"strings" | |
"github.com/zclconf/go-cty/cty" | |
"github.com/zclconf/go-cty/cty/json" | |
) | |
func generateCombinations(m map[string]cty.Value, combination map[string]cty.Value, keys []string) []map[string]cty.Value { | |
var results []map[string]cty.Value | |
if len(keys) == 0 { | |
result := make(map[string]cty.Value) | |
for k, v := range combination { | |
result[k] = v | |
} | |
results = append(results, result) | |
return results | |
} | |
key := keys[0] // pop the first key off the key list to process | |
keys = keys[1:] // dereference after the first key to include keys to process | |
value := m[key] // get the value of the key to process | |
// Determine the type of value to decode | |
if value.Type().IsListType() { // decodes slices | |
collection := value.AsValueSlice() | |
for _, elem := range collection { | |
combination[key] = elem | |
results = append(results, generateCombinations(m, combination, keys)...) | |
} | |
} else if value.Type().IsMapType() || value.Type().IsObjectType(){ // decodes nested maps/objects | |
// TODO: Skip processing if the value is empty | |
// if !value.Type().IsObjectType() || value.Type() != cty.EmptyObject { | |
// do processing.. | |
// } | |
for nestedKey, nestedValue := range value.AsValueMap() { | |
newKey := fmt.Sprintf("%s.%s", key, nestedKey) | |
combination[newKey] = nestedValue | |
results = append(results, generateCombinations(m, combination, keys)...) | |
delete(combination, newKey) | |
} | |
} else { // decodes primitive types | |
combination[key] = value | |
results = generateCombinations(m, combination, keys) | |
} | |
return results | |
} | |
func flattenSourceCombinations (m map[string]cty.Value)map[string]cty.Value { | |
results := make(map[string]cty.Value) | |
for key, value := range m { | |
if value.Type().IsObjectType() || value.Type().IsMapType() { | |
for nestedKey, nestedValue := range value.AsValueMap() { | |
if nestedValue.Type().IsObjectType() || nestedValue.Type().IsMapType() { | |
nestedResults := flattenSourceCombinations(nestedValue.AsValueMap()) | |
for nestedResultKey, nestedResultValue := range nestedResults { | |
results[fmt.Sprintf("%s.%s.%s", key, nestedKey, nestedResultKey)] = nestedResultValue | |
} | |
} else { | |
results[fmt.Sprintf("%s.%s", key, nestedKey)] = nestedValue | |
} | |
} | |
} else { // Primates and slices are preserved | |
results[key] = value | |
} | |
} | |
return results | |
} | |
func MatrixCombinations(matrix map[string]cty.Value) []map[string]cty.Value { | |
// Recursively flatten any nested maps and objects defined | |
// in the matrix and fold them back into the matrix. | |
matrix = flattenSourceCombinations(matrix) | |
var keys []string | |
for key := range matrix { | |
keys = append(keys, key) | |
} | |
return generateCombinations(matrix, make(map[string]cty.Value), keys) | |
} | |
func main() { | |
res := MatrixCombinations(map[string]cty.Value{ | |
"flavour": cty.ListVal([]cty.Value{ | |
cty.StringVal("vanilla"), | |
cty.StringVal("spigot"), | |
}), | |
"version": cty.ObjectVal(map[string]cty.Value{ | |
"number": cty.ListVal([]cty.Value{ | |
cty.StringVal("1.18"), | |
cty.StringVal("1.19"), | |
}), | |
"experimental": cty.ListVal([]cty.Value{ | |
cty.BoolVal(true), | |
cty.BoolVal(false), | |
}), | |
}), | |
}) | |
fmt.Printf("%#v\n", res) | |
for _, combo := range res { | |
var marshaled []string | |
var keys []string | |
for key := range combo { | |
keys = append(keys, key) | |
} | |
sort.Strings(keys) | |
for _, key := range keys { | |
value := combo[key] | |
b, err := json.Marshal(value, value.Type()) | |
if err != nil { | |
panic(err) | |
} | |
marshaled = append(marshaled, fmt.Sprintf("%s: %s", key, string(b))) | |
} | |
fmt.Println(fmt.Sprintf("[%s]", strings.Join(marshaled, ", "))) | |
} | |
} | |
// Result: | |
// [flavour: "vanilla", version.experimental: true, version.number: "1.18"] | |
// [flavour: "vanilla", version.experimental: true, version.number: "1.19"] | |
// [flavour: "vanilla", version.experimental: false, version.number: "1.18"] | |
// [flavour: "vanilla", version.experimental: false, version.number: "1.19"] | |
// [flavour: "spigot", version.experimental: true, version.number: "1.18"] | |
// [flavour: "spigot", version.experimental: true, version.number: "1.19"] | |
// [flavour: "spigot", version.experimental: false, version.number: "1.18"] | |
// [flavour: "spigot", version.experimental: false, version.number: "1.19"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment