| 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)) |
| } |
| } |