diff --git a/plugins/plugins.go b/plugins/plugins.go index 17f2fe3..05bc03b 100644 --- a/plugins/plugins.go +++ b/plugins/plugins.go @@ -22,7 +22,7 @@ type Plugin interface { ConfigureTemplateEngine(*liquid.Engine) error ModifySiteDrop(Site, map[string]interface{}) error PostRead(Site) error - PostRender([]byte) []byte + PostRender([]byte) ([]byte, error) } // Site is the site interface that is available to a plugin. @@ -61,7 +61,7 @@ func (p plugin) Initialize(Site) error { return nil func (p plugin) ConfigureTemplateEngine(*liquid.Engine) error { return nil } func (p plugin) ModifySiteDrop(Site, map[string]interface{}) error { return nil } func (p plugin) PostRead(Site) error { return nil } -func (p plugin) PostRender(b []byte) []byte { return b } +func (p plugin) PostRender(b []byte) ([]byte, error) { return b, nil } var directory = map[string]Plugin{} @@ -90,11 +90,10 @@ func init() { // jemojiPlugin emulates the jekyll-jemoji plugin. type jemojiPlugin struct{ plugin } -func (p jemojiPlugin) PostRender(b []byte) []byte { +func (p jemojiPlugin) PostRender(b []byte) ([]byte, error) { return utils.ApplyToHTMLText(b, func(s string) string { - s = emoji.Sprint(s) - return s - }) + return emoji.Sprint(s) + }), nil } // jekyllMentionsPlugin emulates the jekyll-mentions plugin. @@ -102,10 +101,10 @@ type jekyllMentionsPlugin struct{ plugin } var mentionPattern = regexp.MustCompile(`@(\w+)`) -func (p jekyllMentionsPlugin) PostRender(b []byte) []byte { +func (p jekyllMentionsPlugin) PostRender(b []byte) ([]byte, error) { return utils.ApplyToHTMLText(b, func(s string) string { return mentionPattern.ReplaceAllString(s, `@$1`) - }) + }), nil } // jekyllOptionalFrontMatterPlugin emulates the jekyll-optional-front-matter plugin. diff --git a/site/build.go b/site/build.go index fad48c7..a4457f1 100644 --- a/site/build.go +++ b/site/build.go @@ -44,7 +44,7 @@ func (s *Site) Build() (int, error) { if err := s.setTimeZone(); err != nil { return 0, err } - if err := s.prepareRendering(); err != nil { + if err := s.ensureRendered(); err != nil { return 0, err } if err := s.Clean(); err != nil { diff --git a/site/drop.go b/site/drop.go index f5b588e..2ae76f2 100644 --- a/site/drop.go +++ b/site/drop.go @@ -12,7 +12,7 @@ import ( // ToLiquid returns the site variable for template evaluation. func (s *Site) ToLiquid() interface{} { - s.Do(func() { + s.dropOnce.Do(func() { if err := s.initializeDrop(); err != nil { log.Fatalf("ToLiquid failed: %s\n", err) } @@ -51,16 +51,6 @@ func (s *Site) initializeDrop() error { }) } -// Render renders the site's pages. -func (s *Site) Render() error { - for _, c := range s.Collections { - if err := c.Render(); err != nil { - return err - } - } - return nil -} - // The following functions are only used in the drop, therefore they're // non-public and they're listed here. // diff --git a/site/errors.go b/site/errors.go new file mode 100644 index 0000000..1d05dc8 --- /dev/null +++ b/site/errors.go @@ -0,0 +1,21 @@ +package site + +import ( + "fmt" + "strings" +) + +func combineErrors(errs []error) error { + switch len(errs) { + case 0: + return nil + case 1: + return errs[0] + default: + messages := make([]string, len(errs)) + for i, e := range errs { + messages[i] = e.Error() + } + return fmt.Errorf(strings.Join(messages, "\n")) + } +} diff --git a/site/render.go b/site/render.go new file mode 100644 index 0000000..3092ce4 --- /dev/null +++ b/site/render.go @@ -0,0 +1,25 @@ +package site + +// Render renders the site's pages. +func (s *Site) Render() error { + for _, c := range s.Collections { + if err := c.Render(); err != nil { + return err + } + } + return nil +} + +func (s *Site) ensureRendered() (err error) { + s.renderOnce.Do(func() { + err = s.initializeRenderingPipeline() + if err != nil { + return + } + err = s.Render() + if err != nil { + return + } + }) + return +} diff --git a/site/site.go b/site/site.go index 4421936..dee76c6 100644 --- a/site/site.go +++ b/site/site.go @@ -20,15 +20,18 @@ type Site struct { Collections []*collection.Collection Routes map[string]pages.Document // URL path -> Document, only for output pages - config config.Config - data map[string]interface{} - flags config.Flags - pipeline *pipelines.Pipeline - themeDir string - docs []pages.Document // all documents, whether or not they are output - preparedToRender bool - drop map[string]interface{} // cached drop value - sync.Once // for computing the drop + config config.Config + data map[string]interface{} + flags config.Flags + themeDir string + + docs []pages.Document // all documents, whether or not they are output + + pipeline *pipelines.Pipeline + renderOnce sync.Once + + drop map[string]interface{} // cached drop value + dropOnce sync.Once } // SourceDir returns the site source directory. diff --git a/site/write.go b/site/write.go index 382d0f4..c5683a2 100644 --- a/site/write.go +++ b/site/write.go @@ -6,7 +6,6 @@ import ( "io" "os" "path/filepath" - "strings" "github.com/osteele/gojekyll/pages" "github.com/osteele/gojekyll/plugins" @@ -14,7 +13,6 @@ import ( ) // WriteFiles writes output files. -// It attends to options.dry_run. func (s *Site) WriteFiles() (count int, err error) { errs := make(chan error) // without this, large sites run out of file descriptors @@ -40,7 +38,6 @@ func (s *Site) WriteFiles() (count int, err error) { } // WriteDoc writes a document to the destination directory. -// It attends to options.dry_run. func (s *Site) WriteDoc(d pages.Document) error { from := d.SourcePath() rel := d.Permalink() @@ -69,7 +66,7 @@ func (s *Site) WriteDoc(d pages.Document) error { } } -// WriteDocument writes the document to a writer. +// WriteDocument writes the rendered document. func (s *Site) WriteDocument(w io.Writer, d pages.Document) error { switch p := d.(type) { case pages.Page: @@ -79,9 +76,9 @@ func (s *Site) WriteDocument(w io.Writer, d pages.Document) error { } } -// WritePage writes the page to a writer. +// WritePage writes the rendered page. func (s *Site) WritePage(w io.Writer, p pages.Page) error { - if err := s.prepareRendering(); err != nil { + if err := s.ensureRendered(); err != nil { return err } buf := new(bytes.Buffer) @@ -89,9 +86,9 @@ func (s *Site) WritePage(w io.Writer, p pages.Page) error { return err } b := buf.Bytes() - err := s.runHooks(func(p plugins.Plugin) error { - b = p.PostRender(b) - return nil + err := s.runHooks(func(p plugins.Plugin) (err error) { + b, err = p.PostRender(b) + return }) if err != nil { return err @@ -99,31 +96,3 @@ func (s *Site) WritePage(w io.Writer, p pages.Page) error { _, err = w.Write(b) return err } - -func combineErrors(errs []error) error { - switch len(errs) { - case 0: - return nil - case 1: - return errs[0] - default: - messages := make([]string, len(errs)) - for i, e := range errs { - messages[i] = e.Error() - } - return fmt.Errorf(strings.Join(messages, "\n")) - } -} - -func (s *Site) prepareRendering() error { - if !s.preparedToRender { - if err := s.initializeRenderingPipeline(); err != nil { - return err - } - if err := s.Render(); err != nil { - return err - } - s.preparedToRender = true - } - return nil -}