mirror of
https://git.sr.ht/~adnano/kiln
synced 2024-10-30 01:13:08 +00:00
Add dir and page functions and fix partial function
This commit is contained in:
parent
70cc182bf1
commit
0e54f9eec5
53
dir.go
53
dir.go
|
@ -38,24 +38,12 @@ type Page struct {
|
||||||
Next *Page `yaml:"-"`
|
Next *Page `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDir returns a new Dir with the given path.
|
|
||||||
func NewDir(path string) *Dir {
|
|
||||||
if path == "" {
|
|
||||||
path = "/"
|
|
||||||
} else {
|
|
||||||
path = "/" + path + "/"
|
|
||||||
}
|
|
||||||
return &Dir{
|
|
||||||
Path: path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 *Config) error {
|
func (d *Dir) read(srcDir string, task *Task, cfg *Site) error {
|
||||||
return d._read(srcDir, "", task, cfg)
|
return d._read(srcDir, "", task, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dir) _read(srcDir, path string, task *Task, cfg *Config) error {
|
func (d *Dir) _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
|
||||||
|
@ -69,7 +57,7 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Config) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Gather directory data
|
// Gather directory data
|
||||||
dir := NewDir(path)
|
dir := &Dir{Path: "/" + 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
|
||||||
}
|
}
|
||||||
|
@ -160,7 +148,7 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// process processes the directory's contents.
|
// process processes the directory's contents.
|
||||||
func (d *Dir) process(cfg *Config, task *Task) error {
|
func (d *Dir) process(cfg *Site, task *Task) error {
|
||||||
if task.TemplateExt != "" {
|
if task.TemplateExt != "" {
|
||||||
// Create index
|
// Create index
|
||||||
if d.index != nil {
|
if d.index != nil {
|
||||||
|
@ -321,3 +309,36 @@ func (d *Dir) Date() time.Time {
|
||||||
func (d *Dir) Content() string {
|
func (d *Dir) Content() string {
|
||||||
return d.index.Content
|
return d.index.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Dir) getDir(path string) *Dir {
|
||||||
|
// XXX: This is inefficient
|
||||||
|
if d.Path == path {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
for _, dir := range d.Dirs {
|
||||||
|
if dir.Path == 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 {
|
||||||
|
return page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, dir := range d.Dirs {
|
||||||
|
if page := dir.getPage(path); page != nil {
|
||||||
|
return page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
25
funcs.go
25
funcs.go
|
@ -7,15 +7,22 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var funcs = map[string]interface{}{
|
// funcs returns functions for use in templates.
|
||||||
"path": func() _path { return _path{} },
|
func (s *Site) funcs() map[string]interface{} {
|
||||||
"reverse": reverse,
|
return map[string]interface{}{
|
||||||
"strings": func() _strings { return _strings{} },
|
"dir": s.dir,
|
||||||
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
|
"page": s.page,
|
||||||
"safeHTMLAttr": func(s string) template.HTMLAttr { return template.HTMLAttr(s) },
|
"path": func() _path { return _path{} },
|
||||||
"safeCSS": func(s string) template.CSS { return template.CSS(s) },
|
"partial": s.templates.ExecutePartial,
|
||||||
"safeJS": func(s string) template.JS { return template.JS(s) },
|
"reverse": reverse,
|
||||||
"safeURL": func(s string) template.URL { return template.URL(s) },
|
"safeCSS": func(s string) template.CSS { return template.CSS(s) },
|
||||||
|
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
|
||||||
|
"safeHTMLAttr": func(s string) template.HTMLAttr { return template.HTMLAttr(s) },
|
||||||
|
"safeJS": func(s string) template.JS { return template.JS(s) },
|
||||||
|
"safeURL": func(s string) template.URL { return template.URL(s) },
|
||||||
|
"site": func() *Site { return s },
|
||||||
|
"strings": func() _strings { return _strings{} },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type _path struct{}
|
type _path struct{}
|
||||||
|
|
33
main.go
33
main.go
|
@ -49,30 +49,19 @@ func build() {
|
||||||
flags.StringVar(&config, "c", "config.toml", "the configuration file to use")
|
flags.StringVar(&config, "c", "config.toml", "the configuration file to use")
|
||||||
flags.Parse(os.Args[2:])
|
flags.Parse(os.Args[2:])
|
||||||
|
|
||||||
// Load config
|
site, err := LoadSite(config)
|
||||||
cfg, err := LoadConfig(config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
templateExts := []string{}
|
if err := site.run(); err != nil {
|
||||||
for _, task := range cfg.Tasks {
|
|
||||||
if task.TemplateExt != "" {
|
|
||||||
templateExts = append(templateExts, task.TemplateExt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := cfg.templates.Load("templates", templateExts); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := run(cfg); err != nil {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(cfg *Config) error {
|
func (site *Site) run() error {
|
||||||
for _, task := range cfg.Tasks {
|
for _, task := range site.Tasks {
|
||||||
err := runTask(cfg, task)
|
err := site.runTask(task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -80,19 +69,19 @@ func run(cfg *Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTask(cfg *Config, task *Task) error {
|
func (s *Site) runTask(task *Task) error {
|
||||||
// Read content
|
// Read content
|
||||||
dir := NewDir("")
|
s.root = &Dir{Path: "/"}
|
||||||
if err := dir.read("content", task, cfg); err != nil {
|
if err := s.root.read("content", task, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dir.sort()
|
s.root.sort()
|
||||||
// Process content
|
// Process content
|
||||||
if err := dir.process(cfg, task); err != nil {
|
if err := s.root.process(s, task); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Write content
|
// Write content
|
||||||
if err := dir.write(task.OutputDir, task); err != nil {
|
if err := s.root.write(task.OutputDir, task); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Copy static files
|
// Copy static files
|
||||||
|
|
|
@ -3,21 +3,21 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/pelletier/go-toml"
|
"github.com/pelletier/go-toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains site configuration.
|
// Site represents a site.
|
||||||
type Config struct {
|
type Site struct {
|
||||||
Title string `toml:"title"`
|
Title string `toml:"title"`
|
||||||
URLs []string `toml:"urls"`
|
URLs []string `toml:"urls"`
|
||||||
Tasks []*Task `toml:"tasks"`
|
Tasks []*Task `toml:"tasks"`
|
||||||
Feeds map[string]string `toml:"feeds"`
|
Feeds map[string]string `toml:"feeds"`
|
||||||
Permalinks map[string]string `toml:"permalinks"`
|
Permalinks map[string]string `toml:"permalinks"`
|
||||||
permalinks map[string]*template.Template
|
permalinks map[string]*template.Template
|
||||||
templates *Templates
|
templates Templates
|
||||||
|
root *Dir
|
||||||
}
|
}
|
||||||
|
|
||||||
// Task represents a site build task.
|
// Task represents a site build task.
|
||||||
|
@ -41,57 +41,51 @@ func (t *Task) Match(ext string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads the configuration from the provided path.
|
// LoadSite loads the site with the given configuration file.
|
||||||
func LoadConfig(path string) (*Config, error) {
|
func LoadSite(config string) (*Site, error) {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
c := &Config{}
|
site := &Site{}
|
||||||
if err := toml.NewDecoder(f).Decode(c); err != nil {
|
if err := toml.NewDecoder(f).Decode(site); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcs := site.funcs()
|
||||||
|
|
||||||
// Parse permalinks
|
// Parse permalinks
|
||||||
c.permalinks = map[string]*template.Template{}
|
site.permalinks = map[string]*template.Template{}
|
||||||
for s := range c.Permalinks {
|
for path := range site.Permalinks {
|
||||||
t := template.New(fmt.Sprintf("permalink %q", s)).Funcs(funcs)
|
t := template.New(fmt.Sprintf("permalink %q", path)).Funcs(funcs)
|
||||||
_, err := t.Parse(c.Permalinks[s])
|
_, err := t.Parse(site.Permalinks[path])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.permalinks[s] = t
|
site.permalinks[path] = t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Site contains site metadata passed to templates
|
// Load templates
|
||||||
type Site struct {
|
templateExts := []string{}
|
||||||
Title string
|
for _, task := range site.Tasks {
|
||||||
URLs []string
|
if task.TemplateExt != "" {
|
||||||
}
|
templateExts = append(templateExts, task.TemplateExt)
|
||||||
|
|
||||||
funcs["site"] = func() Site {
|
|
||||||
return Site{
|
|
||||||
Title: c.Title,
|
|
||||||
URLs: c.URLs,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
funcs["partial"] = func(name string, data interface{}) (interface{}, error) {
|
site.templates.Funcs(funcs)
|
||||||
t, ok := c.templates.FindPartial(name)
|
if err := site.templates.Load("templates", templateExts); err != nil {
|
||||||
if !ok {
|
return nil, err
|
||||||
return "", fmt.Errorf("Error: partial %q not found", name)
|
|
||||||
}
|
|
||||||
var b strings.Builder
|
|
||||||
if err := t.Execute(&b, data); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return b.String(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize templates
|
return site, nil
|
||||||
c.templates = NewTemplates()
|
}
|
||||||
c.templates.Funcs(funcs)
|
|
||||||
|
func (s *Site) dir(path string) *Dir {
|
||||||
return c, nil
|
return s.root.getDir(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Site) page(path string) *Page {
|
||||||
|
return s.root.getPage(path)
|
||||||
}
|
}
|
25
templates.go
25
templates.go
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
htemplate "html/template"
|
htemplate "html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
@ -60,14 +61,6 @@ type Templates struct {
|
||||||
funcs map[string]interface{}
|
funcs map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTemplates returns a new Templates with the default templates.
|
|
||||||
func NewTemplates() *Templates {
|
|
||||||
t := &Templates{
|
|
||||||
tmpls: map[string]Template{},
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Funcs sets the functions available to newly created templates.
|
// Funcs sets the functions available to newly created templates.
|
||||||
func (t *Templates) Funcs(funcs map[string]interface{}) {
|
func (t *Templates) Funcs(funcs map[string]interface{}) {
|
||||||
t.funcs = funcs
|
t.funcs = funcs
|
||||||
|
@ -75,6 +68,9 @@ func (t *Templates) Funcs(funcs map[string]interface{}) {
|
||||||
|
|
||||||
// LoadTemplate loads a template from the provided filenames.
|
// LoadTemplate loads a template from the provided filenames.
|
||||||
func (t *Templates) LoadTemplate(name string, filenames ...string) error {
|
func (t *Templates) LoadTemplate(name string, filenames ...string) error {
|
||||||
|
if t.tmpls == nil {
|
||||||
|
t.tmpls = map[string]Template{}
|
||||||
|
}
|
||||||
if ext := pathpkg.Ext(name); ext == ".html" || ext == ".xml" {
|
if ext := pathpkg.Ext(name); ext == ".html" || ext == ".xml" {
|
||||||
return t.loadHTMLTemplate(name, filenames...)
|
return t.loadHTMLTemplate(name, filenames...)
|
||||||
}
|
}
|
||||||
|
@ -170,3 +166,16 @@ func (t *Templates) FindPartial(name string) (Template, bool) {
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutePartial executes the partial with the given name.
|
||||||
|
func (t *Templates) ExecutePartial(name string, data interface{}) (string, error) {
|
||||||
|
tmpl, ok := t.FindPartial(name)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("Error: partial %q not found", name)
|
||||||
|
}
|
||||||
|
var b strings.Builder
|
||||||
|
if err := tmpl.Execute(&b, data); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return b.String(), nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue