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"
[permalinks]
"/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Permalink }}/"
"/" = "/{{ .Date.Format `2006/01/02` }}/{{ path.Base .Path }}/"
[[tasks]]
url = "gemini://example.com"
input = [".gmi"]
output = ".gmi"
template = ".gmi"

View file

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

View file

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

71
page.go
View file

@ -18,19 +18,20 @@ import (
// Page represents a page.
type Page struct {
Title string
Date time.Time
Weight int
Params map[string]interface{}
FilePath string `yaml:"-"`
Permalink string `yaml:"-"`
Content string `yaml:"-"`
Prev *Page `yaml:"-"`
Next *Page `yaml:"-"`
Pages []*Page `yaml:"-"`
Dirs []*Page `yaml:"-"`
feeds map[string][]byte
index bool
Title string
Date time.Time
Weight int
Params map[string]interface{}
Path string `yaml:"-"`
FilePath string `yaml:"-"`
URL string `yaml:"-"`
Content string `yaml:"-"`
Prev *Page `yaml:"-"`
Next *Page `yaml:"-"`
Pages []*Page `yaml:"-"`
Dirs []*Page `yaml:"-"`
feeds map[string][]byte
index bool
}
// 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
}
// 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 {
return err
}
@ -134,12 +140,13 @@ func (p *Page) _read(srcDir, path string, task *Task, cfg *Site) error {
path += "/"
}
}
page.Permalink = path
if permalink, ok := cfg.permalinks[p.Permalink]; ok {
page.Path = path
if permalink, ok := cfg.permalinks[p.Path]; ok {
var b strings.Builder
permalink.Execute(&b, page)
page.Permalink = b.String()
page.Path = b.String()
}
page.URL = task.URL + page.Path
p.Pages = append(p.Pages, page)
}
}
@ -161,7 +168,7 @@ func (p *Page) process(cfg *Site, task *Task) error {
if task.TemplateExt != "" {
// Create 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 {
var b strings.Builder
if err := tmpl.Execute(&b, p); err != nil {
@ -174,7 +181,7 @@ func (p *Page) process(cfg *Site, task *Task) error {
// Process pages
for i := range p.Pages {
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 err := tmpl.Execute(&b, p.Pages[i]); err != nil {
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) {
// Feed represents a feed.
type Feed struct {
Title string
Permalink string
Pages []*Page
Title string
Path string
URL string
Pages []*Page
}
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, feed.Template)
tmpl, ok := cfg.templates.FindTemplate(p.Path, feed.Template)
if !ok {
return nil, fmt.Errorf("failed to generate feed %q: missing feed template %q", feed.Title, feed.Template)
}
var b bytes.Buffer
data := Feed{
Title: feed.Title,
Permalink: p.Permalink,
Pages: p.Pages,
Title: feed.Title,
Path: p.Path,
URL: p.URL,
Pages: p.Pages,
}
if err := tmpl.Execute(&b, data); err != nil {
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.
func (p *Page) write(dstDir string, task *Task) error {
dirPath := pathpkg.Join(dstDir, p.Permalink)
dirPath := pathpkg.Join(dstDir, p.Path)
// Write pages
for _, page := range p.Pages {
dstPath := pathpkg.Join(dstDir, page.Permalink)
dstPath := pathpkg.Join(dstDir, page.Path)
if !task.UglyURLs {
dstPath = pathpkg.Join(dstPath, "index"+task.OutputExt)
}
@ -242,7 +251,7 @@ func (p *Page) write(dstDir string, task *Task) error {
}
// Write index page
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 {
return err
}
@ -337,7 +346,7 @@ func execute(command string, input io.Reader, output io.Writer) error {
func (p *Page) getPage(path string) *Page {
// XXX: This is inefficient
if p.Permalink == path {
if p.Path == path {
return p
}
for _, page := range p.Pages {
@ -346,7 +355,7 @@ func (p *Page) getPage(path string) *Page {
}
}
for _, dir := range p.Dirs {
if dir.Permalink == path {
if dir.Path == path {
return dir
}
}

17
site.go
View file

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

View file

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

View file

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