mirror of
https://git.sr.ht/~adnano/kiln
synced 2024-10-30 09:23:09 +00:00
Merge Page and Dir structs
This commit is contained in:
parent
c0fcac882a
commit
45d2f0e4cb
1
funcs.go
1
funcs.go
|
@ -10,7 +10,6 @@ import (
|
||||||
// funcs returns functions for use in templates.
|
// funcs returns functions for use in templates.
|
||||||
func (s *Site) funcs() map[string]interface{} {
|
func (s *Site) funcs() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"dir": s.dir,
|
|
||||||
"exec": executeString,
|
"exec": executeString,
|
||||||
"page": s.page,
|
"page": s.page,
|
||||||
"path": func() _path { return _path{} },
|
"path": func() _path { return _path{} },
|
||||||
|
|
2
main.go
2
main.go
|
@ -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 = &Dir{Permalink: "/", path: ""}
|
s.root = &Page{Permalink: "/", 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
|
||||||
}
|
}
|
||||||
|
|
218
dir.go → page.go
218
dir.go → page.go
|
@ -16,35 +16,29 @@ import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dir represents a directory.
|
|
||||||
type Dir struct {
|
|
||||||
Permalink string
|
|
||||||
Pages []*Page
|
|
||||||
Dirs []*Dir
|
|
||||||
index *Page // The index page.
|
|
||||||
feeds map[string][]byte // Atom/RSS/Custom feeds.
|
|
||||||
path string // relative to the content dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
Permalink string `yaml:"-"`
|
|
||||||
FilePath string `yaml:"-"`
|
|
||||||
Content string `yaml:"-"`
|
|
||||||
Params map[string]interface{}
|
Params map[string]interface{}
|
||||||
|
FilePath string `yaml:"-"`
|
||||||
|
Permalink string `yaml:"-"`
|
||||||
|
Content string `yaml:"-"`
|
||||||
Prev *Page `yaml:"-"`
|
Prev *Page `yaml:"-"`
|
||||||
Next *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.
|
// read reads from a directory and indexes the files and directories within it.
|
||||||
func (d *Dir) read(srcDir string, task *Task, cfg *Site) error {
|
func (p *Page) read(srcDir string, task *Task, cfg *Site) error {
|
||||||
return d._read(srcDir, "", task, cfg)
|
return p._read(srcDir, "", task, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dir) _read(srcDir, path string, task *Task, cfg *Site) error {
|
func (p *Page) _read(srcDir, path string, task *Task, cfg *Site) error {
|
||||||
entries, err := ioutil.ReadDir(pathpkg.Join(srcDir, path))
|
entries, err := ioutil.ReadDir(pathpkg.Join(srcDir, path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -58,11 +52,11 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Site) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Gather directory data
|
// Gather directory data
|
||||||
dir := &Dir{Permalink: "/" + path + "/", path: path}
|
dir := &Page{Permalink: "/" + path + "/", FilePath: path}
|
||||||
if err := dir._read(srcDir, path, task, cfg); err != nil {
|
if err := dir._read(srcDir, path, task, cfg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.Dirs = append(d.Dirs, dir)
|
p.Dirs = append(p.Dirs, dir)
|
||||||
} else if ext := pathpkg.Ext(name); task.Match(ext) {
|
} else if ext := pathpkg.Ext(name); task.Match(ext) {
|
||||||
// Ignore pages beginning with "_" with the exception of _index pages
|
// Ignore pages beginning with "_" with the exception of _index pages
|
||||||
namePrefix := strings.TrimSuffix(name, ext)
|
namePrefix := strings.TrimSuffix(name, ext)
|
||||||
|
@ -76,7 +70,13 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Site) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
page := &Page{}
|
page := &Page{
|
||||||
|
FilePath: path,
|
||||||
|
}
|
||||||
|
if namePrefix == "_index" {
|
||||||
|
p.index = true
|
||||||
|
page = p
|
||||||
|
}
|
||||||
|
|
||||||
// Try to parse the date from the page filename
|
// Try to parse the date from the page filename
|
||||||
const layout = "2006-01-02"
|
const layout = "2006-01-02"
|
||||||
|
@ -123,12 +123,7 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Site) error {
|
||||||
}
|
}
|
||||||
page.Content = string(content)
|
page.Content = string(content)
|
||||||
|
|
||||||
page.FilePath = path
|
if !page.index {
|
||||||
|
|
||||||
if namePrefix == "_index" {
|
|
||||||
page.Permalink = d.Permalink
|
|
||||||
d.index = page
|
|
||||||
} else {
|
|
||||||
if namePrefix == "index" {
|
if namePrefix == "index" {
|
||||||
path = "/" + strings.TrimSuffix(path, name)
|
path = "/" + strings.TrimSuffix(path, name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,12 +135,12 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Site) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
page.Permalink = path
|
page.Permalink = path
|
||||||
if permalink, ok := cfg.permalinks[d.Permalink]; ok {
|
if permalink, ok := cfg.permalinks[p.Permalink]; ok {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
permalink.Execute(&b, page)
|
permalink.Execute(&b, page)
|
||||||
page.Permalink = b.String()
|
page.Permalink = b.String()
|
||||||
}
|
}
|
||||||
d.Pages = append(d.Pages, page)
|
p.Pages = append(p.Pages, page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,44 +148,44 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Site) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// process processes the directory's contents.
|
// process processes the directory's contents.
|
||||||
func (d *Dir) process(cfg *Site, task *Task) error {
|
func (p *Page) process(cfg *Site, task *Task) error {
|
||||||
// Build feeds before templates are applied to the page contents
|
// Build feeds before templates are applied to the page contents
|
||||||
for _, feed := range task.feeds[d.path] {
|
for _, feed := range task.feeds[p.FilePath] {
|
||||||
b, err := d.buildFeed(cfg, feed)
|
b, err := p.buildFeed(cfg, feed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.addFeed(feed.Output, b)
|
p.addFeed(feed.Output, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.TemplateExt != "" {
|
if task.TemplateExt != "" {
|
||||||
// Create index
|
// Create index
|
||||||
if d.index != nil {
|
if p.index {
|
||||||
tmpl, ok := cfg.templates.FindTemplate(d.Permalink, "index"+task.TemplateExt)
|
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, "index"+task.TemplateExt)
|
||||||
if ok {
|
if ok {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
if err := tmpl.Execute(&b, d); err != nil {
|
if err := tmpl.Execute(&b, p); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.index.Content = b.String()
|
p.Content = b.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process pages
|
// Process pages
|
||||||
for i := range d.Pages {
|
for i := range p.Pages {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
tmpl, ok := cfg.templates.FindTemplate(d.Permalink, "page"+task.TemplateExt)
|
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, "page"+task.TemplateExt)
|
||||||
if ok {
|
if ok {
|
||||||
if err := tmpl.Execute(&b, d.Pages[i]); err != nil {
|
if err := tmpl.Execute(&b, p.Pages[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.Pages[i].Content = b.String()
|
p.Pages[i].Content = b.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process subdirectories
|
// Process subdirectories
|
||||||
for _, d := range d.Dirs {
|
for _, d := range p.Dirs {
|
||||||
if err := d.process(cfg, task); err != nil {
|
if err := d.process(cfg, task); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -199,7 +194,7 @@ func (d *Dir) process(cfg *Site, task *Task) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildFeed build the feed of the directory
|
// buildFeed build the feed of the directory
|
||||||
func (d Dir) 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
|
||||||
|
@ -207,7 +202,7 @@ func (d Dir) buildFeed(cfg *Site, feed Feed) ([]byte, error) {
|
||||||
Pages []*Page
|
Pages []*Page
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, ok := cfg.templates.FindTemplate(d.Permalink, feed.Template)
|
tmpl, ok := cfg.templates.FindTemplate(p.Permalink, 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)
|
||||||
}
|
}
|
||||||
|
@ -215,8 +210,8 @@ func (d Dir) buildFeed(cfg *Site, feed Feed) ([]byte, error) {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
data := Feed{
|
data := Feed{
|
||||||
Title: feed.Title,
|
Title: feed.Title,
|
||||||
Permalink: d.Permalink,
|
Permalink: p.Permalink,
|
||||||
Pages: d.Pages,
|
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
|
||||||
|
@ -224,48 +219,37 @@ func (d Dir) buildFeed(cfg *Site, feed Feed) ([]byte, error) {
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dir) addFeed(name string, content []byte) {
|
func (p *Page) addFeed(name string, content []byte) {
|
||||||
if d.feeds == nil {
|
if p.feeds == nil {
|
||||||
d.feeds = map[string][]byte{}
|
p.feeds = map[string][]byte{}
|
||||||
}
|
}
|
||||||
d.feeds[name] = content
|
p.feeds[name] = content
|
||||||
}
|
}
|
||||||
|
|
||||||
// write writes the directory's contents to the provided destination path.
|
// write writes the directory's contents to the provided destination path.
|
||||||
func (d *Dir) write(dstDir string, task *Task) error {
|
func (p *Page) write(dstDir string, task *Task) error {
|
||||||
dirPath := pathpkg.Join(dstDir, d.Permalink)
|
dirPath := pathpkg.Join(dstDir, p.Permalink)
|
||||||
|
|
||||||
// Write pages
|
// Write pages
|
||||||
pages := d.Pages
|
for _, page := range p.Pages {
|
||||||
if d.index != nil {
|
dstPath := pathpkg.Join(dstDir, page.Permalink)
|
||||||
pages = append(pages, d.index)
|
if !task.UglyURLs {
|
||||||
|
dstPath = pathpkg.Join(dstPath, "index"+task.OutputExt)
|
||||||
}
|
}
|
||||||
for _, page := range pages {
|
if err := page.writeTo(dstPath, task); err != nil {
|
||||||
path := page.Permalink
|
|
||||||
if !task.UglyURLs || page == d.index {
|
|
||||||
path = pathpkg.Join(path, "index"+task.OutputExt)
|
|
||||||
}
|
|
||||||
var content []byte
|
|
||||||
if cmd := task.Postprocess; cmd != "" {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := execute(cmd, strings.NewReader(page.Content), &buf); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content = buf.Bytes()
|
|
||||||
} else {
|
|
||||||
content = []byte(page.Content)
|
|
||||||
}
|
}
|
||||||
|
// Write index page
|
||||||
dstPath := pathpkg.Join(dstDir, path)
|
if p.index {
|
||||||
dir := pathpkg.Dir(dstPath)
|
dstPath := pathpkg.Join(dirPath, p.Permalink, "index"+task.OutputExt)
|
||||||
os.MkdirAll(dir, 0755)
|
if err := p.writeTo(dstPath, task); err != nil {
|
||||||
if err := os.WriteFile(dstPath, content, 0644); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write feeds
|
// Write feeds
|
||||||
for name, content := range d.feeds {
|
for name, content := range p.feeds {
|
||||||
dstPath := pathpkg.Join(dstDir, name)
|
dstPath := pathpkg.Join(dstDir, name)
|
||||||
os.MkdirAll(dirPath, 0755)
|
os.MkdirAll(dirPath, 0755)
|
||||||
if err := os.WriteFile(dstPath, content, 0644); err != nil {
|
if err := os.WriteFile(dstPath, content, 0644); err != nil {
|
||||||
|
@ -274,40 +258,60 @@ func (d *Dir) write(dstDir string, task *Task) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write subdirectories
|
// Write subdirectories
|
||||||
for _, dir := range d.Dirs {
|
for _, dir := range p.Dirs {
|
||||||
dir.write(dstDir, task)
|
dir.write(dstDir, task)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Page) writeTo(dstPath string, task *Task) error {
|
||||||
|
var content []byte
|
||||||
|
if cmd := task.Postprocess; cmd != "" {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := execute(cmd, strings.NewReader(p.Content), &buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content = buf.Bytes()
|
||||||
|
} else {
|
||||||
|
content = []byte(p.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
dir := pathpkg.Dir(dstPath)
|
||||||
|
os.MkdirAll(dir, 0755)
|
||||||
|
if err := os.WriteFile(dstPath, content, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// sort sorts the directory's pages by weight, then date, then filepath.
|
// sort sorts the directory's pages by weight, then date, then filepath.
|
||||||
func (d *Dir) sort() {
|
func (p *Page) sort() {
|
||||||
sort.Slice(d.Pages, func(i, j int) bool {
|
sort.Slice(p.Pages, func(i, j int) bool {
|
||||||
pi, pj := d.Pages[i], d.Pages[j]
|
pi, pj := p.Pages[i], p.Pages[j]
|
||||||
return pi.FilePath < pj.FilePath
|
return pi.FilePath < pj.FilePath
|
||||||
})
|
})
|
||||||
|
|
||||||
sort.SliceStable(d.Pages, func(i, j int) bool {
|
sort.SliceStable(p.Pages, func(i, j int) bool {
|
||||||
pi, pj := d.Pages[i], d.Pages[j]
|
pi, pj := p.Pages[i], p.Pages[j]
|
||||||
return pi.Date.After(pj.Date)
|
return pi.Date.After(pj.Date)
|
||||||
})
|
})
|
||||||
|
|
||||||
sort.SliceStable(d.Pages, func(i, j int) bool {
|
sort.SliceStable(p.Pages, func(i, j int) bool {
|
||||||
pi, pj := d.Pages[i], d.Pages[j]
|
pi, pj := p.Pages[i], p.Pages[j]
|
||||||
return pi.Weight < pj.Weight
|
return pi.Weight < pj.Weight
|
||||||
})
|
})
|
||||||
|
|
||||||
for i := range d.Pages {
|
for i := range p.Pages {
|
||||||
if i-1 >= 0 {
|
if i-1 >= 0 {
|
||||||
d.Pages[i].Prev = d.Pages[i-1]
|
p.Pages[i].Prev = p.Pages[i-1]
|
||||||
}
|
}
|
||||||
if i+1 < len(d.Pages) {
|
if i+1 < len(p.Pages) {
|
||||||
d.Pages[i].Next = d.Pages[i+1]
|
p.Pages[i].Next = p.Pages[i+1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort subdirectories
|
// Sort subdirectories
|
||||||
for _, d := range d.Dirs {
|
for _, d := range p.Dirs {
|
||||||
d.sort()
|
d.sort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,48 +330,22 @@ func execute(command string, input io.Reader, output io.Writer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dir) Title() string {
|
func (p *Page) getPage(path string) *Page {
|
||||||
return d.index.Title
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dir) Date() time.Time {
|
|
||||||
return d.index.Date
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dir) Content() string {
|
|
||||||
return d.index.Content
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dir) Params() map[string]interface{} {
|
|
||||||
return d.index.Params
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dir) getDir(path string) *Dir {
|
|
||||||
// XXX: This is inefficient
|
// XXX: This is inefficient
|
||||||
if d.Permalink == path {
|
if p.Permalink == path {
|
||||||
return d
|
return p
|
||||||
}
|
}
|
||||||
for _, dir := range d.Dirs {
|
for _, page := range p.Pages {
|
||||||
if dir.Permalink == path {
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := range d.Dirs {
|
|
||||||
if dir := d.Dirs[i].getDir(path); dir != nil {
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dir) getPage(path string) *Page {
|
|
||||||
// XXX: This is inefficient
|
|
||||||
for _, page := range d.Pages {
|
|
||||||
if page.FilePath == path {
|
if page.FilePath == path {
|
||||||
return page
|
return page
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, dir := range d.Dirs {
|
for _, dir := range p.Dirs {
|
||||||
|
if dir.Permalink == path {
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, dir := range p.Dirs {
|
||||||
if page := dir.getPage(path); page != nil {
|
if page := dir.getPage(path); page != nil {
|
||||||
return page
|
return page
|
||||||
}
|
}
|
6
site.go
6
site.go
|
@ -18,7 +18,7 @@ type Site struct {
|
||||||
Generated time.Time `toml:"-"`
|
Generated time.Time `toml:"-"`
|
||||||
permalinks map[string]*template.Template
|
permalinks map[string]*template.Template
|
||||||
templates Templates
|
templates Templates
|
||||||
root *Dir
|
root *Page
|
||||||
}
|
}
|
||||||
|
|
||||||
// Task represents a site build task.
|
// Task represents a site build task.
|
||||||
|
@ -103,10 +103,6 @@ func LoadSite(config string) (*Site, error) {
|
||||||
return site, nil
|
return site, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Site) dir(path string) *Dir {
|
|
||||||
return s.root.getDir(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Site) page(path string) *Page {
|
func (s *Site) page(path string) *Page {
|
||||||
return s.root.getPage(path)
|
return s.root.getPage(path)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue