Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion filebasics/filebasics.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ func ReadFile(filename string) ([]byte, error) {
if err != nil {
return nil, err
}
return body, nil

renderedContent, err := renderTemplate(string(body), false)
if err != nil {
return nil, fmt.Errorf("parsing file: %w", err)
}

return []byte(renderedContent), nil
}

// MustReadFile reads file contents. Will panic if reading fails.
Expand Down
111 changes: 111 additions & 0 deletions filebasics/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package filebasics

// This file is a copy of: https://github.com/Kong/go-database-reconciler/blob/main/pkg/file/template.go

import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"text/template"
)

// default env var prefix, can be set using SetEnvVarPrefix
var envVarPrefix = "DECK_"

// SetEnvVarPrefix sets the prefix for environment variables used in the state file.
// The default prefix is "DECK_". This sets a library global(!!) value.
func SetEnvVarPrefix(prefix string) {
envVarPrefix = prefix
}

func getPrefixedEnvVar(key string) (string, error) {
if !strings.HasPrefix(key, envVarPrefix) {
return "", fmt.Errorf("environment variables in the state file must "+
"be prefixed with '%s', found: '%s'", envVarPrefix, key)
}
value, exists := os.LookupEnv(key)
if !exists {
return "", fmt.Errorf("environment variable '%s' present in state file but not set", key)
}
return value, nil
}

// getPrefixedEnvVarMocked is used when we mock the env variables while rendering a template.
// It will always return the name of the environment variable in this case.
func getPrefixedEnvVarMocked(key string) (string, error) {
if !strings.HasPrefix(key, envVarPrefix) {
return "", fmt.Errorf("environment variables in the state file must "+
"be prefixed with '%s', found: '%s'", envVarPrefix, key)
}
return key, nil
}

func toBool(key string) (bool, error) {
return strconv.ParseBool(key)
}

// toBoolMocked is used when we mock the env variables while rendering a template.
// It will always return false in this case.
func toBoolMocked(_ string) (bool, error) {
return false, nil
}

func toInt(key string) (int, error) {
return strconv.Atoi(key)
}

// toIntMocked is used when we mock the env variables while rendering a template.
// It will always return 42 in this case.
func toIntMocked(_ string) (int, error) {
return 42, nil
}

func toFloat(key string) (float64, error) {
return strconv.ParseFloat(key, 64)
}

// toFloatMocked is used when we mock the env variables while rendering a template.
// It will always return 42 in this case.
func toFloatMocked(_ string) (float64, error) {
return 42, nil
}

func indent(spaces int, v string) string {
pad := strings.Repeat(" ", spaces)
return strings.Replace(v, "\n", "\n"+pad, -1)
}

func renderTemplate(content string, mockEnvVars bool) (string, error) {
var templateFuncs template.FuncMap
if mockEnvVars {
templateFuncs = template.FuncMap{
"env": getPrefixedEnvVarMocked,
"toBool": toBoolMocked,
"toInt": toIntMocked,
"toFloat": toFloatMocked,
"indent": indent,
}
} else {
templateFuncs = template.FuncMap{
"env": getPrefixedEnvVar,
"toBool": toBool,
"toInt": toInt,
"toFloat": toFloat,
"indent": indent,
}
}
t := template.New("state").Funcs(templateFuncs).Delims("${{", "}}")

t, err := t.Parse(content)
if err != nil {
return "", err
}
var buffer bytes.Buffer
err = t.Execute(&buffer, nil)
if err != nil {
return "", err
}
return buffer.String(), nil
}