blob: 4f1a946f56bede7e01d45ccd94fe11628cacd485 [file] [log] [blame]
package kube_conf_gen_lib
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"text/template"
"github.com/Masterminds/sprig"
"go.skia.org/infra/go/config"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
)
// ParseConfigHelper takes the given config map and adds its values into the
// given return map in stringified form. If strict is true, it will return an
// error for unsupported types, missing data, etc.
func ParseConfigHelper(confMap map[string]interface{}, ret map[string]interface{}, strict bool) error {
for k, v := range confMap {
val := ""
switch t := v.(type) {
case string:
val = t
case bool:
if t {
val = "true"
} else {
val = "false"
}
case int, int32, int64:
val = fmt.Sprintf("%d", v)
case float32, float64:
val = fmt.Sprintf("%f", v)
case []interface{}:
ret[k] = t
case map[string]interface{}:
subMap := map[string]interface{}{}
if err := ParseConfigHelper(t, subMap, strict); err != nil {
return err
}
ret[k] = subMap
default:
if strict {
return fmt.Errorf("Key %q has unsupported type %q", k, t)
}
reflectVal := reflect.ValueOf(v)
if !reflectVal.IsValid() {
sklog.Warningf("Key %q has unsupported type %q", k, t)
} else {
sklog.Warningf("Key %q has unsupported type %q", k, reflectVal.Type().String())
}
}
if val != "" {
ret[k] = val
}
}
return nil
}
// LoadConfigFiles reads the given JSON5-formatted config files and merges them
// into a single map[string]interface. If parseConf is true, all config values
// are converted to strings. If strict is true, will return an error for
// unsupported types, missing data, etc. If emptyQuotes is true, config values
// which are empty strings are replaced with empty single quotes ('').
func LoadConfigFiles(parseConf, strict, emptyQuotes bool, configFileNames ...string) (map[string]interface{}, error) {
ret := map[string]interface{}{}
for _, configFile := range configFileNames {
confMap := map[string]interface{}{}
if err := config.ParseConfigFile(configFile, "-c", &confMap); err != nil {
return nil, fmt.Errorf("Failed to parse config file %q: %s", configFile, err)
}
if parseConf {
if err := ParseConfigHelper(confMap, ret, strict); err != nil {
return nil, fmt.Errorf("Failed to parse config file %q: %s", configFile, err)
}
} else {
for k, v := range confMap {
ret[k] = v
}
}
}
// Go through the result and replace empty strings with empty single quotes if requested.
if emptyQuotes {
for k, v := range ret {
if strVal, ok := v.(string); ok && strVal == "" {
ret[k] = "''"
}
}
}
return ret, nil
}
// GenerateOutputFromTemplateString executes the template string with config as
// its environment and writes the result to outFile.
func GenerateOutputFromTemplateString(tmplString string, strict bool, config map[string]interface{}, outFile string) error {
tmpl, err := template.New("kube-conf-gen-tmpl").Funcs(sprig.TxtFuncMap()).Parse(tmplString)
if err != nil {
return skerr.Wrapf(err, "error parsing template %s", tmplString)
}
return generateOutputHelper(tmpl, strict, config, outFile)
}
// GenerateOutputFromTemplateFile executes the template file with config as its
// environment and writes the result to outFile.
func GenerateOutputFromTemplateFile(templateFileName string, strict bool, config map[string]interface{}, outFile string) error {
tmpl, err := template.New(path.Base(templateFileName)).Funcs(sprig.TxtFuncMap()).ParseFiles(templateFileName)
if err != nil {
return skerr.Wrapf(err, "error parsing template '%s'", templateFileName)
}
return generateOutputHelper(tmpl, strict, config, outFile)
}
func generateOutputHelper(tmpl *template.Template, strict bool, config map[string]interface{}, outFile string) error {
if strict {
tmpl.Option("missingkey=error")
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, config); err != nil {
return skerr.Wrap(err)
}
if outFile == "_" {
fmt.Println(string(buf.Bytes()))
return nil
} else {
dir, _ := filepath.Split(outFile)
if dir != "" {
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return skerr.Wrapf(err, "failed to create destination directory")
}
}
return skerr.Wrap(ioutil.WriteFile(outFile, buf.Bytes(), 0644))
}
}