Fix baseof block regression
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 13 Jul 2020 11:40:35 +0000 (13:40 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 13 Jul 2020 18:45:09 +0000 (20:45 +0200)
From Hugo 0.74.0.

Fixes #7478

hugolib/hugo_sites_build_errors_test.go
hugolib/template_test.go
tpl/tplimpl/template.go

index 4de98a78875d1abe5b4e5277873083d78c432cb0..d90a8b364088aa8c8ccfef4e63fbb0fab3c9c199 100644 (file)
@@ -65,7 +65,8 @@ func TestSiteBuildErrors(t *testing.T) {
                        fileFixer: func(content string) string {
                                return strings.Replace(content, ".Title }}", ".Title }", 1)
                        },
-                       assertCreateError: func(a testSiteBuildErrorAsserter, err error) {
+                       // Base templates gets parsed at build time.
+                       assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
                                a.assertLineNumber(4, err)
                        },
                },
@@ -90,7 +91,7 @@ func TestSiteBuildErrors(t *testing.T) {
                                a.c.Assert(fe.Position().LineNumber, qt.Equals, 5)
                                a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 1)
                                a.c.Assert(fe.ChromaLexer, qt.Equals, "go-html-template")
-                               a.assertErrorMessage("\"layouts/_default/single.html:5:1\": parse failed: template: _default/single.html.___b:5: unexpected \"}\" in operand", fe.Error())
+                               a.assertErrorMessage("\"layouts/foo/single.html:5:1\": parse failed: template: foo/single.html:5: unexpected \"}\" in operand", fe.Error())
 
                        },
                },
index 673d91b5c15ce73142950b79738a21d179ce826d..a215f09dcf3bd714825296d19dd2cfdb2ba199c8 100644 (file)
@@ -677,3 +677,46 @@ P3: Inline: p3
        )
 
 }
