mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
6e0452e189
commit
c91dbe4ce9
3 changed files with 94 additions and 65 deletions
|
@ -65,7 +65,8 @@ func TestSiteBuildErrors(t *testing.T) {
|
||||||
fileFixer: func(content string) string {
|
fileFixer: func(content string) string {
|
||||||
return strings.Replace(content, ".Title }}", ".Title }", 1)
|
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)
|
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().LineNumber, qt.Equals, 5)
|
||||||
a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 1)
|
a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 1)
|
||||||
a.c.Assert(fe.ChromaLexer, qt.Equals, "go-html-template")
|
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),
|
baseof: make(map[string]templateInfo),
|
||||||
needsBaseof: make(map[string]templateInfo),
|
needsBaseof: make(map[string]templateInfo),
|
||||||
|
|
||||||
main: newTemplateNamespace(funcMap, false),
|
main: newTemplateNamespace(funcMap),
|
||||||
|
|
||||||
Deps: d,
|
Deps: d,
|
||||||
layoutHandler: output.NewLayoutHandler(),
|
layoutHandler: output.NewLayoutHandler(),
|
||||||
|
@ -174,17 +174,11 @@ func newTemplateExec(d *deps.Deps) (*templateExec, error) {
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTemplateNamespace(funcs map[string]interface{}, lock bool) *templateNamespace {
|
func newTemplateNamespace(funcs map[string]interface{}) *templateNamespace {
|
||||||
var mu *sync.RWMutex
|
|
||||||
if lock {
|
|
||||||
mu = &sync.RWMutex{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &templateNamespace{
|
return &templateNamespace{
|
||||||
prototypeHTML: htmltemplate.New("").Funcs(funcs),
|
prototypeHTML: htmltemplate.New("").Funcs(funcs),
|
||||||
prototypeText: texttemplate.New("").Funcs(funcs),
|
prototypeText: texttemplate.New("").Funcs(funcs),
|
||||||
templateStateMap: &templateStateMap{
|
templateStateMap: &templateStateMap{
|
||||||
mu: mu,
|
|
||||||
templates: make(map[string]*templateState),
|
templates: make(map[string]*templateState),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -426,6 +420,10 @@ func (t *templateHandler) findLayout(d output.LayoutDescriptor, f output.Format)
|
||||||
|
|
||||||
t.applyTemplateTransformers(t.main, ts)
|
t.applyTemplateTransformers(t.main, ts)
|
||||||
|
|
||||||
|
if err := t.extractPartials(ts.Template); err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
return ts, true, nil
|
return ts, true, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -570,24 +568,12 @@ func (t *templateHandler) addTemplateFile(name, path string) error {
|
||||||
if isBaseTemplatePath(name) {
|
if isBaseTemplatePath(name) {
|
||||||
// Store it for later.
|
// Store it for later.
|
||||||
t.baseof[name] = tinfo
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
needsBaseof := !t.noBaseNeeded(name) && needsBaseTemplate(tinfo.template)
|
needsBaseof := !t.noBaseNeeded(name) && needsBaseTemplate(tinfo.template)
|
||||||
if needsBaseof {
|
if needsBaseof {
|
||||||
t.needsBaseof[name] = tinfo
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,6 +734,38 @@ func (t *templateHandler) noBaseNeeded(name string) bool {
|
||||||
return strings.Contains(name, "_markup/")
|
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 {
|
func (t *templateHandler) postTransform() error {
|
||||||
defineCheckedHTML := false
|
defineCheckedHTML := false
|
||||||
defineCheckedText := false
|
defineCheckedText := false
|
||||||
|
@ -774,25 +792,8 @@ func (t *templateHandler) postTransform() error {
|
||||||
defineCheckedHTML = true
|
defineCheckedHTML = true
|
||||||
}
|
}
|
||||||
|
|
||||||
templs := templates(v.Template)
|
if err := t.extractPartials(v.Template); err != nil {
|
||||||
for _, templ := range templs {
|
return err
|
||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,20 +829,12 @@ type templateNamespace struct {
|
||||||
*templateStateMap
|
*templateStateMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t templateNamespace) Clone(lock bool) *templateNamespace {
|
func (t templateNamespace) Clone() *templateNamespace {
|
||||||
if t.mu != nil {
|
t.mu.Lock()
|
||||||
t.mu.Lock()
|
defer t.mu.Unlock()
|
||||||
defer t.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
var mu *sync.RWMutex
|
|
||||||
if lock {
|
|
||||||
mu = &sync.RWMutex{}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.templateStateMap = &templateStateMap{
|
t.templateStateMap = &templateStateMap{
|
||||||
templates: make(map[string]*templateState),
|
templates: make(map[string]*templateState),
|
||||||
mu: mu,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.prototypeText = texttemplate.Must(t.prototypeText.Clone())
|
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) {
|
func (t *templateNamespace) Lookup(name string) (tpl.Template, bool) {
|
||||||
if t.mu != nil {
|
t.mu.RLock()
|
||||||
t.mu.RLock()
|
defer t.mu.RUnlock()
|
||||||
defer t.mu.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
templ, found := t.templates[name]
|
templ, found := t.templates[name]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.mu != nil {
|
|
||||||
return &templateWrapperWithLock{RWMutex: t.mu, Template: templ}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return templ, found
|
return templ, found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -892,10 +879,8 @@ func (t *templateNamespace) newTemplateLookup(in *templateState) func(name strin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *templateNamespace) parse(info templateInfo) (*templateState, error) {
|
func (t *templateNamespace) parse(info templateInfo) (*templateState, error) {
|
||||||
if t.mu != nil {
|
t.mu.Lock()
|
||||||
t.mu.Lock()
|
defer t.mu.Unlock()
|
||||||
defer t.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.isText {
|
if info.isText {
|
||||||
prototype := t.prototypeText
|
prototype := t.prototypeText
|
||||||
|
@ -952,7 +937,7 @@ func isText(templ tpl.Template) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type templateStateMap struct {
|
type templateStateMap struct {
|
||||||
mu *sync.RWMutex // May be nil
|
mu sync.RWMutex
|
||||||
templates map[string]*templateState
|
templates map[string]*templateState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue