Skip to content

Commit

Permalink
Refactoring code to add a build command
Browse files Browse the repository at this point in the history
  • Loading branch information
deepakjois committed Aug 21, 2024
1 parent 1e1e36b commit 105154d
Show file tree
Hide file tree
Showing 5 changed files with 324 additions and 228 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go-build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
run: go build ./...

- name: Run
run: ./debugjois.dev
run: ./debugjois.dev build

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
Expand Down
275 changes: 275 additions & 0 deletions build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
package main

import (
"bytes"
"fmt"
"html/template"
"io"
"log"
"os"
"path/filepath"
"sort"
"strings"
"time"

"github.com/bitfield/script"
"github.com/fsnotify/fsnotify"
"github.com/gorilla/feeds"
"github.com/otiai10/copy"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/parser"
"go.abhg.dev/goldmark/hashtag"
)

type BuildCmd struct {
Watch bool `help:"Watch for file changes and rebuild" default:"false"`
Dev bool `help:"Run in dev mode, which compiles scratch file and drafts" default:"false"`
md goldmark.Markdown
}

func (b *BuildCmd) Run() error {
b.md = goldmark.New(
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithExtensions(
&hashtag.Extender{Variant: hashtag.ObsidianVariant},
),
)
if !b.Watch {
return b.generateSite()
}

if watcher, err := fsnotify.NewWatcher(); err != nil {
return err
} else {
defer watcher.Close()

done := make(chan bool)
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Write == fsnotify.Write {
fmt.Println("Modified file:", event.Name)
err := b.generateSite()
if err != nil {
fmt.Printf("Build failed: %v\n", err)
}
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("Error:", err)
}
}
}()

for _, path := range []string{"content", "static", "templates"} {
err := watcher.Add(path)
if err != nil {
return fmt.Errorf("error adding directory to watch: %v", err)
}

}
fmt.Println("Watching for file changes. Press Ctrl+C to stop.")
<-done
}

return nil
}

// Page represents the structure of a web page.
type Page struct {
Title string
Body template.HTML
}

// Note represents a single daily note.
type Note struct {
Body template.HTML
Date string
}

func (b *BuildCmd) generateSite() error {
if err := os.MkdirAll("build", 0755); err != nil {
return fmt.Errorf("create build directory: %w", err)
}

if err := copy.Copy("static", "build"); err != nil {
return fmt.Errorf("copy static files: %w", err)
}

tmpl, err := template.ParseFiles("templates/shell.html")
if err != nil {
return fmt.Errorf("parse shell template: %w", err)
}

if err := generateIndexPage(tmpl); err != nil {
return fmt.Errorf("generate index page: %w", err)
}

if err := generateDailyNotesPage(b.md, tmpl); err != nil {
return fmt.Errorf("generate daily notes page: %w", err)
}

if b.Dev {
fmt.Println("generating scratch page")
if err := generateScratchPage(b.md, tmpl); err != nil {
return fmt.Errorf("generate scratch page: %w", err)
}
}
return nil
}

func generateIndexPage(tmpl *template.Template) error {
content, err := os.ReadFile("content/index.html")
if err != nil {
return fmt.Errorf("read index content: %w", err)
}

page := Page{
Title: "Deepak Jois",
Body: template.HTML(content),
}

return renderPage(tmpl, "build/index.html", page)
}

func generateDailyNotesPage(md goldmark.Markdown, tmpl *template.Template) error {
files, err := script.ListFiles("content/daily-notes/*.md").Slice()
if err != nil {
return fmt.Errorf("list daily notes: %w", err)
}

sort.Sort(sort.Reverse(sort.StringSlice(files)))

var notes []Note
for _, file := range files {
var buf bytes.Buffer
if err := convertMarkdownToHTML(md, file, &buf); err != nil {
return fmt.Errorf("convert note %s: %w", file, err)
}
date := strings.TrimSuffix(filepath.Base(file), ".md")
notes = append(notes, Note{Body: template.HTML(buf.String()), Date: date})
}

ntmpl, err := template.ParseFiles("templates/daily.html")
if err != nil {
return fmt.Errorf("parse daily notes template: %w", err)
}

var buf bytes.Buffer
if err := ntmpl.Execute(&buf, struct{ Notes []Note }{Notes: notes}); err != nil {
return fmt.Errorf("execute daily notes template: %w", err)
}

page := Page{
Title: "Deepak Jois · Daily Notes",
Body: template.HTML(buf.String()),
}

if err := renderPage(tmpl, "build/daily", page); err != nil {
return err
}

return renderDailyNotesFeed(notes)
}

