shithub: hugo

Download patch

ref: c91dbe4ce9c30623ba6e686fd17efae935aa0cc5
parent: 6e0452e189884667cb58778768136ad28ac31688
author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
date: Mon Jul 13 09:40:35 EDT 2020

Fix baseof block regression

From Hugo 0.74.0.

Fixes #7478

--- a/hugolib/hugo_sites_build_errors_test.go
+++ b/hugolib/hugo_sites_build_errors_test.go
@@ -65,7 +65,8 @@
 			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 @@
 				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())
 
 			},
 		},
--- a/hugolib/template_test.go
+++ b/hugolib/template_test.go
@@ -677,3 +677,46 @@
 	)
 
 }
+
+// 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
+`,
+	)
+
+}
--- a/tpl/tplimpl/template.go
+++ b/tpl/tplimpl/template.go
@@ -138,7 +138,7 @@
 		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 @@
 	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 @@
 
 		t.applyTemplateTransformers(t.main, ts)
 
+		if err := t.extractPartials(ts.Template); err != nil {
+			return nil, false, err
+		}
+
 		return ts, true, nil
 
 	}
@@ -570,12 +568,6 @@
 	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
 	}
 
@@ -582,12 +574,6 @@
 	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 @@
 	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 @@
 			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 @@
 	*templateStateMap
 }
 
-func (t templateNamespace) Clone(lock bool) *templateNamespace {
-	if t.mu != nil {
-		t.mu.Lock()
-		defer t.mu.Unlock()
-	}
+func (t templateNamespace) Clone() *templateNamespace {
+	t.mu.Lock()
+	defer t.mu.Unlock()
 
-	var mu *sync.RWMutex
-	if lock {
-		mu = &sync.RWMutex{}
-	}
-
 	t.templateStateMap = &templateStateMap{
 		templates: make(map[string]*templateState),
-		mu:        mu,
 	}
 
 	t.prototypeText = texttemplate.Must(t.prototypeText.Clone())
@@ -851,10 +844,8 @@
 }
 
 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 {
@@ -861,10 +852,6 @@
 		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) 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 @@
 }
 
 type templateStateMap struct {
-	mu        *sync.RWMutex // May be nil
+	mu        sync.RWMutex
 	templates map[string]*templateState
 }