From 0e54f9eec5ed30c1e18b71aab4e2ee5e25d63912 Mon Sep 17 00:00:00 2001 From: adnano Date: Fri, 14 May 2021 00:17:10 -0400 Subject: [PATCH] Add dir and page functions and fix partial function --- dir.go | 53 ++++++++++++++++++++++---------- funcs.go | 25 +++++++++------ main.go | 33 +++++++------------- config.go => site.go | 72 ++++++++++++++++++++------------------------ templates.go | 25 ++++++++++----- 5 files changed, 114 insertions(+), 94 deletions(-) rename config.go => site.go (54%) diff --git a/dir.go b/dir.go index c39a22d..2e3d13a 100644 --- a/dir.go +++ b/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 +} diff --git a/funcs.go b/funcs.go index 307ab80..ec282bf 100644 --- a/funcs.go +++ b/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{} diff --git a/main.go b/main.go index 03a861a..308fd13 100644 --- a/main.go +++ b/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 diff --git a/config.go b/site.go similarity index 54% rename from config.go rename to site.go index f3327f9..ff61679 100644 --- a/config.go +++ b/site.go @@ -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) } diff --git a/templates.go b/templates.go index b4012ef..499afef 100644 --- a/templates.go +++ b/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 +}