mirror of
				https://github.com/gohugoio/hugo.git
				synced 2024-05-11 05:54:58 +00:00 
			
		
		
		
	| @@ -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()) | ||||
|  | ||||
| 			}, | ||||
| 		}, | ||||
|   | ||||
| @@ -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 | ||||
| `, | ||||
| 	) | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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,26 +792,9 @@ 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 { | ||||
| 		if err := t.extractPartials(v.Template); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 				t.main.templates[templ.Name()] = ts | ||||
|  | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for name, source := range t.transformNotFound { | ||||
| @@ -828,20 +829,12 @@ type templateNamespace struct { | ||||
| 	*templateStateMap | ||||
| } | ||||
|  | ||||
| func (t templateNamespace) Clone(lock bool) *templateNamespace { | ||||
| 	if t.mu != nil { | ||||
| 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,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() | ||||
| 	} | ||||
|  | ||||
| 	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() | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user