site: Implement support for task URLs

Resolves #23
This commit is contained in:
adnano 2021-10-02 19:20:47 -04:00
parent 762fe469c4
commit 7013fe9fb9
7 changed files with 117 additions and 90 deletions

View file

@ -1,9 +1,10 @@
title = "Example website" title = "Example website"
[permalinks] [permalinks]
"/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Permalink }}/" "/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Path }}/"
[[tasks]] [[tasks]]
url = "gemini://example.com"
input = [".gmi"] input = [".gmi"]
output = ".gmi" output = ".gmi"
template = ".gmi" template = ".gmi"

View file

@ -195,7 +195,7 @@ content/blog/2021-05-12-hello-world.gmi will have a path of
``` ```
[permalinks] [permalinks]
"/blog/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Permalink }}" "/blog/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Path }}"
``` ```
For more information on templates, see *TEMPLATES*. For more information on templates, see *TEMPLATES*.
@ -292,9 +292,13 @@ The following configuration options are supported per task:
output_dir = "public" output_dir = "public"
``` ```
*url*
The base URL to use for page URLs. The base URL should not have trailing
forward slashes.
*ugly_urls* *ugly_urls*
Specifies whether page permalinks will contain file extensions. By default, Specifies whether page paths will contain file extensions. By default,
clean URLs without any extension are used. clean paths without any extension are used.
Example: Example:
@ -624,14 +628,14 @@ All templates have the following functions available to them:
Site metadata contains the following data: Site metadata contains the following data:
[[ *Variable* *Title*
:[ *Description* The title of the site.
| Title
: The title of the site. *Params*
| Params Extra parameters specified in configuration.
: Extra parameters specified in configuration.
| Generated *Generated*
: Site generation time. Site generation time.
To configure these variables, see *CONFIGURATION*. To configure these variables, see *CONFIGURATION*.
@ -639,51 +643,63 @@ To configure these variables, see *CONFIGURATION*.
Page templates are provided with the following data: Page templates are provided with the following data:
[[ *Variable* *Title*
:[ *Description* The title of the page
| Title
: The title of the page *Date*
| Date The date of the page
: The date of the page
| Weight *Weight*
: The weight of the page The weight of the page
| Permalink
: The permanent link to this page *Path*
| FilePath The path to the page
: The path of the page file relative to the content directory
| Content *URL*
: The contents of the page The URL of the page. If no base URL is configured, it is equivalent to
| Params *Path*.
: Extra parameters specified in frontmatter
| Prev *FilePath*
: The previous page in this directory The path of the page file relative to the content directory
| Next
: The next page in this directory *Content*
The contents of the page
*Params*
Extra parameters specified in frontmatter
*Prev*
The previous page in this directory
*Next*
The next page in this directory
## INDEX TEMPLATES ## INDEX TEMPLATES
Index templates are provided with all the data that page templates are provided, Index templates are provided with all the data that page templates are provided,
plus the following data: plus the following data:
[[ *Variable* *Pages*
:[ *Description* List of pages in this directory
| Pages
: List of pages in this directory *Dirs*
| Dirs List of subdirectories
: List of subdirectories
## FEED TEMPLATES ## FEED TEMPLATES
Feed templates are provided with the following data: Feed templates are provided with the following data:
[[ *Variable* *Title*
:[ *Description* Title of the feed
| Title
: Title of the feed *Path*
| Permalink The path to the feed directory
: The permanent link to the feed directory
| Pages *URL*
: List of pages in this feed The URL of the feed directory
*Pages*
List of pages in this feed
## PARTIAL TEMPLATES ## PARTIAL TEMPLATES

View file

@ -71,7 +71,7 @@ func (site *Site) run() error {
func (s *Site) runTask(task *Task) error { func (s *Site) runTask(task *Task) error {
// Read content // Read content
s.root = &Page{Permalink: "/", FilePath: ""} s.root = &Page{Path: "/", FilePath: ""}
if err := s.root.read("content", task, s); err != nil { if err := s.root.read("content", task, s); err != nil {
return err return err
} }

71
page.go
View file

@ -18,19 +18,20 @@ import (
// Page represents a page. // Page represents a page.
type Page struct { type Page struct {
Title string Title string
Date time.Time Date time.Time
Weight int Weight int
Params map[string]interface{} Params map[string]interface{}
FilePath string `yaml:"-"` Path string `yaml:"-"`
Permalink string `yaml:"-"` FilePath string `yaml:"-"`
Content string `yaml:"-"` URL string `yaml:"-"`
Prev *Page `yaml:"-"` Content string `yaml:"-"`
Next *Page `yaml:"-"` Prev *Page `yaml:"-"`
Pages []*Page `yaml:"-"` Next *Page `yaml:"-"`
Dirs []*Page `yaml:"-"` Pages []*Page `yaml:"-"`
feeds map[string][]byte Dirs []*Page `yaml:"-"`
index bool feeds map[string][]byte
index bool
} }
// read reads from a directory and indexes the files and directories within it. // read reads from a directory and indexes the files and directories within it.
@ -52,7 +53,12 @@ func (p *Page) _read(srcDir, path string, task *Task, cfg *Site) error {
continue continue
} }
// Gather directory data // Gather directory data
dir := &Page{Permalink: "/" + path + "/", FilePath: path} dirPath := "/" + path + "/"
dir := &Page{
Path: dirPath,
FilePath: path,
URL: task.URL + dirPath,
}
if err := dir._read(srcDir, path, task, cfg); err != nil { if err := dir._read(srcDir, path, task, cfg); err != nil {
return err return err
} }
@ -134,12 +140,13 @@ func (p *Page) _read(srcDir, path string, task *Task, cfg *Site) error {
path += "/" path += "/"
} }
} }
page.Permalink = path page.Path = path
if permalink, ok := cfg.permalinks[p.Permalink]; ok { if permalink, ok := cfg.permalinks[p.Path]; ok {
var b strings.Builder var b strings.Builder
permalink.Execute(&b, page) permalink.Execute(&b, page)
page.Permalink = b.String() page.Path = b.String()
} }
page.URL = task.URL + page.Path
p.Pages = append(p.Pages, page) p.Pages = append(p.Pages, page)
} }
} }
@ -161,7 +168,7 @@ func (p *Page) process(cfg *Site, task *Task) error {
if task.TemplateExt != "" { if task.TemplateExt != "" {
// Create index // Create index
if p.index { if p.index {
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, "index"+task.TemplateExt) tmpl, ok := cfg.templates.FindTemplate(p.Path, "index"+task.TemplateExt)
if ok { if ok {
var b strings.Builder var b strings.Builder
if err := tmpl.Execute(&b, p); err != nil { if err := tmpl.Execute(&b, p); err != nil {
@ -174,7 +181,7 @@ func (p *Page) process(cfg *Site, task *Task) error {
// Process pages // Process pages
for i := range p.Pages { for i := range p.Pages {
var b strings.Builder var b strings.Builder
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, "page"+task.TemplateExt) tmpl, ok := cfg.templates.FindTemplate(p.Path, "page"+task.TemplateExt)
if ok { if ok {
if err := tmpl.Execute(&b, p.Pages[i]); err != nil { if err := tmpl.Execute(&b, p.Pages[i]); err != nil {
return err return err
@ -197,21 +204,23 @@ func (p *Page) process(cfg *Site, task *Task) error {
func (p *Page) buildFeed(cfg *Site, feed Feed) ([]byte, error) { func (p *Page) buildFeed(cfg *Site, feed Feed) ([]byte, error) {
// Feed represents a feed. // Feed represents a feed.
type Feed struct { type Feed struct {
Title string Title string
Permalink string Path string
Pages []*Page URL string
Pages []*Page
} }
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, feed.Template) tmpl, ok := cfg.templates.FindTemplate(p.Path, feed.Template)
if !ok { if !ok {
return nil, fmt.Errorf("failed to generate feed %q: missing feed template %q", feed.Title, feed.Template) return nil, fmt.Errorf("failed to generate feed %q: missing feed template %q", feed.Title, feed.Template)
} }
var b bytes.Buffer var b bytes.Buffer
data := Feed{ data := Feed{
Title: feed.Title, Title: feed.Title,
Permalink: p.Permalink, Path: p.Path,
Pages: p.Pages, URL: p.URL,
Pages: p.Pages,
} }
if err := tmpl.Execute(&b, data); err != nil { if err := tmpl.Execute(&b, data); err != nil {
return nil, err return nil, err
@ -228,11 +237,11 @@ func (p *Page) addFeed(name string, content []byte) {
// write writes the directory's contents to the provided destination path. // write writes the directory's contents to the provided destination path.
func (p *Page) write(dstDir string, task *Task) error { func (p *Page) write(dstDir string, task *Task) error {
dirPath := pathpkg.Join(dstDir, p.Permalink) dirPath := pathpkg.Join(dstDir, p.Path)
// Write pages // Write pages
for _, page := range p.Pages { for _, page := range p.Pages {
dstPath := pathpkg.Join(dstDir, page.Permalink) dstPath := pathpkg.Join(dstDir, page.Path)
if !task.UglyURLs { if !task.UglyURLs {
dstPath = pathpkg.Join(dstPath, "index"+task.OutputExt) dstPath = pathpkg.Join(dstPath, "index"+task.OutputExt)
} }
@ -242,7 +251,7 @@ func (p *Page) write(dstDir string, task *Task) error {
} }
// Write index page // Write index page
if p.index { if p.index {
dstPath := pathpkg.Join(dstDir, p.Permalink, "index"+task.OutputExt) dstPath := pathpkg.Join(dstDir, p.Path, "index"+task.OutputExt)
if err := p.writeTo(dstPath, task); err != nil { if err := p.writeTo(dstPath, task); err != nil {
return err return err
} }
@ -337,7 +346,7 @@ func execute(command string, input io.Reader, output io.Writer) error {
func (p *Page) getPage(path string) *Page { func (p *Page) getPage(path string) *Page {
// XXX: This is inefficient // XXX: This is inefficient
if p.Permalink == path { if p.Path == path {
return p return p
} }
for _, page := range p.Pages { for _, page := range p.Pages {
@ -346,7 +355,7 @@ func (p *Page) getPage(path string) *Page {
} }
} }
for _, dir := range p.Dirs { for _, dir := range p.Dirs {
if dir.Permalink == path { if dir.Path == path {
return dir return dir
} }
} }

17
site.go
View file

@ -23,14 +23,15 @@ type Site struct {
// Task represents a site build task. // Task represents a site build task.
type Task struct { type Task struct {
Input []string `toml:"input"` // input file suffixes Input []string `toml:"input"`
OutputExt string `toml:"output"` // output file suffix OutputExt string `toml:"output"`
TemplateExt string `toml:"template"` // template file suffix TemplateExt string `toml:"template"`
Preprocess map[string]string `toml:"preprocess"` // preprocess commands Preprocess map[string]string `toml:"preprocess"`
Postprocess string `toml:"postprocess"` // postprocess command Postprocess string `toml:"postprocess"`
StaticDir string `toml:"static_dir"` // static file directory StaticDir string `toml:"static_dir"`
OutputDir string `toml:"output_dir"` // output directory OutputDir string `toml:"output_dir"`
UglyURLs bool `toml:"ugly_urls"` // whether to use ugly URLs URL string `toml:"url"`
UglyURLs bool `toml:"ugly_urls"`
Feeds []Feed `toml:"feeds"` Feeds []Feed `toml:"feeds"`
feeds map[string][]Feed feeds map[string][]Feed
} }

View file

@ -1,11 +1,11 @@
{{ `<?xml version="1.0" encoding="utf-8"?>` | safeHTML }} {{ `<?xml version="1.0" encoding="utf-8"?>` | safeHTML }}
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">
<id>{{ .Permalink }}</id> <id>{{ .URL }}</id>
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
<updated>{{ site.Generated.Format "2006-01-02T15:04:05Z07:00" }}</updated> <updated>{{ site.Generated.Format "2006-01-02T15:04:05Z07:00" }}</updated>
<link href="{{ .Permalink }}" rel="alternate"/> <link href="{{ .URL }}" rel="alternate"/>
{{ range .Pages }}<entry> {{ range .Pages }}<entry>
<id>{{ .Permalink }}</id> <id>{{ .URL }}</id>
<title>{{ .Title }}</title> <title>{{ .Title }}</title>
<updated>{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}</updated> <updated>{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}</updated>
</entry> </entry>

View file

@ -1,6 +1,6 @@
# {{ .Title }} # {{ .Title }}
{{ if .Content }} {{ if .Content }}
{{ .Content }}{{ end }} {{ .Content }}{{ end }}
{{ range .Pages }}=> {{ .Permalink }} {{ if not .Date.IsZero -}} {{ range .Pages }}=> {{ .Path }} {{ if not .Date.IsZero -}}
{{.Date.Format "2006-01-02"}} {{end}}{{.Title}} {{.Date.Format "2006-01-02"}} {{end}}{{.Title}}
{{ end -}} {{ end -}}