]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
tpl: Add proper file context to template parse errors
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 14 Apr 2025 09:20:36 +0000 (11:20 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 14 Apr 2025 12:38:22 +0000 (14:38 +0200)
Fixes #13604

tpl/templates/templates_integration_test.go
tpl/tplimpl/templates.go
tpl/tplimpl/templatestore.go

index a0a5e385a4704d5737d5480e68d5f6498e553662..635d521d768ea09207655c47526509bd5b358f4b 100644 (file)
@@ -17,6 +17,7 @@ import (
        "path/filepath"
        "testing"
 
+       qt "github.com/frankban/quicktest"
        "github.com/gohugoio/hugo/hugolib"
 )
 
@@ -229,3 +230,35 @@ layouts/section/section.html
        b := hugolib.Test(t, files)
        b.AssertFileContent("public/mysection/index.html", "layouts/section/section.html")
 }
+
+func TestErrorMessageParseError(t *testing.T) {
+       t.Parallel()
+
+       files := `
+-- hugo.toml --
+-- layouts/home.html --
+Line 1.
+Line 2. {{ foo }} <- this func does not exist.
+Line 3.
+`
+
+       b, err := hugolib.TestE(t, files)
+       b.Assert(err, qt.IsNotNil)
+       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`))
+}
+
+func TestErrorMessageExecuteError(t *testing.T) {
+       t.Parallel()
+
+       files := `
+-- hugo.toml --
+-- layouts/home.html --
+Line 1.
+Line 2. {{ .Foo }} <- this method does not exist.
+Line 3.
+`
+
+       b, err := hugolib.TestE(t, files)
+       b.Assert(err, qt.IsNotNil)
+       b.Assert(err.Error(), qt.Contains, filepath.FromSlash(` "/layouts/home.html:2:11": execute of template failed`))
+}
index f3f98f62299a47c656ca69f1878a73594a42846c..19de48e3801af6d2e9cd1ceb107fd202563a4c44 100644 (file)
@@ -44,7 +44,16 @@ var embeddedTemplatesAliases = map[string][]string{
        "_shortcodes/twitter.html": {"_shortcodes/tweet.html"},
 }
 
-func (t *templateNamespace) parseTemplate(ti *TemplInfo) error {
+func (s *TemplateStore) parseTemplate(ti *TemplInfo) error {
+       err := s.tns.doParseTemplate(ti)
+       if err != nil {
+               return s.addFileContext(ti, "parse of template failed", err)
+       }
+
+       return err
+}
+
+func (t *templateNamespace) doParseTemplate(ti *TemplInfo) error {
        if !ti.noBaseOf || ti.category == CategoryBaseof {
                // Delay parsing until we have the base template.
                return nil
index 2e332e382bc76d3c060c9c086cfab24491362d49..7544b562556330942c396a7bbfe2d9b4a987e3a5 100644 (file)
@@ -495,7 +495,7 @@ func (t *TemplateStore) ExecuteWithContext(ctx context.Context, ti *TemplInfo, w
 
        execErr := t.storeSite.executer.ExecuteWithContext(ctx, ti, wr, data)
        if execErr != nil {
-               return t.addFileContext(ti, execErr)
+               return t.addFileContext(ti, "execute of template failed", execErr)
        }
        return nil
 }
@@ -822,7 +822,7 @@ func (t *TemplateStore) addDeferredTemplate(owner *TemplInfo, name string, n *pa
        return nil
 }
 
-func (s *TemplateStore) addFileContext(ti *TemplInfo, inerr error) error {
+func (s *TemplateStore) addFileContext(ti *TemplInfo, what string, inerr error) error {
        if ti.Fi == nil {
                return inerr
        }
@@ -854,25 +854,27 @@ func (s *TemplateStore) addFileContext(ti *TemplInfo, inerr error) error {
                fe := herrors.NewFileErrorFromName(inErr, fi.Meta().Filename)
                fe.UpdateContent(f, lineMatcher)
 
-               if !fe.ErrorContext().Position.IsValid() {
-                       return inErr, false
-               }
-               return fe, true
+               return fe, fe.ErrorContext().Position.IsValid()
        }
 
-       inerr = fmt.Errorf("execute of template failed: %w", inerr)
+       inerr = fmt.Errorf("%s: %w", what, inerr)
 
-       if err, ok := checkFilename(ti.Fi, inerr); ok {
-               return err
+       var (
+               currentErr error
+               ok         bool
+       )
+
+       if currentErr, ok = checkFilename(ti.Fi, inerr); ok {
+               return currentErr
        }
 
        if ti.base != nil {
-               if err, ok := checkFilename(ti.base.Fi, inerr); ok {
-                       return err
+               if currentErr, ok = checkFilename(ti.base.Fi, inerr); ok {
+                       return currentErr
                }
        }
 
-       return inerr
+       return currentErr
 }
 
 func (s *TemplateStore) extractIdentifiers(line string) []string {
@@ -1389,7 +1391,7 @@ func (s *TemplateStore) parseTemplates() error {
                                if vv.state == processingStateTransformed {
                                        continue
                                }
-                               if err := s.tns.parseTemplate(vv); err != nil {
+                               if err := s.parseTemplate(vv); err != nil {
                                        return err
                                }
                        }
@@ -1409,7 +1411,7 @@ func (s *TemplateStore) parseTemplates() error {
                                                // The regular expression used to detect if a template needs a base template has some
                                                // rare false positives. Assume we don't need one.
                                                vv.noBaseOf = true
-                                               if err := s.tns.parseTemplate(vv); err != nil {
+                                               if err := s.parseTemplate(vv); err != nil {
                                                        return err
                                                }
                                                continue
@@ -1438,7 +1440,7 @@ func (s *TemplateStore) parseTemplates() error {
                                if vvv.state == processingStateTransformed {
                                        continue
                                }
-                               if err := s.tns.parseTemplate(vvv); err != nil {
+                               if err := s.parseTemplate(vvv); err != nil {
                                        return err
                                }
                        }