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
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.4/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3VJ5rnZWKq0=
git.sr.ht/~adnano/go-gemini v0.1.8 h1:93DxDNXB0bjnfDhZewf+QsEopfuOMh/I4v7ujoJ6WIs=
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=

158
main.go
View file

@ -3,17 +3,20 @@ package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"text/template"
"time"
"git.sr.ht/~adnano/go-gemini"
"git.sr.ht/~adnano/go-ini"
)
const (
@ -31,29 +34,50 @@ const (
// site config
var cfg struct {
title string // site title
url string // site URL
toAtom bool // output Atom
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")
title string // site title
url string // site URL
toAtom bool // output Atom
toHTML bool // output HTML
}
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()
if err := run(); err != nil {
log.Fatal(err)
}
if cfg.serveSite {
serve()
}
}
// site metadata passed to templates
@ -150,14 +174,6 @@ func run() error {
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.
func write(dir *Dir, dstDir string, format outputFormat) error {
// Empty the destination directory
@ -249,49 +265,71 @@ func (p *Page) Content() string {
// Regexp to parse title from Gemini files
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.
func NewPage(path string, content []byte) *Page {
// Try to parse the date from the page filename
var date time.Time
const layout = "2006-01-02"
base := filepath.Base(path)
if len(base) >= len(layout) {
dateStr := base[:len(layout)]
if time, err := time.Parse(layout, dateStr); err == nil {
date = time
}
// Remove the date from the path
base = base[len(layout):]
if len(base) > 0 {
// Remove a leading dash
if base[0] == '-' {
base = base[1:]
}
if len(base) > 0 {
dir := filepath.Dir(path)
if dir == "." {
dir = ""
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
}
path = filepath.Join(dir, base)
}
// Preserve unrecognized keys
})
fmt.Println(string(submatches[1]))
content = content[len(submatches[0]):]
} else {
// Try to parse the date from the page filename
const layout = "2006-01-02"
base := filepath.Base(path)
if len(base) >= len(layout) {
dateStr := base[:len(layout)]
if time, err := time.Parse(layout, dateStr); err == nil {
page.Date = time
}
// Remove the date from the path
base = base[len(layout):]
if len(base) > 0 {
// Remove a leading dash
if base[0] == '-' {
base = base[1:]
}
if len(base) > 0 {
dir := filepath.Dir(path)
if dir == "." {
dir = ""
}
path = filepath.Join(dir, base)
}
}
}
// Try to parse the title from the contents
if submatches := titleRE.FindSubmatch(content); submatches != nil {
page.Title = string(submatches[1])
// Remove the title from the contents
content = content[len(submatches[0]):]
}
}
// Try to parse the title from the contents
var title string
if submatches := titleRE.FindSubmatch(content); submatches != nil {
title = string(submatches[1])
// Remove the title from the contents
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.

View file

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