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"
|
"crypto/sha256"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"text/template"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ----- Globals ---------------------------------------------------------------
|
// ----- Globals ---------------------------------------------------------------
|
||||||
|
@ -19,28 +17,24 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- Public ----------------------------------------------------------------
|
// ----- Public ----------------------------------------------------------------
|
||||||
func File(filename string, contents []byte) *FilePromise {
|
type FilePromise struct {
|
||||||
|
chain []Promise
|
||||||
|
contents Value
|
||||||
|
err error
|
||||||
|
filename Value
|
||||||
|
status Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func File(filename Value, contents Value) *FilePromise {
|
||||||
return &FilePromise{
|
return &FilePromise{
|
||||||
chain: nil,
|
chain: nil,
|
||||||
contents: contents,
|
contents: contents,
|
||||||
err: nil,
|
err: nil,
|
||||||
filename: filename,
|
filename: filename,
|
||||||
status: PROMISED,
|
status: PROMISED,
|
||||||
templateFunctions: nil,
|
|
||||||
useTemplate: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilePromise struct {
|
|
||||||
chain []Promise
|
|
||||||
contents []byte
|
|
||||||
err error
|
|
||||||
filename string
|
|
||||||
status Status
|
|
||||||
templateFunctions map[string]any
|
|
||||||
useTemplate bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FilePromise) IfRepaired(p ...Promise) Promise {
|
func (f *FilePromise) IfRepaired(p ...Promise) Promise {
|
||||||
f.chain = p
|
f.chain = p
|
||||||
return f
|
return f
|
||||||
|
@ -52,34 +46,17 @@ func (f *FilePromise) Promise() Promise {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FilePromise) Resolve() {
|
func (f *FilePromise) Resolve() {
|
||||||
if f.useTemplate {
|
filename := f.filename.String()
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var sumFile []byte
|
var sumFile []byte
|
||||||
sumFile, f.err = sha256sumOfFile(f.filename)
|
sumFile, f.err = sha256sumOfFile(filename)
|
||||||
if f.err != nil {
|
if f.err != nil {
|
||||||
f.status = BROKEN
|
f.status = BROKEN
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sumContents := sha256sum(f.contents)
|
contents := f.contents.Bytes()
|
||||||
|
sumContents := sha256sum(contents)
|
||||||
if !bytes.Equal(sumFile, sumContents) {
|
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
|
f.status = BROKEN
|
||||||
slog.Error("file", "filename", f.filename, "status", f.status, "error", f.err)
|
slog.Error("file", "filename", f.filename, "status", f.status, "error", f.err)
|
||||||
return
|
return
|
||||||
|
@ -95,24 +72,7 @@ func (f *FilePromise) Resolve() {
|
||||||
slog.Debug("file", "filename", f.filename, "status", f.status)
|
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 --------------------------------------------------------------
|
// ----- Internal --------------------------------------------------------------
|
||||||
var builtinTemplateFunctions = map[string]any{
|
|
||||||
"encodeURIQueryParameter": url.QueryEscape,
|
|
||||||
"var": getVariable,
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveFiles() (status Status) {
|
func resolveFiles() (status Status) {
|
||||||
status = KEPT
|
status = KEPT
|
||||||
for _, f := range files {
|
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
|
package gonf
|
||||||
|
|
||||||
import "crypto/sha256"
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
)
|
||||||
|
|
||||||
|
var builtinTemplateFunctions = map[string]any{
|
||||||
|
//"encodeURIQueryParameter": url.QueryEscape,
|
||||||
|
"var": getVariable,
|
||||||
|
}
|
||||||
|
|
||||||
func sha256sum(contents []byte) []byte {
|
func sha256sum(contents []byte) []byte {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
|
|
|
@ -1,23 +1,41 @@
|
||||||
package gonf
|
package gonf
|
||||||
|
|
||||||
type Value interface {
|
type Value interface {
|
||||||
Equals(Value) bool
|
Bytes() []byte
|
||||||
String() string
|
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 {
|
type StringValue struct {
|
||||||
Value string
|
value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StringValue) Equals(v Value) bool {
|
func (s StringValue) Bytes() []byte {
|
||||||
sv, ok := v.(StringValue)
|
return []byte(s.value)
|
||||||
return ok && s.Value == sv.Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StringValue) String() string {
|
func (s StringValue) String() string {
|
||||||
// TODO handle interpolation
|
return s.value
|
||||||
return s.Value
|
}
|
||||||
|
|
||||||
|
func String(value string) *StringValue {
|
||||||
|
return &StringValue{value}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO lists
|
// TODO lists
|
||||||
|
|
Loading…
Add table
Reference in a new issue