internal/builder/template/template.go (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | package template
import (
"bytes"
"encoding/xml"
"io"
"text/template"
"go.alanpearce.eu/homestead/internal/atom"
"go.alanpearce.eu/homestead/internal/config"
"go.alanpearce.eu/homestead/internal/content"
"go.alanpearce.eu/homestead/templates"
"github.com/PuerkitoBio/goquery"
"github.com/antchfx/xmlquery"
"github.com/antchfx/xpath"
"gitlab.com/tozd/go/errors"
)
var (
nsMap = map[string]string{
"xsl": "http://www.w3.org/1999/XSL/Transform",
"atom": "http://www.w3.org/2005/Atom",
"xhtml": "http://www.w3.org/1999/xhtml",
}
)
func RenderRobotsTXT(baseURL config.URL, w io.Writer) errors.E {
tpl, err := template.ParseFS(templates.Files, "robots.tmpl")
if err != nil {
return errors.WithStack(err)
}
err = tpl.Execute(w, map[string]any{
"BaseURL": baseURL,
})
if err != nil {
return errors.WithStack(err)
}
return nil
}
func RenderFeed(
title string,
config *config.Config,
posts []*content.Post,
specific string,
) (io.WriterTo, errors.E) {
buf := &bytes.Buffer{}
datetime := posts[0].Date.UTC()
buf.WriteString(xml.Header)
err := atom.LinkXSL(buf, "/feed-styles.xsl")
if err != nil {
return nil, err
}
feed := &atom.Feed{
Title: title,
Link: atom.MakeLink(config.BaseURL.URL),
ID: atom.MakeTagURI(config, specific),
Updated: datetime,
Entries: make([]*atom.FeedEntry, len(posts)),
}
for i, post := range posts {
html, err := post.RenderString()
if err != nil {
return nil, errors.WithMessage(err, "could not render post")
}
feed.Entries[i] = &atom.FeedEntry{
Title: post.Title,
Link: atom.MakeLink(config.BaseURL.JoinPath(post.URL)),
ID: atom.MakeTagURI(config, post.Basename),
Updated: post.Date.UTC(),
Summary: post.Description,
Author: config.Title,
Content: atom.FeedContent{
Content: html,
Type: "html",
},
}
}
enc := xml.NewEncoder(buf)
if err := enc.Encode(feed); err != nil {
return nil, errors.WithStack(err)
}
return buf, nil
}
func CopyFile(filename string, w io.Writer) errors.E {
f, err := templates.Files.Open(filename)
if err != nil {
return errors.WithStack(err)
}
defer f.Close()
if _, err := io.Copy(w, f); err != nil {
return errors.WithStack(err)
}
return nil
}
func GetFeedStyleHash(r io.Reader) (string, errors.E) {
doc, err := xmlquery.Parse(r)
if err != nil {
return "", errors.WithStack(err)
}
expr, err := xpath.CompileWithNS("//xhtml:style", nsMap)
if err != nil {
return "", errors.WithMessage(err, "could not parse XPath")
}
style := xmlquery.QuerySelector(doc, expr)
return Hash(style.InnerText()), nil
}
func GetHTMLStyleHash(r io.Reader) (string, errors.E) {
doc, err := goquery.NewDocumentFromReader(r)
if err != nil {
return "", errors.WithStack(err)
}
html := doc.Find("head > style").Text()
return Hash(html), nil
}
|