diff --git a/go.mod b/go.mod index c3938a7..09e0b96 100644 --- a/go.mod +++ b/go.mod @@ -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 +) diff --git a/go.sum b/go.sum index c60218b..6b53722 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/main.go b/main.go index 9fadd26..ac82c29 100644 --- a/main.go +++ b/main.go @@ -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. diff --git a/templates.go b/templates.go index ccb3687..9f5e317 100644 --- a/templates.go +++ b/templates.go @@ -1,5 +1,7 @@ package main +// TODO: Use go:embed + // Default atom feed template const atom_xml = `