Skip to content

Commit 8a2830f

Browse files
committed
tpl: Add proper file context to template parse errors
Fixes #13604
1 parent 1e0287f commit 8a2830f

File tree

3 files changed

+60
-16
lines changed

3 files changed

+60
-16
lines changed

Diff for: tpl/templates/templates_integration_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"path/filepath"
1818
"testing"
1919

20+
qt "github.com/frankban/quicktest"
2021
"github.com/gohugoio/hugo/hugolib"
2122
)
2223

@@ -229,3 +230,35 @@ layouts/section/section.html
229230
b := hugolib.Test(t, files)
230231
b.AssertFileContent("public/mysection/index.html", "layouts/section/section.html")
231232
}
233+
234+
func TestErrorMessageParseError(t *testing.T) {
235+
t.Parallel()
236+
237+
files := `
238+
-- hugo.toml --
239+
-- layouts/home.html --
240+
Line 1.
241+
Line 2. {{ foo }} <- this func does not exist.
242+
Line 3.
243+
`
244+
245+
b, err := hugolib.TestE(t, files)
246+
b.Assert(err, qt.IsNotNil)
247+
b.Assert(err.Error(), qt.Contains, filepath.FromSlash(`"/layouts/home.html:2:1": parse of template failed: template: home.html:2: function "foo" not defined`))
248+
}
249+
250+
func TestErrorMessageExecuteError(t *testing.T) {
251+
t.Parallel()
252+
253+
files := `
254+
-- hugo.toml --
255+
-- layouts/home.html --
256+
Line 1.
257+
Line 2. {{ .Foo }} <- this method does not exist.
258+
Line 3.
259+
`
260+
261+
b, err := hugolib.TestE(t, files)
262+
b.Assert(err, qt.IsNotNil)
263+
b.Assert(err.Error(), qt.Contains, filepath.FromSlash(` "/layouts/home.html:2:11": execute of template failed`))
264+
}

Diff for: tpl/tplimpl/templates.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,16 @@ var embeddedTemplatesAliases = map[string][]string{
4444
"_shortcodes/twitter.html": {"_shortcodes/tweet.html"},
4545
}
4646

47-
func (t *templateNamespace) parseTemplate(ti *TemplInfo) error {
47+
func (s *TemplateStore) parseTemplate(ti *TemplInfo) error {
48+
err := s.tns.doParseTemplate(ti)
49+
if err != nil {
50+
return s.addFileContext(ti, "parse of template failed", err)
51+
}
52+
53+
return err
54+
}
55+
56+
func (t *templateNamespace) doParseTemplate(ti *TemplInfo) error {
4857
if !ti.noBaseOf || ti.category == CategoryBaseof {
4958
// Delay parsing until we have the base template.
5059
return nil

Diff for: tpl/tplimpl/templatestore.go

+17-15
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ func (t *TemplateStore) ExecuteWithContext(ctx context.Context, ti *TemplInfo, w
495495

496496
execErr := t.storeSite.executer.ExecuteWithContext(ctx, ti, wr, data)
497497
if execErr != nil {
498-
return t.addFileContext(ti, execErr)
498+
return t.addFileContext(ti, "execute of template failed", execErr)
499499
}
500500
return nil
501501
}
@@ -822,7 +822,7 @@ func (t *TemplateStore) addDeferredTemplate(owner *TemplInfo, name string, n *pa
822822
return nil
823823
}
824824

825-
func (s *TemplateStore) addFileContext(ti *TemplInfo, inerr error) error {
825+
func (s *TemplateStore) addFileContext(ti *TemplInfo, what string, inerr error) error {
826826
if ti.Fi == nil {
827827
return inerr
828828
}
@@ -854,25 +854,27 @@ func (s *TemplateStore) addFileContext(ti *TemplInfo, inerr error) error {
854854
fe := herrors.NewFileErrorFromName(inErr, fi.Meta().Filename)
855855
fe.UpdateContent(f, lineMatcher)
856856

857-
if !fe.ErrorContext().Position.IsValid() {
858-
return inErr, false
859-
}
860-
return fe, true
857+
return fe, fe.ErrorContext().Position.IsValid()
861858
}
862859

863-
inerr = fmt.Errorf("execute of template failed: %w", inerr)
860+
inerr = fmt.Errorf("%s: %w", what, inerr)
864861

865-
if err, ok := checkFilename(ti.Fi, inerr); ok {
866-
return err
862+
var (
863+
currentErr error
864+
ok bool
865+
)
866+
867+
if currentErr, ok = checkFilename(ti.Fi, inerr); ok {
868+
return currentErr
867869
}
868870

869871
if ti.base != nil {
870-
if err, ok := checkFilename(ti.base.Fi, inerr); ok {
871-
return err
872+
if currentErr, ok = checkFilename(ti.base.Fi, inerr); ok {
873+
return currentErr
872874
}
873875
}
874876

875-
return inerr
877+
return currentErr
876878
}
877879

878880
func (s *TemplateStore) extractIdentifiers(line string) []string {
@@ -1389,7 +1391,7 @@ func (s *TemplateStore) parseTemplates() error {
13891391
if vv.state == processingStateTransformed {
13901392
continue
13911393
}
1392-
if err := s.tns.parseTemplate(vv); err != nil {
1394+
if err := s.parseTemplate(vv); err != nil {
13931395
return err
13941396
}
13951397
}
@@ -1409,7 +1411,7 @@ func (s *TemplateStore) parseTemplates() error {
14091411
// The regular expression used to detect if a template needs a base template has some
14101412
// rare false positives. Assume we don't need one.
14111413
vv.noBaseOf = true
1412-
if err := s.tns.parseTemplate(vv); err != nil {
1414+
if err := s.parseTemplate(vv); err != nil {
14131415
return err
14141416
}
14151417
continue
@@ -1438,7 +1440,7 @@ func (s *TemplateStore) parseTemplates() error {
14381440
if vvv.state == processingStateTransformed {
14391441
continue
14401442
}
1441-
if err := s.tns.parseTemplate(vvv); err != nil {
1443+
if err := s.parseTemplate(vvv); err != nil {
14421444
return err
14431445
}
14441446
}

0 commit comments

Comments
 (0)