From 45c20d03663878f3508eaa9b961cb0cb12cc5574 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Wed, 24 Jul 2024 21:48:38 +0200 Subject: Got post exporting working --- src/cmd/export/posts.go | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 src/cmd/export/posts.go (limited to 'src/cmd/export/posts.go') diff --git a/src/cmd/export/posts.go b/src/cmd/export/posts.go new file mode 100644 index 0000000..f54fc2c --- /dev/null +++ b/src/cmd/export/posts.go @@ -0,0 +1,179 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "os" + "path/filepath" + "strings" + txttpl "text/template" + + gmnhg "github.com/tdemin/gmnhg" + + "dev.mediocregopher.com/mediocre-blog.git/src/gmi" + "dev.mediocregopher.com/mediocre-blog.git/src/http" + "dev.mediocregopher.com/mediocre-blog.git/src/post" + "dev.mediocregopher.com/mediocre-blog.git/src/render" + "dev.mediocregopher.com/mediocre-go-lib.git/mctx" + "dev.mediocregopher.com/mediocre-go-lib.git/mlog" +) + +var postFileExtensions = map[post.Format]string{ + post.FormatGemtext: "gmi", + post.FormatMarkdown: "md", +} + +func postTargetFormat(p post.StoredPost) post.Format { + if p.Format == post.FormatMarkdown && strings.Contains(p.Body, ` %s\n\n", post.Description)) + } + writeString(body) + + return err +} + +func writePosts( + urlBuilder render.URLBuilder, posts []post.StoredPost, path string, +) error { + f, err := os.Create(path) + if err != nil { + return fmt.Errorf("opening file: %w", err) + } + defer func() { _ = f.Close() }() + + writeString := func(str string) { + if err != nil { + return + } + _, err = f.WriteString(str) + } + + writeString("# Posts\n\n") + for _, p := range posts { + var ( + targetFormat = postTargetFormat(p) + u = urlBuilder.Post(p.ID) + ) + + if targetFormat == post.FormatMarkdown { + u = u.HTTP() + } + + writeString(fmt.Sprintf( + "=> %s %s - %s\n\n", + u.String(), + p.PublishedAt.Format("2006-01-02"), + p.Title, + )) + } + + return err +} + +func exportPosts( + ctx context.Context, + logger *mlog.Logger, + postStore post.Store, + urlBuilder render.URLBuilder, + exportDirPath string, +) error { + var ( + postsDir = filepath.Join(exportDirPath, "posts") + preprocessFuncs = map[post.Format]post.PreprocessFunctions{ + post.FormatGemtext: gmi.PostPreprocessFuncs{URLBuilder: urlBuilder}, + post.FormatMarkdown: http.NewPostPreprocessFuncs(urlBuilder), + } + ) + + if err := os.MkdirAll(postsDir, 0755); err != nil { + return fmt.Errorf("creating posts dir %q: %w", postsDir, err) + } + + logger.Info(ctx, "Getting posts") + posts, _, err := postStore.Get(0, 10000) + if err != nil { + return fmt.Errorf("getting posts: %w", err) + } + + { + postsIndexPath := filepath.Join(postsDir, "index.gmi") + ctx := mctx.Annotate(ctx, "path", postsIndexPath) + logger.Info(ctx, "Writing posts index page") + err = writePosts(urlBuilder, posts, postsIndexPath) + if err != nil { + return fmt.Errorf("writing posts index page: %w", err) + } + } + + for _, p := range posts { + var ( + targetFormat = postTargetFormat(p) + ext = postFileExtensions[targetFormat] + postFilePath = filepath.Join(postsDir, p.ID+"."+ext) + + ctx = mctx.Annotate( + ctx, + "post_id", p.ID, + "post_title", p.Title, + "post_format", p.Format, + "target_format", targetFormat, + ) + + body = new(bytes.Buffer) + ) + + logger.Info(ctx, "Rendering post body") + tpl := txttpl.New("") + + tpl, err := tpl.Parse(p.Body) + if err != nil { + return fmt.Errorf("parsing post %q body as template: %w", p.ID, err) + } + + err = tpl.Execute(body, struct { + RootURL render.URLBuilder + post.PreprocessFunctions + }{ + urlBuilder, preprocessFuncs[targetFormat], + }) + if err != nil { + return fmt.Errorf("executing post %q body as template: %w", p.ID, err) + } + + if p.Format == post.FormatMarkdown && targetFormat == post.FormatGemtext { + gemtextBodyBytes, err := gmnhg.RenderMarkdown(body.Bytes(), 0) + if err != nil { + return fmt.Errorf("converting post %q from markdown: %w", p.ID, err) + } + body = bytes.NewBuffer(gemtextBodyBytes) + } + + if err := writePostBody(p, postFilePath, body.String()); err != nil { + return fmt.Errorf("writing post %q body to file %q: %w", p.ID, postFilePath, err) + } + } + + return nil +} -- cgit v1.2.3