package yaml import ( "fmt" "strings" yttcmd "carvel.dev/ytt/pkg/cmd/template" yttui "carvel.dev/ytt/pkg/cmd/ui" yttfiles "carvel.dev/ytt/pkg/files" "gopkg.in/yaml.v2" ) func ytt(tpl, dvs []string, varFiles []string) ([]byte, error) { // create and invoke ytt "template" command templatingOptions := yttcmd.NewOptions() input, err := templatesAsInput(tpl...) if err != nil { return nil, err } if len(varFiles) > 0 { // Load vaarFiles into the templating options. templatingOptions.DataValuesFlags.FromFiles = varFiles } // equivalent to `--data-value-yaml` templatingOptions.DataValuesFlags.KVsFromYAML = dvs // for in-memory use, pipe output to "/dev/null" noopUI := yttui.NewCustomWriterTTY(false, noopWriter{}, noopWriter{}) // Evaluate the template given the configured data values... output := templatingOptions.RunWithFiles(input, noopUI) if output.Err != nil { return nil, output.Err } return output.DocSet.AsBytes() } // templatesAsInput conveniently wraps one or more strings, each in a files.File, into a template.Input. func templatesAsInput(tpl ...string) (yttcmd.Input, error) { var files []*yttfiles.File for i, t := range tpl { // to make this less brittle, you'll probably want to use well-defined names for `path`, here, for each input. // this matters when you're processing errors which report based on these paths. file, err := yttfiles.NewFileFromSource(yttfiles.NewBytesSource(fmt.Sprintf("tpl%d.yml", i), []byte(t))) if err != nil { return yttcmd.Input{}, err } files = append(files, file) } return yttcmd.Input{Files: files}, nil } func mapToKeyValueSlice(m map[string]interface{}) []string { var result []string for k, v := range m { y, _ := yaml.Marshal(v) result = append(result, fmt.Sprintf("%s=%s", k, strings.TrimSpace(string(y)))) } return result } type noopWriter struct{} func (w noopWriter) Write(data []byte) (int, error) { return len(data), nil }