makeshift/pkg/generator/templates.go

98 lines
2.7 KiB
Go

package generator
import (
"bytes"
"fmt"
"os"
"git.towk2.me/towk/configurator/pkg/util"
"github.com/nikolalohinski/gonja/v2"
"github.com/nikolalohinski/gonja/v2/exec"
"github.com/rs/zerolog/log"
)
type Template struct {
Contents []byte `json:"contents"`
}
func (t *Template) LoadFromFile(path string) error {
// skip loading template if path is a directory with no error
if isDir, err := util.IsDirectory(path); err == nil && isDir {
return nil
} else if err != nil {
return fmt.Errorf("failed to test if template path is directory: %w", err)
}
// try and read the contents of the file
// NOTE: we don't care if this is actually a Jinja template
// or not...at least for now.
contents, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read file: %v", err)
}
t.Contents = contents
return nil
}
func (t *Template) IsEmpty() bool {
return len(t.Contents) <= 0
}
// Wrapper function to slightly abstract away some of the nuances with using gonja
// into a single function call. This function is *mostly* for convenience and
// simplication. If no paths are supplied, then no templates will be applied and
// there will be no output.
//
// The "FileList" returns a slice of byte arrays in the same order as the argument
// list supplied, but with the Jinja templating applied.
func ApplyTemplates(mappings Mappings, templates map[string]Template) (FileMap, error) {
var (
data = exec.NewContext(mappings)
outputs = FileMap{}
)
for path, template := range templates {
// load jinja template from file
t, err := gonja.FromBytes(template.Contents)
if err != nil {
return nil, fmt.Errorf("failed to read template from file: %w", err)
}
// execute/render jinja template
b := bytes.Buffer{}
if err = t.Execute(&b, data); err != nil {
return nil, fmt.Errorf("failed to execute: %w", err)
}
outputs[path] = b.Bytes()
}
log.Debug().Any("templates", templates).Any("outputs", outputs).Any("mappings", mappings).Msg("apply templates")
return outputs, nil
}
// Wrapper function similiar to "ApplyTemplates" but takes file paths as arguments.
// This function will load templates from a file instead of using file contents.
func ApplyTemplateFromFiles(mappings Mappings, paths ...string) (FileMap, error) {
var (
data = exec.NewContext(mappings)
outputs = FileMap{}
)
for _, path := range paths {
// load jinja template from file
t, err := gonja.FromFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read template from file: %w", err)
}
// execute/render jinja template
b := bytes.Buffer{}
if err = t.Execute(&b, data); err != nil {
return nil, fmt.Errorf("failed to execute: %w", err)
}
outputs[path] = b.Bytes()
}
return outputs, nil
}