+
+// https://github.com/gohugoio/hugo/issues/7478
+func TestBaseWithAndWithoutDefine(t *testing.T) {
+
+       b := newTestSitesBuilder(t)
+
+       b.WithContent("p1.md", "---\ntitle: P\n---\nContent")
+
+       b.WithTemplates(
+               "_default/baseof.html", `
+::Header Start:{{ block "header" . }}{{ end }}:Header End:
+::{{ block "main" . }}Main{{ end }}::
+`, "index.html", `
+{{ define "header" }}
+Home Header
+{{ end }}
+{{ define "main" }}
+This is home main
+{{ end }}
+`,
+
+               "_default/single.html", `
+{{ define "main" }}
+This is single main
+{{ end }}
+`,
+       )
+
+       b.CreateSites().Build(BuildCfg{})
+
+       b.AssertFileContent("public/index.html", `
+Home Header
+This is home main
+`,
+       )
+
+       b.AssertFileContent("public/p1/index.html", `
+ ::Header Start::Header End:
+This is single main
+`,
+       )
+
+}
index 6171d167be247280a84d7763c91caae7db30f271..e3a4ce09029bdaf29f0041268b20f1f417703020 100644 (file)
@@ -138,7 +138,7 @@ func newTemplateExec(d *deps.Deps) (*templateExec, error) {
                baseof:       make(map[string]templateInfo),
                needsBaseof:  make(map[string]templateInfo),
 
-               main: newTemplateNamespace(funcMap, false),
+               main: newTemplateNamespace(funcMap),
 
                Deps:                d,
                layoutHandler:       output.NewLayoutHandler(),
@@ -174,17 +174,11 @@ func newTemplateExec(d *deps.Deps) (*templateExec, error) {
        return e, nil
 }
 
-func newTemplateNamespace(funcs map[string]interface{}, lock bool) *templateNamespace {
-       var mu *sync.RWMutex
-       if lock {
-               mu = &sync.RWMutex{}
-       }
-
+func newTemplateNamespace(funcs map[string]interface{}) *templateNamespace {
        return &templateNamespace{
                prototypeHTML: htmltemplate.New("").Funcs(funcs),
                prototypeText: texttemplate.New("").Funcs(funcs),
                templateStateMap: &templateStateMap{
-                       mu:        mu,
                        templates: make(map[string]*templateState),
                },
        }
@@ -426,6 +420,10 @@ func (t *templateHandler) findLayout(d output.LayoutDescriptor, f output.Format)
 
                t.applyTemplateTransformers(t.main, ts)
 
+               if err := t.extractPartials(ts.Template); err != nil {
+                       return nil, false, err
+               }
+
                return ts, true, nil
 
        }
@@ -570,24 +568,12 @@ func (t *templateHandler) addTemplateFile(name, path string) error {
        if isBaseTemplatePath(name) {
                // Store it for later.
                t.baseof[name] = tinfo
-               // Also parse and add it on its own to make sure we reach the inline partials.
-               tinfo.name = name + ".___b"
-               _, err := t.addTemplateTo(tinfo, t.main)
-               if err != nil {
-                       return tinfo.errWithFileContext("parse failed", err)
-               }
                return nil
        }
 
        needsBaseof := !t.noBaseNeeded(name) && needsBaseTemplate(tinfo.template)
        if needsBaseof {
                t.needsBaseof[name] = tinfo
-               // Also parse and add it on its own to make sure we reach the inline partials.
-               tinfo.name = name + ".___b"
-               _, err := t.addTemplateTo(tinfo, t.main)
-               if err != nil {
-                       return tinfo.errWithFileContext("parse failed", err)
-               }
                return nil
        }
 
@@ -748,6 +734,38 @@ func (t *templateHandler) noBaseNeeded(name string) bool {
        return strings.Contains(name, "_markup/")
 }
 
+func (t *templateHandler) extractPartials(templ tpl.Template) error {
+       templs := templates(templ)
+       for _, templ := range templs {
+               if templ.Name() == "" || !strings.HasPrefix(templ.Name(), "partials/") {
+                       continue
+               }
+
+               ts := newTemplateState(templ, templateInfo{name: templ.Name()})
+               ts.typ = templatePartial
+
+               t.main.mu.RLock()
+               _, found := t.main.templates[templ.Name()]
+               t.main.mu.RUnlock()
+
+               if !found {
+                       t.main.mu.Lock()
+                       // This is a template defined inline.
+                       _, err := applyTemplateTransformers(ts, t.main.newTemplateLookup(ts))
+                       if err != nil {
+                               t.main.mu.Unlock()
+                               return err
+                       }
+                       t.main.templates[templ.Name()] = ts
+                       t.main.mu.Unlock()
+
+               }
+       }
+
+       return nil
+
+}
+
 func (t *templateHandler) postTransform() error {
        defineCheckedHTML := false
        defineCheckedText := false
@@ -774,25 +792,8 @@ func (t *templateHandler) postTransform() error {
                        defineCheckedHTML = true
                }
 
-               templs := templates(v.Template)
-               for _, templ := range templs {
-                       if templ.Name() == "" || !strings.HasPrefix(templ.Name(), "partials/") {
-                               continue
-                       }
-
-                       ts := newTemplateState(templ, templateInfo{name: templ.Name()})
-                       ts.typ = templatePartial
-
-                       if _, found := t.main.templates[templ.Name()]; !found {
-                               // This is a template defined inline.
-
-                               _, err := applyTemplateTransformers(ts, t.main.newTemplateLookup(ts))
-                               if err != nil {
-                                       return err
-                               }
-                               t.main.templates[templ.Name()] = ts
-
-                       }
+               if err := t.extractPartials(v.Template); err != nil {
+                       return err
                }
        }
 
@@ -828,20 +829,12 @@ type templateNamespace struct {
        *templateStateMap
 }
 
-func (t templateNamespace) Clone(lock bool) *templateNamespace {
-       if t.mu != nil {
-               t.mu.Lock()
-               defer t.mu.Unlock()
-       }
-
-       var mu *sync.RWMutex
-       if lock {
-               mu = &sync.RWMutex{}
-       }
+func (t templateNamespace) Clone() *templateNamespace {
+       t.mu.Lock()
+       defer t.mu.Unlock()
 
        t.templateStateMap = &templateStateMap{
                templates: make(map[string]*templateState),
-               mu:        mu,
        }
 
        t.prototypeText = texttemplate.Must(t.prototypeText.Clone())
@@ -851,20 +844,14 @@ func (t templateNamespace) Clone(lock bool) *templateNamespace {
 }
 
 func (t *templateNamespace) Lookup(name string) (tpl.Template, bool) {
-       if t.mu != nil {
-               t.mu.RLock()
-               defer t.mu.RUnlock()
-       }
+       t.mu.RLock()
+       defer t.mu.RUnlock()
 
        templ, found := t.templates[name]
        if !found {
                return nil, false
        }
 
-       if t.mu != nil {
-               return &templateWrapperWithLock{RWMutex: t.mu, Template: templ}, true
-       }
-
        return templ, found
 }
 
@@ -892,10 +879,8 @@ func (t *templateNamespace) newTemplateLookup(in *templateState) func(name strin
 }
 
 func (t *templateNamespace) parse(info templateInfo) (*templateState, error) {
-       if t.mu != nil {
-               t.mu.Lock()
-               defer t.mu.Unlock()
-       }
+       t.mu.Lock()
+       defer t.mu.Unlock()
 
        if info.isText {
                prototype := t.prototypeText
@@ -952,7 +937,7 @@ func isText(templ tpl.Template) bool {
 }
 
 type templateStateMap struct {
-       mu        *sync.RWMutex // May be nil
+       mu        sync.RWMutex
        templates map[string]*templateState
 }