Implement frontmatter and site configuration

This commit is contained in:
adnano 2020-11-10 19:33:45 -05:00
parent 7b6efd6fb8
commit 99e1906d90
4 changed files with 108 additions and 63 deletions

5
go.mod
View file

@ -2,4 +2,7 @@ module kiln
go 1.15 go 1.15
require git.sr.ht/~adnano/go-gemini v0.1.4 require (
git.sr.ht/~adnano/go-gemini v0.1.8
git.sr.ht/~adnano/go-ini v0.0.0-20201014024959-cc89f6531f0e
)

6
go.sum
View file

@ -1,2 +1,4 @@
git.sr.ht/~adnano/go-gemini v0.1.4 h1:va3yFDqPQHwcE6AxaP1gBkPlOkSeLXJJqdTTjQzBppY= git.sr.ht/~adnano/go-gemini v0.1.8 h1:93DxDNXB0bjnfDhZewf+QsEopfuOMh/I4v7ujoJ6WIs=
git.sr.ht/~adnano/go-gemini v0.1.4/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3VJ5rnZWKq0= git.sr.ht/~adnano/go-gemini v0.1.8/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3VJ5rnZWKq0=
git.sr.ht/~adnano/go-ini v0.0.0-20201014024959-cc89f6531f0e h1:NRVtAaE3jvBKkwX/x7/yGeQKe8Agj13VDoKKOEE04aA=
git.sr.ht/~adnano/go-ini v0.0.0-20201014024959-cc89f6531f0e/go.mod h1:eysIkA6b8oivxACZfyG75+wlq6BW6t5qPVnx8IcFYlE=

100
main.go
View file

@ -3,17 +3,20 @@ package main
import ( import (
"bytes" "bytes"
"flag" "flag"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"sort" "sort"
"strconv"
"strings" "strings"
"text/template" "text/template"
"time" "time"
"git.sr.ht/~adnano/go-gemini" "git.sr.ht/~adnano/go-gemini"
"git.sr.ht/~adnano/go-ini"
) )
const ( const (
@ -35,25 +38,46 @@ var cfg struct {
url string // site URL url string // site URL
toAtom bool // output Atom toAtom bool // output Atom
toHTML bool // output HTML toHTML bool // output HTML
serveSite bool // serve the site
}
func init() {
flag.StringVar(&cfg.title, "title", "", "site title")
flag.StringVar(&cfg.url, "url", "", "site URL")
flag.BoolVar(&cfg.toAtom, "atom", false, "output Atom feed")
flag.BoolVar(&cfg.toHTML, "html", false, "output HTML")
flag.BoolVar(&cfg.serveSite, "serve", false, "serve the site")
} }
func main() { func main() {
// Try to read config file
if f, err := os.Open("config.ini"); err == nil {
ini.Parse(f, func(section, key, value string) {
if section == "" {
switch key {
case "title":
cfg.title = value
case "url":
cfg.url = value
case "atom":
b, err := strconv.ParseBool(value)
if err != nil {
fmt.Println(err)
break
}
cfg.toAtom = b
case "html":
b, err := strconv.ParseBool(value)
if err != nil {
fmt.Println(err)
break
}
cfg.toHTML = b
case "serve":
b, err := strconv.ParseBool(value)
if err != nil {
fmt.Println(err)
break
}
}
}
})
}
flag.Parse() flag.Parse()
if err := run(); err != nil { if err := run(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if cfg.serveSite {
serve()
}
} }
// site metadata passed to templates // site metadata passed to templates
@ -150,14 +174,6 @@ func run() error {
return nil return nil
} }
// serve the site
func serve() error {
var server gemini.Server
server.Certificates.Load("/var/lib/gemini/certs")
server.Register("localhost", gemini.FileServer(gemini.Dir("dst")))
return server.ListenAndServe()
}
// write writes the contents of the Index to the provided destination directory. // write writes the contents of the Index to the provided destination directory.
func write(dir *Dir, dstDir string, format outputFormat) error { func write(dir *Dir, dstDir string, format outputFormat) error {
// Empty the destination directory // Empty the destination directory
@ -249,16 +265,42 @@ func (p *Page) Content() string {
// Regexp to parse title from Gemini files // Regexp to parse title from Gemini files
var titleRE = regexp.MustCompile("^# ?([^#\r\n]+)\r?\n?\r?\n?") var titleRE = regexp.MustCompile("^# ?([^#\r\n]+)\r?\n?\r?\n?")
// Regexp to parse frontmatter from Gemini files
var frontmatterRE = regexp.MustCompile("---\r?\n(?s)(.*)(?-s)---\r?\n?")
// NewPage returns a new Page with the given path and content. // NewPage returns a new Page with the given path and content.
func NewPage(path string, content []byte) *Page { func NewPage(path string, content []byte) *Page {
var page Page
// Try to parse frontmatter
if submatches := frontmatterRE.FindSubmatch(content); submatches != nil {
ini.Parse(bytes.NewReader(submatches[1]), func(section, key, value string) {
if section == "" {
switch key {
case "title":
page.Title = value
case "date":
date, err := time.Parse("2006-01-02", value)
if err != nil {
fmt.Println(err)
break
}
page.Date = date
}
}
// Preserve unrecognized keys
})
fmt.Println(string(submatches[1]))
content = content[len(submatches[0]):]
} else {
// Try to parse the date from the page filename // Try to parse the date from the page filename
var date time.Time
const layout = "2006-01-02" const layout = "2006-01-02"
base := filepath.Base(path) base := filepath.Base(path)
if len(base) >= len(layout) { if len(base) >= len(layout) {
dateStr := base[:len(layout)] dateStr := base[:len(layout)]
if time, err := time.Parse(layout, dateStr); err == nil { if time, err := time.Parse(layout, dateStr); err == nil {
date = time page.Date = time
} }
// Remove the date from the path // Remove the date from the path
base = base[len(layout):] base = base[len(layout):]
@ -278,20 +320,16 @@ func NewPage(path string, content []byte) *Page {
} }
// Try to parse the title from the contents // Try to parse the title from the contents
var title string
if submatches := titleRE.FindSubmatch(content); submatches != nil { if submatches := titleRE.FindSubmatch(content); submatches != nil {
title = string(submatches[1]) page.Title = string(submatches[1])
// Remove the title from the contents // Remove the title from the contents
content = content[len(submatches[0]):] content = content[len(submatches[0]):]
} }
permalink := strings.TrimSuffix(path, ".gmi")
return &Page{
Permalink: "/" + permalink + "/",
Title: title,
Date: date,
content: content,
} }
page.Permalink = "/" + strings.TrimSuffix(path, ".gmi") + "/"
page.content = content
return &page
} }
// Dir represents a directory. // Dir represents a directory.

View file

@ -1,5 +1,7 @@
package main package main
// TODO: Use go:embed
// Default atom feed template // Default atom feed template
const atom_xml = `<?xml version="1.0" encoding="utf-8"?> const atom_xml = `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">