func generateScratchPage(md goldmark.Markdown, tmpl *template.Template) error {
var buf bytes.Buffer
if err := convertMarkdownToHTML(md, "content/scratch.md", &buf); err != nil {
return fmt.Errorf("convert scratch: %w", err)
}

page := Page{
Title: "Scratch",
Body: template.HTML(buf.String()),
}

return renderPage(tmpl, "build/scratch", page)
}

func renderDailyNotesFeed(notes []Note) error {
feed := &feeds.AtomFeed{
Title: "Deepak Jois · Daily Log",
Subtitle: "Running log of links, code snippets and other miscellany.",
Link: &feeds.AtomLink{Href: "https://www.debugjois.dev/daily"},
Author: &feeds.AtomAuthor{AtomPerson: feeds.AtomPerson{Name: "Deepak Jois", Email: "[email protected]"}},
Logo: "https://www.debugjois.dev/android-chrome-512x512.png",
Icon: "https://www.debugjois.dev/favicon.ico",
Id: "https://www.debugjois.dev/daily",
Updated: time.Now().Format(time.RFC3339),
}

// Load the Asia/Kolkata time zone (IST)
ist, err := time.LoadLocation("Asia/Kolkata")
if err != nil {
return err
}

for _, note := range notes {
if note.Date == time.Now().In(ist).Format("2006-01-02") { // skip today
continue
}
var updated time.Time
if date, err := time.ParseInLocation("2006-01-02", note.Date, ist); err != nil {
return err
} else {
date = time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, ist)
updated = date.Add(24 * time.Hour)
}

entry := feeds.AtomEntry{
Title: note.Date,
Links: []feeds.AtomLink{
{Href: fmt.Sprintf("https://www.debugjois.dev/daily#%s", note.Date)},
},
Updated: updated.Format(time.RFC3339),
Id: note.Date,
Author: &feeds.AtomAuthor{AtomPerson: feeds.AtomPerson{Name: "Deepak Jois"}},
Content: &feeds.AtomContent{Content: string(note.Body), Type: "html"},
}
feed.Entries = append(feed.Entries, &entry)
}

f, err := os.Create("build/daily.xml")
if err != nil {
return fmt.Errorf("create atom file: %w", err)
}
defer f.Close()

return feeds.WriteXML(feed, f)

}

func convertMarkdownToHTML(md goldmark.Markdown, filename string, w io.Writer) error {
content, err := os.ReadFile(filename)
if err != nil {
return fmt.Errorf("read markdown file: %w", err)
}

if err := md.Convert(content, w); err != nil {
return fmt.Errorf("convert markdown to HTML: %w", err)
}

return nil
}

func renderPage(tmpl *template.Template, outputPath string, page Page) error {
f, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("create output file: %w", err)
}
defer f.Close()

if err := tmpl.Execute(f, page); err != nil {
return fmt.Errorf("execute page template: %w", err)
}

return nil
}
15 changes: 10 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ module github.com/deepakjois/debugjois.dev
go 1.23

require (
github.com/bitfield/script v0.22.1 // indirect
github.com/alecthomas/kong v0.9.0
github.com/bitfield/script v0.22.1
github.com/fsnotify/fsnotify v1.7.0
github.com/gorilla/feeds v1.2.0
github.com/otiai10/copy v1.14.0
github.com/yuin/goldmark v1.7.4
go.abhg.dev/goldmark/hashtag v0.3.1
)

require (
github.com/forPelevin/gomoji v1.1.3 // indirect
github.com/gorilla/feeds v1.2.0 // indirect
github.com/itchyny/gojq v0.12.13 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/otiai10/copy v1.14.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/yuin/goldmark v1.7.4 // indirect
go.abhg.dev/goldmark/hashtag v0.3.1 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.10.0 // indirect
mvdan.cc/sh/v3 v3.7.0 // indirect
Expand Down
32 changes: 32 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA=
github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/bitfield/script v0.22.1 h1:DphxoC5ssYciwd0ZS+N0Xae46geAD/0mVWh6a2NUxM4=
github.com/bitfield/script v0.22.1/go.mod h1:fv+6x4OzVsRs6qAlc7wiGq8fq1b5orhtQdtW0dwjUHI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/forPelevin/gomoji v1.1.3 h1:7c3dYzVmYhpOL3bS4riXqSWJBX3BhSvH68yoNNf3FH0=
github.com/forPelevin/gomoji v1.1.3/go.mod h1:ypB7Kz3Fsp+LVR7KoT7mEFOioYBuTuAtaAT4RGl+ASY=
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc=
github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.abhg.dev/goldmark/hashtag v0.3.1 h1:k0FQwEtVQ1SstIRR2fqDJ4VNYUS0AXLp869V0qHOZMg=
Expand All @@ -20,5 +48,9 @@ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
Loading

0 comments on commit 105154d

Please sign in to comment.