func gen(in, out string, vals map[string]interface{}) error {
	t, err := template.New(filepath.Base(in)).Funcs(sprig.FuncMap()).ParseFiles(in)
	if err != nil {
		return err
	}
	buf := bytes.NewBuffer([]byte(""))
	if err := t.Execute(buf, vals); err != nil {
		return err
	}
	if buf.Len() == 0 {
		return nil
	}
	wd, _ := os.Getwd()
	rel, _ := filepath.Rel(wd, out)
	if rel == "" {
		rel = out
	}
	_, err = os.Stat(out)
	switch {
	case !(err != nil):
		log.Printf("\texists: %v", rel)
	case os.IsNotExist(err):
		if err := ioutil.WriteFile(out, buf.Bytes(), 0600); err != nil {
			return err
		}
		log.Printf("\tcreated: %v", rel)
	default:
	}
	return nil
}
gen generates files with in templates on out path with vals values.
package main
import (
	"bufio"
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"github.com/BurntSushi/toml"
	"github.com/Masterminds/sprig"
	"github.com/google/shlex"
	"github.com/spf13/cobra"
)
func main() {
	log.SetFlags(0)
	cmd := &cobra.Command{
		Use:   "ska [template]",
		Short: "Render template",
		Args:  cobra.ExactArgs(1),
		Run:   run,
	}
	setUpFlags(cmd)
	must(cmd.Execute())
}
func setUpFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringP("templates", "t", templatePathDefault(), "templates dir")
	cmd.PersistentFlags().StringP("output", "o", ".", "output")
	cmd.PersistentFlags().StringP("editor", "e", os.Getenv("EDITOR"), "editor")
	cmd.PersistentFlags().StringP("values", "v", "", "values path")
	cmd.PersistentFlags().BoolP("default-values", "d", false, "use default values")
}
func run(cmd *cobra.Command, args []string) {
	var (
		ska                = cmd.Flag("templates").Value.String()
		out                = cmd.Flag("output").Value.String()
		editor             = cmd.Flag("editor").Value.String()
		externalValuesPath = cmd.Flag("values").Value.String()
		defaultValues      = cmd.Flag("default-values").Value.String()
	)
	valuePath, templatesPath := tplPaths(ska, args[0])
	out, err := filepath.Abs(out)
	if err != nil {
		must(err)
	}
	var values map[string]interface{}
	switch {
	case defaultValues == "true":
		values = readValuesFromPath(valuePath)
	case externalValuesPath != "":
		values = readValuesFromPath(externalValuesPath)
	default:
		values = readValuesFromTempFile(valuePath, editor)
	}
	if err != nil && !os.IsNotExist(err) {
		must(err)
	}
	must(walk(templatesPath, out, values, gen))
}
func readValuesFromPath(valuePath string) map[string]interface{} {
	valuePath, _ = filepath.Abs(valuePath)
	values, err := vals(valuePath)
	if err != nil {
		log.Fatalf("Error while parsing default values: %v", err)
	}
	return values
}
func readValuesFromTempFile(valuePath, editor string) map[string]interface{} {
	tmp, err := tempfile(valuePath)
	if err != nil {
		log.Fatalf("Error while creating temp value file: %v", err)
	}
	s := bufio.NewScanner(os.Stdin)
	var values map[string]interface{}
	for {
		must(invokeEditor(editor, tmp))
		var err error
		values, err = vals(tmp)
		if !(err != nil) {
			break
		}
		fmt.Printf("Error while parsing file: %v\n", err)
		s.Scan()
	}
	if err := os.RemoveAll(tmp); err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
	}
	return values
}
func tplPaths(ska, tpl string) (vp, tp string) {
	tplf := fmt.Sprintf("%s/%s", ska, tpl)
	return fmt.Sprintf("%s/values.toml", tplf), fmt.Sprintf("%s/templates", tplf)
}
func vals(path string) (map[string]interface{}, error) {
	var vals map[string]interface{}
	if _, err := toml.DecodeFile(path, &vals); err != nil {
		return nil, err
	}
	return vals, nil
}
func walk(in, out string, vals map[string]interface{},
	f func(in, out string, vals map[string]interface{}) error) error {
	return filepath.Walk(in, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		file, err := prepareFilepath(path, vals)
		if err != nil {
			return err
		}
		in, err = filepath.Abs(in)
		if err != nil {
			return err
		}
		saveto := out + string(filepath.Separator) + strings.ReplaceAll(file, in, "")
		if err := mkdirr(filepath.Dir(saveto)); err != nil {
			return err
		}
		return f(path, saveto, vals)
	})
}