func MakeFnWith(sources *deepstack.DeepStack, outerRules *template.Rules) template.Rule { return func(path []interface{}, node interface{}) (interface{}, interface{}) { key := interface{}(nil) if len(path) > 0 { key = path[len(path)-1] } raw, ok := singleKey(node, "Fn::With") if !ok { return key, node //passthru } args, ok := collectArgs( raw, func(argsSoFar []interface{}) bool { return len(argsSoFar) < 2 }, func(argsSoFar []interface{}, arg interface{}) (bool, interface{}) { // unconditionally process the argument, in case it needs to be skipped key, node := template.Walk(path, arg, outerRules) if skip, ok := key.(bool); ok && skip { return true, nil } if len(argsSoFar) == 1 { return false, arg // return unprocessed 2nd arg. It's a template. } return false, node }, ) if !ok { return key, node //passthru } var source map[string]interface{} if source, ok = args[0].(map[string]interface{}); !ok { return key, node //passthru } sources.Push(fallbackmap.DeepMap(source)) innerTemplate := interface{}(args[1]) key, generated := template.Walk(path, innerTemplate, outerRules) sources.PopDiscard() return key, interface{}(generated) } }
func MakeRef(sources fallbackmap.Deep, rules *template.Rules) template.Rule { return func(path []interface{}, node interface{}) (interface{}, interface{}) { key := interface{}(nil) if len(path) > 0 { key = path[len(path)-1] } argInterface, ok := singleKey(node, "Ref") if !ok { return key, node //passthru } var argString string if argString, ok = argInterface.(string); !ok { return key, node //passthru } var refpath []string for _, part := range deepalias.Split(argString) { refpath = append(refpath, part) } var newNode interface{} newNode, ok = sources.Get(refpath) if ok { var newKey interface{} newKey, newNode = template.Walk(path, newNode, rules) return newKey, newNode } return key, node //passthru (ref not found) } }
func (lazy LazyMap) Get(path []string) (value interface{}, has_key bool) { if len(path) == 0 { return lazy, true } processed, ok := lazy.processed[strings.Join(path, ".")] if ok { value, has_key = processed.Get(path) if has_key { lazy.processed[strings.Join(path, ".")] = fallbackmap.NewDeepSingle(path, value) return value, true } lazy.processed[strings.Join(path, ".")] = fallbackmap.DeepNil return nil, false } value, has_key = lazy.deep.Get(path) if has_key { var newKey interface{} newKey, value = template.Walk([]interface{}{path[len(path)-1]}, value, lazy.rules) if newKey == nil { return nil, false } if newKey == path[len(path)-1] { lazy.processed[strings.Join(path, ".")] = fallbackmap.NewDeepSingle(path, value) return value, true } return nil, false } if len(path) == 1 { return nil, false } head := path[:len(path)-1] _, has_key = lazy.Get(head) if has_key { value, has_key = lazy.processed[strings.Join(head, ".")].Get(path) if has_key { lazy.processed[strings.Join(path, ".")] = fallbackmap.NewDeepSingle(path, value) return value, true } } return nil, false }
func MakeFnIncludeFile(opener vfs.Opener, rules *template.Rules) template.Rule { return func(path []interface{}, node interface{}) (interface{}, interface{}) { key := interface{}(nil) if len(path) > 0 { key = path[len(path)-1] } argInterface, ok := singleKey(node, "Fn::IncludeFile") if !ok { return key, node //passthru } var argString string if argString, ok = argInterface.(string); !ok { return key, node //passthru } var absPath string var err error if absPath, err = filepath.Abs(argString); err != nil { panic(fmt.Errorf("Error opening imported file '%s': %s", argString, err)) } var jsonStream io.Reader if jsonStream, err = opener.Open(absPath); err != nil { panic(fmt.Errorf("Error opening imported file '%s': %s", absPath, err)) } dec := json.NewDecoder(jsonStream) includedTemplate := interface{}(nil) if err := dec.Decode(&includedTemplate); err != nil { panic(fmt.Errorf("Error loading imported file '%s': %s", argString, err)) } key, generated := template.Walk(path, includedTemplate, rules) return key, interface{}(generated) } }
func MakeFnFor(sources *deepstack.DeepStack, templateRules *template.Rules) template.Rule { return func(path []interface{}, node interface{}) (interface{}, interface{}) { key := interface{}(nil) if len(path) > 0 { key = path[len(path)-1] } raw, ok := singleKey(node, "Fn::For") if !ok { return key, node //passthru } args, ok := collectArgs( raw, func(argsSoFar []interface{}) bool { return len(argsSoFar) < 3 }, func(argsSoFar []interface{}, arg interface{}) (skip bool, newNode interface{}) { // unconditionally process the argument, in case it needs to be skipped key, node := template.Walk(path, arg, templateRules) if skip, ok := key.(bool); ok && skip { return true, nil } if len(argsSoFar) == 2 { return false, arg // return unprocessed 3rd arg. It's a template. } return false, node }, ) if !ok { return key, node //passthru } var refNames []interface{} var refName interface{} if refNames, ok = args[0].([]interface{}); ok { if len(refNames) == 1 { refNames = []interface{}{nil, refNames[0]} } else if len(refNames) != 2 { return key, node //passthru } } else { refNames = []interface{}{nil, args[0]} } for _, refName = range refNames { if _, ok = refName.(string); !ok && refName != nil { return key, node //passthru } } valuesInterface := args[1] var values []interface{} if values, ok = valuesInterface.([]interface{}); !ok { return key, node //passthru } loopTemplate := interface{}(args[2]) generated := []interface{}{} for deepIndex, value := range values { refMap := make(map[string]interface{}) if refNames[0] != nil { refMap[refNames[0].(string)] = float64(deepIndex) } if refNames[1] != nil { refMap[refNames[1].(string)] = value } deepPath := make([]interface{}, len(path)+1) copy(deepPath, path) deepPath[cap(deepPath)-1] = interface{}(deepIndex) sources.Push(fallbackmap.DeepMap(refMap)) newIndex, processed := template.Walk(deepPath, loopTemplate, templateRules) sources.PopDiscard() if newIndex != nil { generated = append(generated, processed) } } return key, interface{}(generated) } }