diff options
Diffstat (limited to 'cmd/build')
-rw-r--r-- | cmd/build/main.go | 123 |
1 files changed, 71 insertions, 52 deletions
diff --git a/cmd/build/main.go b/cmd/build/main.go index 68bba43..81d31e9 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -5,6 +5,7 @@ import ( "encoding/json" "encoding/xml" "fmt" + "io" "io/fs" "log" "log/slog" @@ -179,10 +180,19 @@ func layout(filename string, config Config, pageTitle string) (*goquery.Document return doc, nil } -func renderPost(post Post, config Config) (string, error) { +func renderHTML(doc *goquery.Document) io.Reader { + r, w := io.Pipe() + go func() { + goquery.Render(w, doc.Children()) + defer w.Close() + }() + return r +} + +func renderPost(post Post, config Config) (r io.Reader, err error) { doc, err := layout("templates/post.html", config, post.PostMatter.Title) if err != nil { - return "", err + return nil, err } doc.Find(".title").AddClass("p-author h-card").SetAttr("rel", "author") doc.Find(".h-entry .dt-published"). @@ -199,13 +209,14 @@ func renderPost(post Post, config Config) (string, error) { cat.Find(".p-category").SetAttr("href", fmt.Sprintf("/tags/%s/", tag)).SetText("#" + tag) categories.AppendSelection(cat) } - return doc.Html() + + return renderHTML(doc), nil } -func renderTags(tags Tags, config Config) (string, error) { +func renderTags(tags Tags, config Config) (io.Reader, error) { doc, err := layout("templates/tags.html", config, config.Title) if err != nil { - return "", err + return nil, err } tagList := doc.Find(".tags") tpl := doc.Find(".h-feed") @@ -215,10 +226,10 @@ func renderTags(tags Tags, config Config) (string, error) { li.Find("a").SetAttr("href", fmt.Sprintf("/tags/%s/", tag)).SetText("#" + tag) tagList.AppendSelection(li) } - return doc.Html() + return renderHTML(doc), nil } -func renderListPage(tag string, config Config, posts []Post) (string, error) { +func renderListPage(tag string, config Config, posts []Post) (io.Reader, error) { var title string if len(tag) > 0 { title = tag @@ -227,7 +238,7 @@ func renderListPage(tag string, config Config, posts []Post) (string, error) { } doc, err := layout("templates/list.html", config, title) if err != nil { - return "", err + return nil, err } feed := doc.Find(".h-feed") tpl := feed.Find(".h-entry") @@ -249,17 +260,17 @@ func renderListPage(tag string, config Config, posts []Post) (string, error) { feed.AppendSelection(entry) } - return doc.Html() + return renderHTML(doc), nil } -func renderHomepage(config Config, posts []Post) (string, error) { +func renderHomepage(config Config, posts []Post) (io.Reader, error) { _, index, err := getPost("content/_index.md") if err != nil { - return "", err + return nil, err } doc, err := layout("templates/homepage.html", config, config.Title) if err != nil { - return "", err + return nil, err } doc.Find("body").AddClass("h-card") doc.Find(".title").AddClass("p-name u-url") @@ -267,7 +278,7 @@ func renderHomepage(config Config, posts []Post) (string, error) { md := goldmark.New(goldmark.WithRendererOptions(html.WithUnsafe())) if err := md.Convert(*index, &buf); err != nil { - return "", err + return nil, err } doc.Find("#content").SetHtml(buf.String()) @@ -300,21 +311,21 @@ func renderHomepage(config Config, posts []Post) (string, error) { elsewhere.AppendSelection(el) } - return doc.Html() + return renderHTML(doc), nil } -func render404(config Config) (string, error) { +func render404(config Config) (io.Reader, error) { doc, err := layout("templates/404.html", config, "404 Not Found") if err != nil { - return "", err + return nil, err } - return doc.Html() + return renderHTML(doc), nil } -func renderFeed(title string, config Config, posts []Post, specific string) (string, error) { +func renderFeed(title string, config Config, posts []Post, specific string) (io.Reader, error) { reader, err := os.Open("templates/feed.xml") if err != nil { - return "", err + return nil, err } defer reader.Close() doc, err := xmlquery.Parse(reader) @@ -330,7 +341,7 @@ func renderFeed(title string, config Config, posts []Post, specific string) (str for _, post := range posts { fullURL, err := url.JoinPath(config.BaseURL, post.URL) if err != nil { - return "", err + return nil, err } text, err := xml.MarshalIndent(&FeedEntry{ Title: post.Title, @@ -345,7 +356,7 @@ func renderFeed(title string, config Config, posts []Post, specific string) (str }, }, " ", " ") if err != nil { - return "", err + return nil, err } entry, err := xmlquery.ParseWithOptions(strings.NewReader(string(text)), xmlquery.ParserOptions{ Decoder: &xmlquery.DecoderOptions{ @@ -355,18 +366,18 @@ func renderFeed(title string, config Config, posts []Post, specific string) (str }, }) if err != nil { - return "", err + return nil, err } xmlquery.AddChild(feed, entry.SelectElement("entry")) } - return doc.OutputXML(true), nil + return strings.NewReader(doc.OutputXML(true)), nil } -func renderFeedStyles() (string, error) { +func renderFeedStyles() (io.Reader, error) { reader, err := os.Open("templates/feed-styles.xsl") if err != nil { - return "", err + return nil, err } defer reader.Close() nsMap := map[string]string{ @@ -377,22 +388,31 @@ func renderFeedStyles() (string, error) { doc, err := xmlquery.Parse(reader) expr, err := xpath.CompileWithNS("//xhtml:style", nsMap) if err != nil { - return "", err + return nil, err } style := xmlquery.QuerySelector(doc, expr) css, err := os.ReadFile("templates/style.css") if err != nil { - return "", err + return nil, err } xmlquery.AddChild(style, &xmlquery.Node{ Type: xmlquery.TextNode, Data: string(css), }) - return doc.OutputXML(true), nil + return strings.NewReader(doc.OutputXML(true)), nil } -type errFiler struct { - err error +func outputToFile(output io.Reader, filename ...string) error { + file, err := os.OpenFile(path.Join(filename...), os.O_WRONLY|os.O_CREATE, 00644) + if err != nil { + return errors.WithMessage(err, "could not open output file") + } + defer file.Close() + + if _, err := file.ReadFrom(output); err != nil { + return errors.WithMessage(err, "could not write output file") + } + return nil } func build() error { @@ -418,21 +438,20 @@ func build() error { if err != nil { return errors.WithMessagef(err, "could not render post %s", post.Input) } - if err := os.WriteFile(post.Output, []byte(output), 0755); err != nil { - return errors.WithMessage(err, "could not write output file") + if err := outputToFile(output, post.Output); err != nil { + return err } } if err := os.MkdirAll(path.Join(outDir, "tags"), 0755); err != nil { return errors.WithMessage(err, "could not create directory for tags") } - tagsHtml, err := renderTags(tags, *config) + output, err := renderTags(tags, *config) if err != nil { return errors.WithMessage(err, "could not render tags") } - err = os.WriteFile(path.Join(outDir, "tags", "index.html"), []byte(tagsHtml), 0644) - if err != nil { - return errors.WithMessage(err, "could not write output file") + if err := outputToFile(output, outDir, "tags", "index.html"); err != nil { + return err } for _, tag := range tags.ToSlice() { @@ -445,60 +464,60 @@ func build() error { if err := os.MkdirAll(path.Join(outDir, "tags", tag), 0755); err != nil { return errors.WithMessage(err, "could not create directory") } - tagPage, err := renderListPage(tag, *config, matchingPosts) + output, err := renderListPage(tag, *config, matchingPosts) if err != nil { return errors.WithMessage(err, "could not render tag page") } - if err := os.WriteFile(path.Join(outDir, "tags", tag, "index.html"), []byte(tagPage), 0644); err != nil { - return errors.WithMessage(err, "could not write tag output file") + if err := outputToFile(output, outDir, "tags", tag, "index.html"); err != nil { + return err } - feedPage, err := renderFeed(fmt.Sprintf("%s - %s", config.Title, tag), *config, matchingPosts, tag) + output, err = renderFeed(fmt.Sprintf("%s - %s", config.Title, tag), *config, matchingPosts, tag) if err != nil { return errors.WithMessage(err, "could not render tag feed page") } - if err := os.WriteFile(path.Join(outDir, "tags", tag, "atom.xml"), []byte(feedPage), 0644); err != nil { - return errors.WithMessage(err, "could not write tag feed output file") + if err := outputToFile(output, outDir, "tags", tag, "atom.xml"); err != nil { + return err } } listPage, err := renderListPage("", *config, posts) if err != nil { return errors.WithMessage(err, "could not render list page") } - if err := os.WriteFile(path.Join(outDir, "post", "index.html"), []byte(listPage), 0644); err != nil { - return errors.WithMessage(err, "could not write list page output file") + if err := outputToFile(listPage, outDir, "post", "index.html"); err != nil { + return err } feed, err := renderFeed(config.Title, *config, posts, "feed") if err != nil { return errors.WithMessage(err, "could not render feed") } - if err := os.WriteFile(path.Join(outDir, "atom.xml"), []byte(feed), 0644); err != nil { - return errors.WithMessage(err, "could not write feed") + if err := outputToFile(feed, outDir, "atom.xml"); err != nil { + return err } feedStyles, err := renderFeedStyles() if err != nil { return errors.WithMessage(err, "could not render feed styles") } - if err := os.WriteFile(path.Join(outDir, "feed-styles.xsl"), []byte(feedStyles), 0644); err != nil { - return errors.WithMessage(err, "could not write feed styles") + if err := outputToFile(feedStyles, outDir, "feed-styles.xsl"); err != nil { + return err } homePage, err := renderHomepage(*config, posts) if err != nil { return errors.WithMessage(err, "could not render homepage") } - if err := os.WriteFile(path.Join(outDir, "index.html"), []byte(homePage), 0644); err != nil { - return errors.WithMessage(err, "could not write homepage") + if err := outputToFile(homePage, outDir, "index.html"); err != nil { + return err } notFound, err := render404(*config) if err != nil { return errors.WithMessage(err, "could not render 404 page") } - if err := os.WriteFile(path.Join(outDir, "404.html"), []byte(notFound), 0644); err != nil { - return errors.WithMessage(err, "could not write 404 file") + if err := outputToFile(notFound, outDir, "404.html"); err != nil { + return err } return nil |