use buffers as interface to storage
1 file changed, 63 insertions(+), 32 deletions(-)
changed files
M internal/builder/builder.go → internal/builder/builder.go
@@ -1,6 +1,7 @@ package builder import ( + "context" "fmt" "io" "io/fs"@@ -10,6 +11,7 @@ "path/filepath" "slices" "time" + "go.alanpearce.eu/website/internal/buffer" "go.alanpearce.eu/website/internal/config" "go.alanpearce.eu/website/internal/content" "go.alanpearce.eu/website/internal/sitemap"@@ -39,6 +41,7 @@ } } func copyRecursive(storage storage.Writer, src string) error { + buf := new(buffer.Buffer) return filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error { if err != nil { return err@@ -56,12 +59,11 @@ if err != nil { return err } defer sf.Close() - df, err := storage.OpenFileAndVariants(rel) - if err != nil { + buf.Reset() + if _, err := io.Copy(buf, sf); err != nil { return err } - defer df.Close() - if _, err := io.Copy(df, sf); err != nil { + if err := storage.Write("/"+rel, buf); err != nil { return err }@@ -76,6 +78,8 @@ ioConfig *IOConfig, config *config.Config, log *log.Logger, ) (*Result, error) { + ctx := context.TODO() + buf := new(buffer.Buffer) joinSource := joinSourcePath(ioConfig.Source) log.Debug("output", "dir", ioConfig.Destination)@@ -106,16 +110,21 @@ for _, post := range posts { log.Debug("rendering post", "post", post.Basename) sitemap.AddPath(post.URL, post.Date) - if err := storage.RenderToFile(templates.PostPage(config, post), post.Output); err != nil { + if err := templates.PostPage(config, post).Render(ctx, buf); err != nil { + return nil, errors.WithMessage(err, "could not render post") + } + + if err := storage.Write(post.URL, buf); err != nil { return nil, err } } log.Debug("rendering tags list") - if err := storage.RenderToFile( - templates.TagsPage(config, "tags", mapset.Sorted(tags), "/tags"), - "tags/", - ); err != nil { + buf.Reset() + if err := templates.TagsPage(config, "tags", mapset.Sorted(tags), "/tags").Render(ctx, buf); err != nil { + return nil, err + } + if err := storage.Write("/tags/", buf); err != nil { return nil, err } sitemap.AddPath("/tags/", lastMod)@@ -128,11 +137,12 @@ matchingPosts = append(matchingPosts, post) } } log.Debug("rendering tags page", "tag", tag) - url := path.Join("tags", tag) + "/" - if err := storage.RenderToFile( - templates.TagPage(config, tag, matchingPosts, url), - url, - ); err != nil { + url := path.Join("/tags", tag) + "/" + buf.Reset() + if err := templates.TagPage(config, tag, matchingPosts, url).Render(ctx, buf); err != nil { + return nil, err + } + if err = storage.Write(url, buf); err != nil { return nil, err } sitemap.AddPath(url, matchingPosts[0].Date)@@ -147,16 +157,21 @@ ) if err != nil { return nil, errors.WithMessage(err, "could not render tag feed page") } - if err := storage.WriterToFile(feed, path.Join("tags", tag, "atom.xml")); err != nil { + buf.Reset() + if _, err := feed.WriteTo(buf); err != nil { + return nil, err + } + if err := storage.Write(path.Join("/tags", tag, "atom.xml"), buf); err != nil { return nil, err } } log.Debug("rendering list page") - if err := storage.RenderToFile( - templates.ListPage(config, posts, "/post"), - "post/", - ); err != nil { + buf.Reset() + if err := templates.ListPage(config, posts, "/post").Render(ctx, buf); err != nil { + return nil, err + } + if err := storage.Write("/post/", buf); err != nil { return nil, err } sitemap.AddPath("/post/", lastMod)@@ -166,7 +181,11 @@ feed, err := renderFeed(config.Title, config, posts, "feed") if err != nil { return nil, errors.WithMessage(err, "could not render feed") } - if err := storage.WriterToFile(feed, "atom.xml"); err != nil { + buf.Reset() + if _, err := feed.WriteTo(buf); err != nil { + return nil, err + } + if err := storage.Write("/atom.xml", buf); err != nil { return nil, err }@@ -175,7 +194,11 @@ feedStyles, err := renderFeedStyles(ioConfig.Source) if err != nil { return nil, errors.WithMessage(err, "could not render feed styles") } - if err := storage.OutputToFile(feedStyles, "feed-styles.xsl"); err != nil { + buf.Reset() + if _, err := feedStyles.WriteTo(buf); err != nil { + return nil, err + } + if err := storage.Write("/feed-styles.xsl", buf); err != nil { return nil, err } _, err = feedStyles.Seek(0, 0)@@ -197,23 +220,25 @@ content, err := content.RenderMarkdown(text) if err != nil { return nil, err } - if err := storage.RenderToFile(templates.Homepage(config, posts, content), "/"); err != nil { + buf.Reset() + if err := templates.Homepage(config, posts, content).Render(ctx, buf); err != nil { + return nil, err + } + if err := storage.Write("/", buf); err != nil { return nil, err } + // it would be nice to set LastMod here, but using the latest post // date would be wrong as the homepage has its own content file // without a date, which could be newer sitemap.AddPath("/", time.Time{}) - f, err := storage.Open("/") - if err != nil { - return nil, err - } - defer f.Close() - h, _ = getHTMLStyleHash(f) + h, _ = getHTMLStyleHash(buf) r.Hashes = append(r.Hashes, h) log.Debug("rendering sitemap") - if err := storage.WriterToFile(sitemap, "sitemap.xml"); err != nil { + buf.Reset() + sitemap.WriteTo(buf) + if err := storage.Write("/sitemap.xml", buf); err != nil { return nil, err }@@ -222,7 +247,11 @@ rob, err := renderRobotsTXT(ioConfig.Source, config) if err != nil { return nil, err } - if err := storage.OutputToFile(rob, "robots.txt"); err != nil { + buf.Reset() + if _, err := io.Copy(buf, rob); err != nil { + return nil, err + } + if err := storage.Write("/robots.txt", buf); err != nil { return nil, err }@@ -238,10 +267,12 @@ templates.Setup() loadCSS(ioConfig.Source) - var storage storage.Writer - storage = files.NewWriter(ioConfig.Destination, log, &files.Options{ + storage, err := files.NewWriter(ioConfig.Destination, log, &files.Options{ Compress: !ioConfig.Development, }) + if err != nil { + return nil, errors.WithMessage(err, "could not create storage writer") + } return build(storage, ioConfig, cfg, log) }