package tmpl import ( "fmt" "gopkg.in/yaml.v2" "os" "path/filepath" "strings" "text/template" ) type Values = map[string]interface{} func (c *Context) createFuncMap() template.FuncMap { return template.FuncMap{ "readFile": c.ReadFile, "toYaml": ToYaml, "fromYaml": FromYaml, "setValueAtPath": SetValueAtPath, "requiredEnv": RequiredEnv, } } func (c *Context) ReadFile(filename string) (string, error) { path := filepath.Join(c.basePath, filename) bytes, err := c.readFile(path) if err != nil { return "", err } return string(bytes), nil } func ToYaml(v interface{}) (string, error) { data, err := yaml.Marshal(v) if err != nil { return "", err } return string(data), nil } func FromYaml(str string) (Values, error) { m := Values{} if err := yaml.Unmarshal([]byte(str), &m); err != nil { return nil, err } return m, nil } func SetValueAtPath(path string, value interface{}, values Values) (Values, error) { var current interface{} current = values components := strings.Split(path, ".") pathToMap := components[:len(components)-1] key := components[len(components)-1] for _, k := range pathToMap { var elem interface{} switch typedCurrent := current.(type) { case map[string]interface{}: v, exists := typedCurrent[k] if !exists { return nil, fmt.Errorf("failed to set value at path \"%s\": value for key \"%s\" does not exist", path, k) } elem = v case map[interface{}]interface{}: v, exists := typedCurrent[k] if !exists { return nil, fmt.Errorf("failed to set value at path \"%s\": value for key \"%s\" does not exist", path, k) } elem = v default: return nil, fmt.Errorf("failed to set value at path \"%s\": value for key \"%s\" was not a map", path, k) } switch typedElem := elem.(type) { case map[string]interface{}, map[interface{}]interface{}: current = typedElem default: return nil, fmt.Errorf("failed to set value at path \"%s\": value for key \"%s\" was not a map", path, k) } } switch typedCurrent := current.(type) { case map[string]interface{}: typedCurrent[key] = value case map[interface{}]interface{}: typedCurrent[key] = value default: return nil, fmt.Errorf("failed to set value at path \"%s\": value for key \"%s\" was not a map", path, key) } return values, nil } func RequiredEnv(name string) (string, error) { if val, exists := os.LookupEnv(name); exists && len(val) > 0 { return val, nil } return "", fmt.Errorf("required env var `%s` is not set", name) }