mirror of
https://git.sr.ht/~adnano/kiln
synced 2024-11-23 18:51:10 +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:"-"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -69,7 +57,7 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Config) error {
|
|||
continue
|
||||
}
|
||||
// Gather directory data
|
||||
dir := NewDir(path)
|
||||
dir := &Dir{Path: "/" + path + "/"}
|
||||
if err := dir._read(srcDir, path, task, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -160,7 +148,7 @@ func (d *Dir) _read(srcDir, path string, task *Task, cfg *Config) error {
|
|||
}
|
||||
|
||||
// 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 != "" {
|
||||
// Create index
|
||||
if d.index != nil {
|
||||
|
@ -321,3 +309,36 @@ func (d *Dir) Date() time.Time {
|
|||
func (d *Dir) Content() string {
|
||||
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"
|
||||
)
|
||||
|
||||
var funcs = map[string]interface{}{
|
||||
"path": func() _path { return _path{} },
|
||||
"reverse": reverse,
|
||||
"strings": func() _strings { return _strings{} },
|
||||
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
|
||||
"safeHTMLAttr": func(s string) template.HTMLAttr { return template.HTMLAttr(s) },
|
||||
"safeCSS": func(s string) template.CSS { return template.CSS(s) },
|
||||
"safeJS": func(s string) template.JS { return template.JS(s) },
|
||||
"safeURL": func(s string) template.URL { return template.URL(s) },
|
||||
// funcs returns functions for use in templates.
|
||||
func (s *Site) funcs() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"dir": s.dir,
|
||||
"page": s.page,
|
||||
"path": func() _path { return _path{} },
|
||||
"partial": s.templates.ExecutePartial,
|
||||
"reverse": reverse,
|
||||
"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{}
|
||||
|
|
33
main.go
33
main.go
|
@ -49,30 +49,19 @@ func build() {
|
|||
flags.StringVar(&config, "c", "config.toml", "the configuration file to use")
|
||||
flags.Parse(os.Args[2:])
|
||||
|
||||
// Load config
|
||||
cfg, err := LoadConfig(config)
|
||||
site, err := LoadSite(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
templateExts := []string{}
|
||||
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 {
|
||||
if err := site.run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(cfg *Config) error {
|
||||
for _, task := range cfg.Tasks {
|
||||
err := runTask(cfg, task)
|
||||
func (site *Site) run() error {
|
||||
for _, task := range site.Tasks {
|
||||
err := site.runTask(task)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -80,19 +69,19 @@ func run(cfg *Config) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runTask(cfg *Config, task *Task) error {
|
||||
func (s *Site) runTask(task *Task) error {
|
||||
// Read content
|
||||
dir := NewDir("")
|
||||
if err := dir.read("content", task, cfg); err != nil {
|
||||
s.root = &Dir{Path: "/"}
|
||||
if err := s.root.read("content", task, s); err != nil {
|
||||
return err
|
||||
}
|
||||
dir.sort()
|
||||
s.root.sort()
|
||||
// Process content
|
||||
if err := dir.process(cfg, task); err != nil {
|
||||
if err := s.root.process(s, task); err != nil {
|
||||
return err
|
||||
}
|
||||
// Write content
|
||||
if err := dir.write(task.OutputDir, task); err != nil {
|
||||
if err := s.root.write(task.OutputDir, task); err != nil {
|
||||
return err
|
||||
}
|
||||
// Copy static files
|
||||
|
|
|
@ -3,21 +3,21 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
// Config contains site configuration.
|
||||
type Config struct {
|
||||
// Site represents a site.
|
||||
type Site struct {
|
||||
Title string `toml:"title"`
|
||||
URLs []string `toml:"urls"`
|
||||
Tasks []*Task `toml:"tasks"`
|
||||
Feeds map[string]string `toml:"feeds"`
|
||||
Permalinks map[string]string `toml:"permalinks"`
|
||||
permalinks map[string]*template.Template
|
||||
templates *Templates
|
||||
templates Templates
|
||||
root *Dir
|
||||
}
|
||||
|
||||
// Task represents a site build task.
|
||||
|
@ -41,57 +41,51 @@ func (t *Task) Match(ext string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// LoadConfig loads the configuration from the provided path.
|
||||
func LoadConfig(path string) (*Config, error) {
|
||||
f, err := os.Open(path)
|
||||
// LoadSite loads the site with the given configuration file.
|
||||
func LoadSite(config string) (*Site, error) {
|
||||
f, err := os.Open(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
c := &Config{}
|
||||
if err := toml.NewDecoder(f).Decode(c); err != nil {
|
||||
site := &Site{}
|
||||
if err := toml.NewDecoder(f).Decode(site); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
funcs := site.funcs()
|
||||
|
||||
// Parse permalinks
|
||||
c.permalinks = map[string]*template.Template{}
|
||||
for s := range c.Permalinks {
|
||||
t := template.New(fmt.Sprintf("permalink %q", s)).Funcs(funcs)
|
||||
_, err := t.Parse(c.Permalinks[s])
|
||||
site.permalinks = map[string]*template.Template{}
|
||||
for path := range site.Permalinks {
|
||||
t := template.New(fmt.Sprintf("permalink %q", path)).Funcs(funcs)
|
||||
_, err := t.Parse(site.Permalinks[path])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.permalinks[s] = t
|
||||
site.permalinks[path] = t
|
||||
}
|
||||
|
||||
// Site contains site metadata passed to templates
|
||||
type Site struct {
|
||||
Title string
|
||||
URLs []string
|
||||
}
|
||||
|
||||
funcs["site"] = func() Site {
|
||||
return Site{
|
||||
Title: c.Title,
|
||||
URLs: c.URLs,
|
||||
// Load templates
|
||||
templateExts := []string{}
|
||||
for _, task := range site.Tasks {
|
||||
if task.TemplateExt != "" {
|
||||
templateExts = append(templateExts, task.TemplateExt)
|
||||
}
|
||||
}
|
||||
funcs["partial"] = func(name string, data interface{}) (interface{}, error) {
|
||||
t, ok := c.templates.FindPartial(name)
|
||||
if !ok {
|
||||
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
|
||||
site.templates.Funcs(funcs)
|
||||
if err := site.templates.Load("templates", templateExts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize templates
|
||||
c.templates = NewTemplates()
|
||||
c.templates.Funcs(funcs)
|
||||
|
||||
return c, nil
|
||||
return site, nil
|
||||
}
|
||||
|
||||
func (s *Site) dir(path string) *Dir {
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
htemplate "html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
|
@ -60,14 +61,6 @@ type Templates struct {
|
|||
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.
|
||||
func (t *Templates) Funcs(funcs map[string]interface{}) {
|
||||
t.funcs = funcs
|
||||
|
@ -75,6 +68,9 @@ func (t *Templates) Funcs(funcs map[string]interface{}) {
|
|||
|
||||
// LoadTemplate loads a template from the provided filenames.
|
||||
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" {
|
||||
return t.loadHTMLTemplate(name, filenames...)
|
||||
}
|
||||
|
@ -170,3 +166,16 @@ func (t *Templates) FindPartial(name string) (Template, bool) {
|
|||
}
|
||||
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