commit b730aca6cfb41c83218c2c8d50e5722ad88f3b59 Author: Timon Ringwald Date: Sun Sep 18 19:28:34 2022 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e8719d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.yaml +templates +target diff --git a/config_file.go b/config_file.go new file mode 100644 index 0000000..463704b --- /dev/null +++ b/config_file.go @@ -0,0 +1,7 @@ +package main + +type Config struct { + Globals map[interface{}]interface{} `yaml:"globals"` + TemplateDir string `yaml:"templates"` + TargetDir string `yaml:"target"` +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c00fb36 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.milar.in/milarin/cfgen + +go 1.19 + +require gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dd0bc19 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/handle_template.go b/handle_template.go new file mode 100644 index 0000000..969f903 --- /dev/null +++ b/handle_template.go @@ -0,0 +1,42 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "text/template" +) + +func HandleTemplate(tmpl *template.Template) error { + b := &bytes.Buffer{} + if err := tmpl.Execute(b, ConfigFile.Globals); err != nil { + return err + } + + if len(strings.TrimSpace(b.String())) == 0 { + return nil + } + + tmplPath := filepath.Join(ConfigFile.TargetDir, tmpl.Name()) + + if err := os.MkdirAll(filepath.Dir(tmplPath), 0755); err != nil { + return err + } + + file, err := os.Create(tmplPath) + if err != nil { + return err + } + defer file.Close() + + if _, err := io.Copy(file, b); err != nil { + return err + } + + fmt.Println(tmplPath) + + return nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..448f64d --- /dev/null +++ b/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "errors" + "flag" + "os" + "text/template" + + "gopkg.in/yaml.v2" +) + +var ( + ConfigFile = &Config{} +) + +func main() { + flag.Parse() + + if err := ReadConfigFile(); err != nil { + panic(err) + } + + tmplMap, err := ParseTemplates(template.New("template"), ConfigFile.TemplateDir) + if err != nil { + panic(err) + } + + if err := os.MkdirAll(ConfigFile.TargetDir, 0755); err != nil { + panic(err) + } + + for _, tmpl := range tmplMap { + if err := HandleTemplate(tmpl); err != nil { + panic(err) + } + } +} + +func ReadConfigFile() error { + filename := flag.Arg(0) + if filename == "" { + return errors.New("no config file provided") + } + + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + if err := yaml.NewDecoder(file).Decode(ConfigFile); err != nil { + return err + } + + RecursiveEnvLookupForMap(ConfigFile.Globals) + return nil +} + +func RecursiveEnvLookupForMap(m map[interface{}]interface{}) { + for k, v := range m { + if str, ok := v.(string); ok { + m[k] = os.ExpandEnv(str) + } else if m2, ok := v.(map[interface{}]interface{}); ok { + RecursiveEnvLookupForMap(m2) + } else if arr, ok := v.([]interface{}); ok { + RecursiveEnvLookupForSlice(arr) + } + } +} + +func RecursiveEnvLookupForSlice(s []interface{}) { + for i, v := range s { + if str, ok := v.(string); ok { + s[i] = os.ExpandEnv(str) + } else if m, ok := v.(map[interface{}]interface{}); ok { + RecursiveEnvLookupForMap(m) + } else if arr, ok := v.([]interface{}); ok { + RecursiveEnvLookupForSlice(arr) + } + } +} diff --git a/parse_templates.go b/parse_templates.go new file mode 100644 index 0000000..c564c83 --- /dev/null +++ b/parse_templates.go @@ -0,0 +1,58 @@ +package main + +import ( + "os" + "path/filepath" + "strings" + "text/template" +) + +func ParseTemplates(tmpl *template.Template, path string) (map[string]*template.Template, error) { + tmplMap := map[string]*template.Template{} + + err := parseTemplates(tmpl, tmplMap, path, path) + if err != nil { + return nil, err + } + + return tmplMap, nil +} + +func parseTemplates(tmpl *template.Template, tmplMap map[string]*template.Template, path string, trimPrefix string) error { + var err error + + dirEntries, err := os.ReadDir(path) + if err != nil { + return err + } + + for _, dirEntry := range dirEntries { + entryPath := filepath.Join(path, dirEntry.Name()) + if dirEntry.IsDir() { + err = parseTemplates(tmpl, tmplMap, entryPath, trimPrefix) + if err != nil { + return err + } + continue + } + + data, err := ReadFileString(entryPath) + if err != nil { + return err + } + + tmplName := filepath.Clean(strings.TrimPrefix(entryPath, trimPrefix)) + if tmplName[0] == '/' { + tmplName = tmplName[1:] + } + + tmpl, err = tmpl.New(tmplName).Parse(string(data)) + if err != nil { + return err + } + + tmplMap[tmplName] = tmpl + } + + return nil +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..df44c78 --- /dev/null +++ b/utils.go @@ -0,0 +1,20 @@ +package main + +import ( + "io" + "os" +) + +func ReadFile(path string) ([]byte, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + return io.ReadAll(file) +} + +func ReadFileString(path string) (string, error) { + data, err := ReadFile(path) + return string(data), err +}