140 lines
3.5 KiB
Go
140 lines
3.5 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/Masterminds/sprig/v3"
|
|
)
|
|
|
|
// TemplateEngine handles template processing with Wild Cloud context
|
|
type TemplateEngine struct {
|
|
configData map[string]interface{}
|
|
secretsData map[string]interface{}
|
|
}
|
|
|
|
// NewTemplateEngine creates a new template engine with config and secrets context
|
|
func NewTemplateEngine(configMgr *Manager) (*TemplateEngine, error) {
|
|
configData, err := configMgr.LoadConfig()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("loading config: %w", err)
|
|
}
|
|
|
|
secretsData, err := configMgr.LoadSecrets()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("loading secrets: %w", err)
|
|
}
|
|
|
|
return &TemplateEngine{
|
|
configData: configData,
|
|
secretsData: secretsData,
|
|
}, nil
|
|
}
|
|
|
|
// Process processes template content with Wild Cloud context
|
|
func (t *TemplateEngine) Process(templateContent string) (string, error) {
|
|
// Create template with sprig functions
|
|
tmpl := template.New("wild").Funcs(sprig.TxtFuncMap())
|
|
|
|
// Add Wild Cloud specific functions
|
|
tmpl = tmpl.Funcs(template.FuncMap{
|
|
// Config access function - matches gomplate .config
|
|
"config": func(path string) interface{} {
|
|
return t.getValueByPath(t.configData, path)
|
|
},
|
|
// Secret access function - matches gomplate .secrets
|
|
"secret": func(path string) interface{} {
|
|
return t.getValueByPath(t.secretsData, path)
|
|
},
|
|
// Direct access to config data - matches gomplate behavior
|
|
"getConfig": func(path string) interface{} {
|
|
return t.getValueByPath(t.configData, path)
|
|
},
|
|
// Direct access to secret data - matches gomplate behavior
|
|
"getSecret": func(path string) interface{} {
|
|
return t.getValueByPath(t.secretsData, path)
|
|
},
|
|
})
|
|
|
|
// Parse template
|
|
parsed, err := tmpl.Parse(templateContent)
|
|
if err != nil {
|
|
return "", fmt.Errorf("parsing template: %w", err)
|
|
}
|
|
|
|
// Execute template with context
|
|
var buf bytes.Buffer
|
|
context := map[string]interface{}{
|
|
"config": t.configData,
|
|
"secrets": t.secretsData,
|
|
}
|
|
|
|
err = parsed.Execute(&buf, context)
|
|
if err != nil {
|
|
return "", fmt.Errorf("executing template: %w", err)
|
|
}
|
|
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// ProcessFile processes a template file with Wild Cloud context
|
|
func (t *TemplateEngine) ProcessFile(templateFile string) (string, error) {
|
|
// Read file content
|
|
content, err := readFile(templateFile)
|
|
if err != nil {
|
|
return "", fmt.Errorf("reading template file: %w", err)
|
|
}
|
|
|
|
return t.Process(string(content))
|
|
}
|
|
|
|
// getValueByPath retrieves a value from nested data using dot-notation path
|
|
func (t *TemplateEngine) getValueByPath(data interface{}, path string) interface{} {
|
|
if path == "" {
|
|
return data
|
|
}
|
|
|
|
parts := strings.Split(path, ".")
|
|
current := data
|
|
|
|
for _, part := range parts {
|
|
switch v := current.(type) {
|
|
case map[string]interface{}:
|
|
var exists bool
|
|
current, exists = v[part]
|
|
if !exists {
|
|
return nil
|
|
}
|
|
case map[interface{}]interface{}:
|
|
var exists bool
|
|
current, exists = v[part]
|
|
if !exists {
|
|
return nil
|
|
}
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return current
|
|
}
|
|
|
|
// readFile is a helper to read file contents
|
|
func readFile(filename string) ([]byte, error) {
|
|
// This would be implemented to read from filesystem
|
|
// For now, returning empty to avoid import cycles
|
|
return nil, fmt.Errorf("file reading not implemented yet")
|
|
}
|
|
|
|
// CompileTemplate is a convenience function for one-off template processing
|
|
func CompileTemplate(templateContent string, configMgr *Manager) (string, error) {
|
|
engine, err := NewTemplateEngine(configMgr)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return engine.Process(templateContent)
|
|
}
|