Example #1
0
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)
	}
}
Example #2
0
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)
	}
}
Example #3
0
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
}
Example #4
0
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)
	}
}
Example #5
0
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)
	}
}