feat(templates): generalised templating from file contents to any gonf value
This commit is contained in:
parent
325f6e2130
commit
c1d2b8912d
4 changed files with 99 additions and 69 deletions
|
@ -5,9 +5,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// ----- Globals ---------------------------------------------------------------
|
||||
|
@ -19,26 +17,22 @@ func init() {
|
|||
}
|
||||
|
||||
// ----- Public ----------------------------------------------------------------
|
||||
func File(filename string, contents []byte) *FilePromise {
|
||||
return &FilePromise{
|
||||
chain: nil,
|
||||
contents: contents,
|
||||
err: nil,
|
||||
filename: filename,
|
||||
status: PROMISED,
|
||||
templateFunctions: nil,
|
||||
useTemplate: false,
|
||||
}
|
||||
type FilePromise struct {
|
||||
chain []Promise
|
||||
contents Value
|
||||
err error
|
||||
filename Value
|
||||
status Status
|
||||
}
|
||||
|
||||
type FilePromise struct {
|
||||
chain []Promise
|
||||
contents []byte
|
||||
err error
|
||||
filename string
|
||||
status Status
|
||||
templateFunctions map[string]any
|
||||
useTemplate bool
|
||||
func File(filename Value, contents Value) *FilePromise {
|
||||
return &FilePromise{
|
||||
chain: nil,
|
||||
contents: contents,
|
||||
err: nil,
|
||||
filename: filename,
|
||||
status: PROMISED,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FilePromise) IfRepaired(p ...Promise) Promise {
|
||||
|
@ -52,34 +46,17 @@ func (f *FilePromise) Promise() Promise {
|
|||
}
|
||||
|
||||
func (f *FilePromise) Resolve() {
|
||||
if f.useTemplate {
|
||||
tpl := template.New(f.filename)
|
||||
tpl.Option("missingkey=error")
|
||||
tpl.Funcs(builtinTemplateFunctions)
|
||||
tpl.Funcs(f.templateFunctions)
|
||||
if ttpl, err := tpl.Parse(string(f.contents)); err != nil {
|
||||
f.status = BROKEN
|
||||
slog.Error("file", "filename", f.filename, "status", f.status, "error", f.err)
|
||||
return
|
||||
} else {
|
||||
var buff bytes.Buffer
|
||||
if err := ttpl.Execute(&buff, 0 /* TODO */); err != nil {
|
||||
f.status = BROKEN
|
||||
slog.Error("file", "filename", f.filename, "status", f.status, "error", f.err)
|
||||
return
|
||||
}
|
||||
f.contents = buff.Bytes()
|
||||
}
|
||||
}
|
||||
filename := f.filename.String()
|
||||
var sumFile []byte
|
||||
sumFile, f.err = sha256sumOfFile(f.filename)
|
||||
sumFile, f.err = sha256sumOfFile(filename)
|
||||
if f.err != nil {
|
||||
f.status = BROKEN
|
||||
return
|
||||
}
|
||||
sumContents := sha256sum(f.contents)
|
||||
contents := f.contents.Bytes()
|
||||
sumContents := sha256sum(contents)
|
||||
if !bytes.Equal(sumFile, sumContents) {
|
||||
if f.err = writeFile(f.filename, f.contents); f.err != nil {
|
||||
if f.err = writeFile(filename, contents); f.err != nil {
|
||||
f.status = BROKEN
|
||||
slog.Error("file", "filename", f.filename, "status", f.status, "error", f.err)
|
||||
return
|
||||
|
@ -95,24 +72,7 @@ func (f *FilePromise) Resolve() {
|
|||
slog.Debug("file", "filename", f.filename, "status", f.status)
|
||||
}
|
||||
|
||||
func Template(filename string, contents []byte) *FilePromise {
|
||||
f := File(filename, contents)
|
||||
f.useTemplate = true
|
||||
return f
|
||||
}
|
||||
|
||||
func TemplateWith(filename string, contents []byte, templateFunctions map[string]any) *FilePromise {
|
||||
f := Template(filename, contents)
|
||||
f.templateFunctions = templateFunctions
|
||||
return f
|
||||
}
|
||||
|
||||
// ----- Internal --------------------------------------------------------------
|
||||
var builtinTemplateFunctions = map[string]any{
|
||||
"encodeURIQueryParameter": url.QueryEscape,
|
||||
"var": getVariable,
|
||||
}
|
||||
|
||||
func resolveFiles() (status Status) {
|
||||
status = KEPT
|
||||
for _, f := range files {
|
||||
|
|
45
gonf/templates.go
Normal file
45
gonf/templates.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package gonf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log/slog"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// ----- Globals ---------------------------------------------------------------
|
||||
var templates *template.Template
|
||||
|
||||
// ----- Init ------------------------------------------------------------------
|
||||
func init() {
|
||||
templates = template.New("")
|
||||
templates.Option("missingkey=error")
|
||||
templates.Funcs(builtinTemplateFunctions)
|
||||
}
|
||||
|
||||
// ----- Public ----------------------------------------------------------------
|
||||
type TemplateValue struct {
|
||||
contents []byte
|
||||
name string
|
||||
}
|
||||
|
||||
func (t *TemplateValue) Bytes() []byte {
|
||||
var buff bytes.Buffer
|
||||
if err := templates.ExecuteTemplate(&buff, t.name, nil /* no data needed */); err != nil {
|
||||
slog.Error("template", "step", "ExecuteTemplate", "name", t.name, "error", err)
|
||||
return nil
|
||||
}
|
||||
return buff.Bytes()
|
||||
}
|
||||
|
||||
func (t TemplateValue) String() string {
|
||||
return string(t.Bytes()[:])
|
||||
}
|
||||
|
||||
func Template(name string, contents []byte) *TemplateValue {
|
||||
tpl := templates.New(name)
|
||||
if _, err := tpl.Parse(string(contents)); err != nil {
|
||||
slog.Error("template", "step", "Parse", "name", name, "error", err)
|
||||
return nil
|
||||
}
|
||||
return &TemplateValue{contents, name}
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
package gonf
|
||||
|
||||
import "crypto/sha256"
|
||||
import (
|
||||
"crypto/sha256"
|
||||
)
|
||||
|
||||
var builtinTemplateFunctions = map[string]any{
|
||||
//"encodeURIQueryParameter": url.QueryEscape,
|
||||
"var": getVariable,
|
||||
}
|
||||
|
||||
func sha256sum(contents []byte) []byte {
|
||||
h := sha256.New()
|
||||
|
|
|
@ -1,23 +1,41 @@
|
|||
package gonf
|
||||
|
||||
type Value interface {
|
||||
Equals(Value) bool
|
||||
Bytes() []byte
|
||||
String() string
|
||||
}
|
||||
|
||||
// ----- String variables ------------------------------------------------------
|
||||
// ----- BytesValue -----------------------------------------------------------------
|
||||
type BytesValue struct {
|
||||
value []byte
|
||||
}
|
||||
|
||||
func (b BytesValue) Bytes() []byte {
|
||||
return b.value
|
||||
}
|
||||
|
||||
func (b BytesValue) String() string {
|
||||
return string(b.value[:])
|
||||
}
|
||||
|
||||
func Bytes(value []byte) *BytesValue {
|
||||
return &BytesValue{value}
|
||||
}
|
||||
|
||||
// ----- StringValue ----------------------------------------------------------------
|
||||
type StringValue struct {
|
||||
Value string
|
||||
value string
|
||||
}
|
||||
|
||||
func (s StringValue) Equals(v Value) bool {
|
||||
sv, ok := v.(StringValue)
|
||||
return ok && s.Value == sv.Value
|
||||
func (s StringValue) Bytes() []byte {
|
||||
return []byte(s.value)
|
||||
}
|
||||
|
||||
func (s StringValue) String() string {
|
||||
// TODO handle interpolation
|
||||
return s.Value
|
||||
return s.value
|
||||
}
|
||||
|
||||
func String(value string) *StringValue {
|
||||
return &StringValue{value}
|
||||
}
|
||||
|
||||
// TODO lists
|
||||
|
|
Loading…
Add table
Reference in a new issue