ref: 973393c99e3e6927e1c8ef27b0cd8f22eae3f4e4
parent: 9896cd0030da75bf6acab14dad0a7f78472ceff9
author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
date: Wed Mar 9 09:05:31 EST 2016
Create template clone for late template execution Fixing some breaking blogs on Go 1.6 Fixes #1879
--- a/hugolib/handler_test.go
+++ b/hugolib/handler_test.go
@@ -51,12 +51,11 @@
}
s.initializeSiteInfo()
- // From site_test.go
- templatePrep(s)
- must(s.addTemplate("_default/single.html", "{{.Content}}"))- must(s.addTemplate("head", "<head><script src=\"script.js\"></script></head>"))- must(s.addTemplate("head_abs", "<head><script src=\"/script.js\"></script></head>"))+ s.prepTemplates(
+ "_default/single.html", "{{.Content}}",+ "head", "<head><script src=\"script.js\"></script></head>",
+ "head_abs", "<head><script src=\"/script.js\"></script></head>")
// From site_test.go
createAndRenderPages(t, s)
--- a/hugolib/robotstxt_test.go
+++ b/hugolib/robotstxt_test.go
@@ -31,8 +31,7 @@
s.initializeSiteInfo()
- s.prepTemplates()
- s.addTemplate("robots.txt", ROBOTSTXT_TEMPLATE)+ s.prepTemplates("robots.txt", ROBOTSTXT_TEMPLATE) if err := s.CreatePages(); err != nil { t.Fatalf("Unable to create pages: %s", err)--- a/hugolib/rss_test.go
+++ b/hugolib/rss_test.go
@@ -58,10 +58,7 @@
Source: &source.InMemorySource{ByteSource: WEIGHTED_SOURCES},}
s.initializeSiteInfo()
- s.prepTemplates()
-
- // Add an rss.xml template to invoke the rss build.
- s.addTemplate("rss.xml", RSS_TEMPLATE)+ s.prepTemplates("rss.xml", RSS_TEMPLATE) if err := s.CreatePages(); err != nil { t.Fatalf("Unable to create pages: %s", err)--- a/hugolib/shortcode_test.go
+++ b/hugolib/shortcode_test.go
@@ -458,12 +458,16 @@
}
s.initializeSiteInfo()
- templatePrep(s)
+
+ s.loadTemplates()
+
+ s.Tmpl.AddTemplate("_default/single.html", "{{.Content}}")+
s.Tmpl.AddInternalShortcode("b.html", `b`) s.Tmpl.AddInternalShortcode("c.html", `c`) s.Tmpl.AddInternalShortcode("d.html", `d`)- must(s.addTemplate("_default/single.html", "{{.Content}}"))+ s.Tmpl.MarkReady()
createAndRenderPages(t, s)
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -50,6 +50,9 @@
var _ = transform.AbsURL
+// used to indicate if run as a test.
+var testMode bool
+
var DefaultTimer *nitro.B
var distinctErrorLogger = helpers.NewDistinctErrorLogger()
@@ -594,7 +597,7 @@
return s.ShowPlan(os.Stdout)
}
-func (s *Site) prepTemplates() {+func (s *Site) loadTemplates() {s.Tmpl = tpl.InitializeT()
s.Tmpl.LoadTemplates(s.absLayoutDir())
if s.hasTheme() {@@ -602,8 +605,18 @@
}
}
-func (s *Site) addTemplate(name, data string) error {- return s.Tmpl.AddTemplate(name, data)
+func (s *Site) prepTemplates(additionalNameValues ...string) error {+ s.loadTemplates()
+
+ for i := 0; i < len(additionalNameValues); i += 2 {+ err := s.Tmpl.AddTemplate(additionalNameValues[i], additionalNameValues[i+1])
+ if err != nil {+ return err
+ }
+ }
+ s.Tmpl.MarkReady()
+
+ return nil
}
func (s *Site) loadData(sources []source.Input) (err error) {@@ -1386,7 +1399,7 @@
var layouts []string
if !p.IsRenderable() {self := "__" + p.TargetPath()
- _, err := s.Tmpl.New(self).Parse(string(p.Content))
+ _, err := s.Tmpl.GetClone().New(self).Parse(string(p.Content))
if err != nil {results <- err
continue
@@ -2024,8 +2037,11 @@
if err := s.renderThing(d, layout, w); err != nil {// Behavior here should be dependent on if running in server or watch mode.
distinctErrorLogger.Printf("Error while rendering %s: %v", name, err)- if !s.Running() {+ if !s.Running() && !testMode {+ // TODO(bep) check if this can be propagated
os.Exit(-1)
+ } else if testMode {+ return err
}
}
@@ -2043,10 +2059,11 @@
func (s *Site) renderThing(d interface{}, layout string, w io.Writer) error {// If the template doesn't exist, then return, but leave the Writer open
- if s.Tmpl.Lookup(layout) == nil {- return fmt.Errorf("Layout not found: %s", layout)+ if templ := s.Tmpl.Lookup(layout); templ != nil {+ return templ.Execute(w, d)
}
- return s.Tmpl.ExecuteTemplate(w, layout, d)
+ return fmt.Errorf("Layout not found: %s", layout)+
}
func (s *Site) NewXMLBuffer() *bytes.Buffer {--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -30,7 +30,6 @@
"github.com/spf13/hugo/hugofs"
"github.com/spf13/hugo/source"
"github.com/spf13/hugo/target"
- "github.com/spf13/hugo/tpl"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)
@@ -65,6 +64,10 @@
`
)
+func init() {+ testMode = true
+}
+
// Issue #1797
func TestReadPagesFromSourceWithEmptySource(t *testing.T) {viper.Reset()
@@ -110,14 +113,6 @@
}
}
-func templatePrep(s *Site) {- s.Tmpl = tpl.New()
- s.Tmpl.LoadTemplates(s.absLayoutDir())
- if s.hasTheme() {- s.Tmpl.LoadTemplatesWithPrefix(s.absThemeDir()+"/layouts", "theme")
- }
-}
-
func pageMust(p *Page, err error) *Page { if err != nil {panic(err)
@@ -129,7 +124,7 @@
p, _ := NewPageFrom(strings.NewReader(PAGE_SIMPLE_TITLE), "content/a/file.md")
p.Convert()
s := new(Site)
- templatePrep(s)
+ s.prepTemplates()
err := s.renderThing(p, "foobar", nil)
if err == nil { t.Errorf("Expected err to be returned when missing the template.")@@ -138,8 +133,7 @@
func TestAddInvalidTemplate(t *testing.T) {s := new(Site)
- templatePrep(s)
- err := s.addTemplate("missing", TEMPLATE_MISSING_FUNC)+ err := s.prepTemplates("missing", TEMPLATE_MISSING_FUNC) if err == nil { t.Fatalf("Expecting the template to return an error")}
@@ -182,7 +176,6 @@
for i, test := range tests {s := new(Site)
- templatePrep(s)
p, err := NewPageFrom(strings.NewReader(test.content), "content/a/file.md")
p.Convert()
@@ -190,7 +183,9 @@
t.Fatalf("Error parsing buffer: %s", err)}
templateName := fmt.Sprintf("foobar%d", i)- err = s.addTemplate(templateName, test.template)
+
+ s.prepTemplates(templateName, test.template)
+
if err != nil { t.Fatalf("Unable to add template: %s", err)}
@@ -230,7 +225,6 @@
for i, test := range tests { s := &Site{}- templatePrep(s)
p, err := NewPageFrom(strings.NewReader(PAGE_SIMPLE_TITLE), "content/a/file.md")
if err != nil {@@ -237,11 +231,9 @@
t.Fatalf("Error parsing buffer: %s", err)}
templateName := fmt.Sprintf("default%d", i)- err = s.addTemplate(templateName, test.template)
- if err != nil {- t.Fatalf("Unable to add template: %s", err)- }
+ s.prepTemplates(templateName, test.template)
+
var err2 error
if test.missing {@@ -387,9 +379,8 @@
}
s.initializeSiteInfo()
- templatePrep(s)
- must(s.addTemplate("_default/single.html", "{{.Content}}"))+ s.prepTemplates("_default/single.html", "{{.Content}}")createAndRenderPages(t, s)
@@ -454,16 +445,14 @@
}
s.initializeSiteInfo()
- templatePrep(s)
- must(s.addTemplate("index.html", "Home Sweet {{ if.IsHome }}Home{{ end }}."))- must(s.addTemplate("_default/single.html", "{{.Content}}{{ if.IsHome }}This is not home!{{ end }}"))- must(s.addTemplate("404.html", "Page Not Found.{{ if.IsHome }}This is not home!{{ end }}"))+ s.prepTemplates(
+ "index.html", "Home Sweet {{ if.IsHome }}Home{{ end }}.",+ "_default/single.html", "{{.Content}}{{ if.IsHome }}This is not home!{{ end }}",+ "404.html", "Page Not Found.{{ if.IsHome }}This is not home!{{ end }}",+ "rss.xml", "<root>RSS</root>",
+ "sitemap.xml", "<root>SITEMAP</root>")
- // make sure the XML files also end up with ugly urls
- must(s.addTemplate("rss.xml", "<root>RSS</root>"))- must(s.addTemplate("sitemap.xml", "<root>SITEMAP</root>"))-
createAndRenderPages(t, s)
s.RenderHomePage()
s.RenderSitemap()
@@ -549,11 +538,10 @@
}
s.initializeSiteInfo()
- templatePrep(s)
+ s.prepTemplates(
+ "_default/single.html", "{{.Content}}",+ "_default/list.html", "{{ .Title }}")- must(s.addTemplate("_default/single.html", "{{.Content}}"))- must(s.addTemplate("_default/list.html", "{{ .Title }}"))-
createAndRenderPages(t, s)
s.RenderSectionLists()
@@ -614,11 +602,11 @@
}
s.initializeSiteInfo()
- templatePrep(s)
- must(s.addTemplate("_default/single.html", "{{.Content}}"))- must(s.addTemplate("head", "<head><script src=\"script.js\"></script></head>"))- must(s.addTemplate("head_abs", "<head><script src=\"/script.js\"></script></head>"))+ s.prepTemplates(
+ "_default/single.html", "{{.Content}}",+ "head", "<head><script src=\"script.js\"></script></head>",
+ "head_abs", "<head><script src=\"/script.js\"></script></head>")
createAndRenderPages(t, s)
@@ -670,8 +658,8 @@
}
t.Logf("Rendering with BaseURL %q and CanonifyURLs set %v", viper.GetString("baseURL"), canonify)s.initializeSiteInfo()
- templatePrep(s)
- must(s.addTemplate("blue/single.html", TEMPLATE_WITH_URL_ABS))+
+ s.prepTemplates("blue/single.html", TEMPLATE_WITH_URL_ABS) if err := s.CreatePages(); err != nil { t.Fatalf("Unable to create pages: %s", err)--- a/hugolib/site_url_test.go
+++ b/hugolib/site_url_test.go
@@ -103,8 +103,7 @@
Source: &source.InMemorySource{ByteSource: urlFakeSource},}
s.initializeSiteInfo()
- s.prepTemplates()
- must(s.addTemplate("indexes/blue.html", INDEX_TEMPLATE))+ s.prepTemplates("indexes/blue.html", INDEX_TEMPLATE) if err := s.CreatePages(); err != nil { t.Errorf("Unable to create pages: %s", err)--- a/hugolib/siteinfo_test.go
+++ b/hugolib/siteinfo_test.go
@@ -33,8 +33,9 @@
if s.Info.Params["MyGlobalParam"] != "FOOBAR_PARAM" { t.Errorf("Unable to set site.Info.Param")}
- s.prepTemplates()
- s.addTemplate("template", SITE_INFO_PARAM_TEMPLATE)+
+ s.prepTemplates("template", SITE_INFO_PARAM_TEMPLATE)+
buf := new(bytes.Buffer)
err := s.renderThing(s.NewNode(), "template", buf)
--- a/hugolib/sitemap_test.go
+++ b/hugolib/sitemap_test.go
@@ -50,8 +50,7 @@
s.initializeSiteInfo()
- s.prepTemplates()
- s.addTemplate("sitemap.xml", SITEMAP_TEMPLATE)+ s.prepTemplates("sitemap.xml", SITEMAP_TEMPLATE) if err := s.CreatePages(); err != nil { t.Fatalf("Unable to create pages: %s", err)--- a/tpl/template.go
+++ b/tpl/template.go
@@ -37,8 +37,10 @@
Lookup(name string) *template.Template
Templates() []*template.Template
New(name string) *template.Template
+ GetClone() *template.Template
LoadTemplates(absPath string)
LoadTemplatesWithPrefix(absPath, prefix string)
+ MarkReady()
AddTemplate(name, tpl string) error
AddAceTemplate(name, basePath, innerPath string, baseContent, innerContent []byte) error
AddInternalTemplate(prefix, name, tpl string) error
@@ -53,6 +55,7 @@
type GoHTMLTemplate struct {template.Template
+ clone *template.Template
errors []*templateErr
}
@@ -109,12 +112,12 @@
name := layout
- if localTemplates.Lookup(name) == nil {+ if Lookup(name) == nil {name = layout + ".html"
}
- if localTemplates.Lookup(name) != nil {- err := localTemplates.ExecuteTemplate(w, name, context)
+ if templ := Lookup(name); templ != nil {+ err := templ.Execute(w, context)
if err != nil {jww.ERROR.Println(err, "in", name)
}
@@ -135,11 +138,49 @@
return template.HTML(b.String())
}
+func Lookup(name string) *template.Template {+ return (tmpl.(*GoHTMLTemplate)).Lookup(name)
+}
+
+func (t *GoHTMLTemplate) Lookup(name string) *template.Template {+
+ templ := localTemplates.Lookup(name)
+
+ if templ != nil {+ return templ
+ }
+
+ if t.clone != nil {+ return t.clone.Lookup(name)
+ }
+
+ return nil
+
+}
+
+func (t *GoHTMLTemplate) GetClone() *template.Template {+ return t.clone
+}
+
func (t *GoHTMLTemplate) LoadEmbedded() {t.EmbedShortcodes()
t.EmbedTemplates()
}
+// MarkReady marks the template as "ready for execution". No changes allowed
+// after this is set.
+func (t *GoHTMLTemplate) MarkReady() {+ if t.clone == nil {+ t.clone = template.Must(t.Template.Clone())
+ }
+}
+
+func (t *GoHTMLTemplate) checkState() {+ if t.clone != nil {+ panic("template is cloned and cannot be modfified")+ }
+}
+
func (t *GoHTMLTemplate) AddInternalTemplate(prefix, name, tpl string) error { if prefix != "" { return t.AddTemplate("_internal/"+prefix+"/"+name, tpl)@@ -153,6 +194,7 @@
}
func (t *GoHTMLTemplate) AddTemplate(name, tpl string) error {+ t.checkState()
_, err := t.New(name).Parse(tpl)
if err != nil { t.errors = append(t.errors, &templateErr{name: name, err: err})@@ -161,6 +203,7 @@
}
func (t *GoHTMLTemplate) AddAceTemplate(name, basePath, innerPath string, baseContent, innerContent []byte) error {+ t.checkState()
var base, inner *ace.File
name = name[:len(name)-len(filepath.Ext(innerPath))] + ".html"
@@ -188,6 +231,7 @@
}
func (t *GoHTMLTemplate) AddTemplateFile(name, baseTemplatePath, path string) error {+ t.checkState()
// get the suffix and switch on that
ext := filepath.Ext(path)
switch ext {--
⑨