Improve error messages, esp. when the server is running

* Add file context to minifier errors when publishing
* Misc fixes (see issues)
* Allow custom server error template in layouts/server/error.html

To get to this, this commit also cleans up and simplifies the code surrounding errors and files. This also removes the usage of `github.com/pkg/errors`, mostly because of https://github.com/pkg/errors/issues/223 -- but also because most of this is now built-in to Go.

Fixes #9852
Fixes #9857
Fixes #9863
This commit is contained in:
Bjørn Erik Pedersen
2022-05-02 16:07:52 +02:00
parent 6eea32bd6b
commit f2946da9e8
109 changed files with 861 additions and 780 deletions

View File

@@ -33,11 +33,12 @@ import (
"github.com/gohugoio/hugo/parser/metadecoders"
"errors"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/modules"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/privacy"
@@ -510,5 +511,5 @@ func (configLoader) loadSiteConfig(cfg config.Provider) (scfg SiteConfig, err er
}
func (l configLoader) wrapFileError(err error, filename string) error {
return herrors.WithFileContextForFileDefault(err, filename, l.Fs)
return herrors.NewFileErrorFromFile(err, filename, filename, l.Fs, herrors.SimpleLineMatcher)
}

View File

@@ -146,7 +146,7 @@ baseURL = "https://example.org"
_, _, err := LoadConfig(ConfigSourceDescriptor{Fs: mm, Environment: "development", Filename: "hugo.toml", AbsConfigDir: "config"})
c.Assert(err, qt.Not(qt.IsNil))
fe := herrors.UnwrapErrorWithFileContext(err)
fe := herrors.UnwrapFileError(err)
c.Assert(fe, qt.Not(qt.IsNil))
c.Assert(fe.Position().Filename, qt.Equals, filepath.FromSlash("config/development/config.toml"))
}

View File

@@ -14,6 +14,7 @@
package hugolib
import (
"fmt"
"io"
"path/filepath"
"strings"
@@ -25,7 +26,6 @@ import (
"github.com/gohugoio/hugo/resources/page"
"github.com/pkg/errors"
"github.com/spf13/afero"
)
@@ -48,12 +48,12 @@ func (f ContentFactory) ApplyArchetypeFilename(w io.Writer, p page.Page, archety
}
if fi.IsDir() {
return errors.Errorf("archetype directory (%q) not supported", archetypeFilename)
return fmt.Errorf("archetype directory (%q) not supported", archetypeFilename)
}
templateSource, err := afero.ReadFile(f.h.SourceFilesystems.Archetypes.Fs, archetypeFilename)
if err != nil {
return errors.Wrapf(err, "failed to read archetype file %q: %s", archetypeFilename, err)
return fmt.Errorf("failed to read archetype file %q: %s: %w", archetypeFilename, err, err)
}
@@ -79,12 +79,12 @@ func (f ContentFactory) ApplyArchetypeTemplate(w io.Writer, p page.Page, archety
templ, err := ps.s.TextTmpl().Parse("archetype.md", string(templateSource))
if err != nil {
return errors.Wrapf(err, "failed to parse archetype template: %s", err)
return fmt.Errorf("failed to parse archetype template: %s: %w", err, err)
}
result, err := executeToString(ps.s.Tmpl(), templ, d)
if err != nil {
return errors.Wrapf(err, "failed to execute archetype template: %s", err)
return fmt.Errorf("failed to execute archetype template: %s: %w", err, err)
}
_, err = io.WriteString(w, f.shortcodeReplacerPost.Replace(result))

View File

@@ -23,7 +23,6 @@ import (
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/resources/page"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/hugofs/files"
@@ -207,7 +206,7 @@ func (b *cmInsertKeyBuilder) WithFile(fi hugofs.FileMetaInfo) *cmInsertKeyBuilde
p, k := b.getBundle(p)
if k == "" {
b.err = errors.Errorf("no bundle header found for %q", bundlePath)
b.err = fmt.Errorf("no bundle header found for %q", bundlePath)
return b
}

View File

@@ -35,7 +35,6 @@ import (
"github.com/spf13/cast"
"github.com/gohugoio/hugo/common/para"
"github.com/pkg/errors"
)
func newPageMaps(h *HugoSites) *pageMaps {
@@ -131,13 +130,13 @@ func (m *pageMap) newPageFromContentNode(n *contentNode, parentBucket *pagesMapB
gi, err := s.h.gitInfoForPage(ps)
if err != nil {
return nil, errors.Wrap(err, "failed to load Git data")
return nil, fmt.Errorf("failed to load Git data: %w", err)
}
ps.gitInfo = gi
owners, err := s.h.codeownersForPage(ps)
if err != nil {
return nil, errors.Wrap(err, "failed to load CODEOWNERS")
return nil, fmt.Errorf("failed to load CODEOWNERS: %w", err)
}
ps.codeowners = owners
@@ -282,7 +281,7 @@ func (m *pageMap) createSiteTaxonomies() error {
} else {
taxonomy := m.s.taxonomies[viewName.plural]
if taxonomy == nil {
walkErr = errors.Errorf("missing taxonomy: %s", viewName.plural)
walkErr = fmt.Errorf("missing taxonomy: %s", viewName.plural)
return true
}
m.taxonomyEntries.WalkPrefix(s, func(ss string, v any) bool {

View File

@@ -14,12 +14,11 @@
package hugolib
import (
"fmt"
"strings"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/afero"
@@ -41,7 +40,7 @@ type fileInfo struct {
func (fi *fileInfo) Open() (afero.File, error) {
f, err := fi.FileInfo().Meta().Open()
if err != nil {
err = errors.Wrap(err, "fileInfo")
err = fmt.Errorf("fileInfo: %w", err)
}
return f, err

View File

@@ -35,8 +35,6 @@ import (
"github.com/gohugoio/hugo/hugofs/files"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/modules"
hpaths "github.com/gohugoio/hugo/common/paths"
@@ -176,7 +174,7 @@ func (b *BaseFs) AbsProjectContentDir(filename string) (string, string, error) {
}
return "", "", errors.Errorf("could not determine content directory for %q", filename)
return "", "", fmt.Errorf("could not determine content directory for %q", filename)
}
// ResolveJSConfigFile resolves the JS-related config file to a absolute
@@ -468,7 +466,7 @@ func NewBase(p *paths.Paths, logger loggers.Logger, options ...func(*BaseFs) err
builder := newSourceFilesystemsBuilder(p, logger, b)
sourceFilesystems, err := builder.Build()
if err != nil {
return nil, errors.Wrap(err, "build filesystems")
return nil, fmt.Errorf("build filesystems: %w", err)
}
b.SourceFilesystems = sourceFilesystems
@@ -502,7 +500,7 @@ func (b *sourceFilesystemsBuilder) Build() (*SourceFilesystems, error) {
if b.theBigFs == nil {
theBigFs, err := b.createMainOverlayFs(b.p)
if err != nil {
return nil, errors.Wrap(err, "create main fs")
return nil, fmt.Errorf("create main fs: %w", err)
}
b.theBigFs = theBigFs
@@ -544,7 +542,7 @@ func (b *sourceFilesystemsBuilder) Build() (*SourceFilesystems, error) {
contentFs, err := hugofs.NewLanguageFs(b.p.LanguagesDefaultFirst.AsOrdinalSet(), contentBfs)
if err != nil {
return nil, errors.Wrap(err, "create content filesystem")
return nil, fmt.Errorf("create content filesystem: %w", err)
}
b.result.Content = b.newSourceFilesystem(files.ComponentFolderContent, contentFs, contentDirs)

View File

@@ -15,6 +15,7 @@ package hugolib
import (
"context"
"fmt"
"io"
"path/filepath"
"sort"
@@ -33,9 +34,10 @@ import (
"github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/parser/metadecoders"
"errors"
"github.com/gohugoio/hugo/common/para"
"github.com/gohugoio/hugo/hugofs"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/source"
@@ -194,7 +196,7 @@ func (h *hugoSitesInit) Reset() {
func (h *HugoSites) Data() map[string]any {
if _, err := h.init.data.Do(); err != nil {
h.SendError(errors.Wrap(err, "failed to load data"))
h.SendError(fmt.Errorf("failed to load data: %w", err))
return nil
}
return h.data
@@ -242,7 +244,7 @@ func (h *HugoSites) pickOneAndLogTheRest(errors []error) error {
for j, err := range errors {
// If this is in server mode, we want to return an error to the client
// with a file context, if possible.
if herrors.UnwrapErrorWithFileContext(err) != nil {
if herrors.UnwrapFileError(err) != nil {
i = j
break
}
@@ -327,7 +329,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
langConfig, err := newMultiLingualFromSites(cfg.Cfg, sites...)
if err != nil {
return nil, errors.Wrap(err, "failed to create language config")
return nil, fmt.Errorf("failed to create language config: %w", err)
}
var contentChangeTracker *contentChangeMap
@@ -365,7 +367,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
h.init.data.Add(func() (any, error) {
err := h.loadData(h.PathSpec.BaseFs.Data.Dirs)
if err != nil {
return nil, errors.Wrap(err, "failed to load data")
return nil, fmt.Errorf("failed to load data: %w", err)
}
return nil, nil
})
@@ -391,7 +393,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
h.init.gitInfo.Add(func() (any, error) {
err := h.loadGitInfo()
if err != nil {
return nil, errors.Wrap(err, "failed to load Git info")
return nil, fmt.Errorf("failed to load Git info: %w", err)
}
return nil, nil
})
@@ -402,7 +404,7 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
var l configLoader
if err := l.applyDeps(cfg, sites...); err != nil {
initErr = errors.Wrap(err, "add site dependencies")
initErr = fmt.Errorf("add site dependencies: %w", err)
}
h.Deps = sites[0].Deps
@@ -485,7 +487,7 @@ func (l configLoader) applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
siteConfig, err := l.loadSiteConfig(s.language)
if err != nil {
return errors.Wrap(err, "load site config")
return fmt.Errorf("load site config: %w", err)
}
s.siteConfigConfig = siteConfig
@@ -516,17 +518,17 @@ func (l configLoader) applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
var err error
d, err = deps.New(cfg)
if err != nil {
return errors.Wrap(err, "create deps")
return fmt.Errorf("create deps: %w", err)
}
d.OutputFormatsConfig = s.outputFormatsConfig
if err := onCreated(d); err != nil {
return errors.Wrap(err, "on created")
return fmt.Errorf("on created: %w", err)
}
if err = d.LoadResources(); err != nil {
return errors.Wrap(err, "load resources")
return fmt.Errorf("load resources: %w", err)
}
} else {
@@ -548,7 +550,7 @@ func NewHugoSites(cfg deps.DepsCfg) (*HugoSites, error) {
}
sites, err := createSitesFromConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "from config")
return nil, fmt.Errorf("from config: %w", err)
}
return newHugoSites(cfg, sites...)
}
@@ -882,7 +884,7 @@ func (h *HugoSites) handleDataFile(r source.File) error {
f, err := r.FileInfo().Meta().Open()
if err != nil {
return errors.Wrapf(err, "data: failed to open %q:", r.LogicalName())
return fmt.Errorf("data: failed to open %q: %w", r.LogicalName(), err)
}
defer f.Close()
@@ -960,23 +962,16 @@ func (h *HugoSites) errWithFileContext(err error, f source.File) error {
if !ok {
return err
}
realFilename := fim.Meta().Filename
err, _ = herrors.WithFileContextForFile(
err,
realFilename,
realFilename,
h.SourceSpec.Fs.Source,
herrors.SimpleLineMatcher)
return herrors.NewFileErrorFromFile(err, realFilename, realFilename, h.SourceSpec.Fs.Source, herrors.SimpleLineMatcher)
return err
}
func (h *HugoSites) readData(f source.File) (any, error) {
file, err := f.FileInfo().Meta().Open()
if err != nil {
return nil, errors.Wrap(err, "readData: failed to open data file")
return nil, fmt.Errorf("readData: failed to open data file: %w", err)
}
defer file.Close()
content := helpers.ReaderToBytes(file)

View File

@@ -35,7 +35,7 @@ import (
"github.com/gohugoio/hugo/output"
"github.com/pkg/errors"
"errors"
"github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/helpers"
@@ -50,7 +50,7 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
if !config.NoBuildLock {
unlock, err := h.BaseFs.LockBuild()
if err != nil {
return errors.Wrap(err, "failed to acquire a build lock")
return fmt.Errorf("failed to acquire a build lock: %w", err)
}
defer unlock()
}
@@ -99,11 +99,11 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
if len(events) > 0 {
// Rebuild
if err := h.initRebuild(conf); err != nil {
return errors.Wrap(err, "initRebuild")
return fmt.Errorf("initRebuild: %w", err)
}
} else {
if err := h.initSites(conf); err != nil {
return errors.Wrap(err, "initSites")
return fmt.Errorf("initSites: %w", err)
}
}
@@ -117,7 +117,7 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
}
trace.WithRegion(ctx, "process", f)
if err != nil {
return errors.Wrap(err, "process")
return fmt.Errorf("process: %w", err)
}
f = func() {

View File

@@ -2,6 +2,7 @@ package hugolib
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
@@ -17,14 +18,15 @@ type testSiteBuildErrorAsserter struct {
c *qt.C
}
func (t testSiteBuildErrorAsserter) getFileError(err error) *herrors.ErrorWithFileContext {
func (t testSiteBuildErrorAsserter) getFileError(err error) herrors.FileError {
t.c.Assert(err, qt.Not(qt.IsNil), qt.Commentf(t.name))
ferr := herrors.UnwrapErrorWithFileContext(err)
t.c.Assert(ferr, qt.Not(qt.IsNil))
return ferr
fe := herrors.UnwrapFileError(err)
t.c.Assert(fe, qt.Not(qt.IsNil))
return fe
}
func (t testSiteBuildErrorAsserter) assertLineNumber(lineNumber int, err error) {
t.c.Helper()
fe := t.getFileError(err)
t.c.Assert(fe.Position().LineNumber, qt.Equals, lineNumber, qt.Commentf(err.Error()))
}
@@ -87,7 +89,6 @@ func TestSiteBuildErrors(t *testing.T) {
fe := a.getFileError(err)
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/foo/single.html:5:1\": parse failed: template: foo/single.html:5: unexpected \"}\" in operand", fe.Error())
},
},
@@ -101,7 +102,6 @@ func TestSiteBuildErrors(t *testing.T) {
fe := a.getFileError(err)
a.c.Assert(fe.Position().LineNumber, qt.Equals, 5)
a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 14)
a.c.Assert(fe.ChromaLexer, qt.Equals, "go-html-template")
a.assertErrorMessage("\"layouts/_default/single.html:5:14\": execute of template failed", fe.Error())
},
},
@@ -115,7 +115,6 @@ func TestSiteBuildErrors(t *testing.T) {
fe := a.getFileError(err)
a.c.Assert(fe.Position().LineNumber, qt.Equals, 5)
a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 14)
a.c.Assert(fe.ChromaLexer, qt.Equals, "go-html-template")
a.assertErrorMessage("\"layouts/_default/single.html:5:14\": execute of template failed", fe.Error())
},
},
@@ -130,18 +129,17 @@ func TestSiteBuildErrors(t *testing.T) {
},
},
{
name: "Shortode execute failed",
name: "Shortcode execute failed",
fileType: shortcode,
fileFixer: func(content string) string {
return strings.Replace(content, ".Title", ".Titles", 1)
},
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
fe := a.getFileError(err)
a.c.Assert(fe.Position().LineNumber, qt.Equals, 7)
a.c.Assert(fe.ChromaLexer, qt.Equals, "md")
// Make sure that it contains both the content file and template
a.assertErrorMessage(`content/myyaml.md:7:10": failed to render shortcode "sc"`, fe.Error())
a.assertErrorMessage(`shortcodes/sc.html:4:22: executing "shortcodes/sc.html" at <.Page.Titles>: can't evaluate`, fe.Error())
a.assertErrorMessage(`"content/myyaml.md:7:10": failed to render shortcode "sc": failed to process shortcode: "layouts/shortcodes/sc.html:4:22": execute of template failed: template: shortcodes/sc.html:4:22: executing "shortcodes/sc.html" at <.Page.Titles>: can't evaluate field Titles in type page.Page`, fe.Error())
a.c.Assert(fe.Position().LineNumber, qt.Equals, 7)
},
},
{
@@ -154,7 +152,6 @@ func TestSiteBuildErrors(t *testing.T) {
fe := a.getFileError(err)
a.c.Assert(fe.Position().LineNumber, qt.Equals, 7)
a.c.Assert(fe.Position().ColumnNumber, qt.Equals, 10)
a.c.Assert(fe.ChromaLexer, qt.Equals, "md")
a.assertErrorMessage(`"content/myyaml.md:7:10": failed to extract shortcode: template for shortcode "nono" not found`, fe.Error())
},
},
@@ -162,10 +159,14 @@ func TestSiteBuildErrors(t *testing.T) {
name: "Invalid YAML front matter",
fileType: yamlcontent,
fileFixer: func(content string) string {
return strings.Replace(content, "title:", "title: %foo", 1)
return `---
title: "My YAML Content"
foo bar
---
`
},
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
a.assertLineNumber(2, err)
a.assertLineNumber(3, err)
},
},
{
@@ -177,7 +178,6 @@ func TestSiteBuildErrors(t *testing.T) {
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
fe := a.getFileError(err)
a.c.Assert(fe.Position().LineNumber, qt.Equals, 6)
a.c.Assert(fe.ErrorContext.ChromaLexer, qt.Equals, "toml")
},
},
{
@@ -188,9 +188,7 @@ func TestSiteBuildErrors(t *testing.T) {
},
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
fe := a.getFileError(err)
a.c.Assert(fe.Position().LineNumber, qt.Equals, 3)
a.c.Assert(fe.ErrorContext.ChromaLexer, qt.Equals, "json")
},
},
{
@@ -211,6 +209,9 @@ func TestSiteBuildErrors(t *testing.T) {
}
for _, test := range tests {
if test.name != "Invalid JSON front matter" {
continue
}
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
@@ -311,6 +312,77 @@ Some content.
}
})
}
}
// Issue 9852
func TestErrorMinify(t *testing.T) {
t.Parallel()
files := `
-- config.toml --
minify = true
-- layouts/index.html --
<body>
<script>=;</script>
</body>
`
b, err := NewIntegrationTestBuilder(
IntegrationTestConfig{
T: t,
TxtarString: files,
},
).BuildE()
fe := herrors.UnwrapFileError(err)
b.Assert(fe, qt.IsNotNil)
b.Assert(fe.Position().LineNumber, qt.Equals, 2)
b.Assert(fe.Position().ColumnNumber, qt.Equals, 9)
b.Assert(fe.Error(), qt.Contains, "unexpected = in expression on line 2 and column 9")
b.Assert(filepath.ToSlash(fe.Position().Filename), qt.Contains, "hugo-transform-error")
b.Assert(os.Remove(fe.Position().Filename), qt.IsNil)
}
func TestErrorNested(t *testing.T) {
t.Parallel()
files := `
-- config.toml --
-- layouts/index.html --
line 1
12{{ partial "foo.html" . }}
line 4
line 5
-- layouts/partials/foo.html --
line 1
line 2
123{{ .ThisDoesNotExist }}
line 4
`
b, err := NewIntegrationTestBuilder(
IntegrationTestConfig{
T: t,
TxtarString: files,
},
).BuildE()
b.Assert(err, qt.IsNotNil)
errors := herrors.UnwrapFileErrorsWithErrorContext(err)
b.Assert(errors, qt.HasLen, 2)
fmt.Println(errors[0])
b.Assert(errors[0].Position().LineNumber, qt.Equals, 2)
b.Assert(errors[0].Position().ColumnNumber, qt.Equals, 5)
b.Assert(errors[0].Error(), qt.Contains, filepath.FromSlash(`"/layouts/index.html:2:5": execute of template failed`))
b.Assert(errors[0].ErrorContext().Lines, qt.DeepEquals, []string{"line 1", "12{{ partial \"foo.html\" . }}", "line 4", "line 5"})
b.Assert(errors[1].Position().LineNumber, qt.Equals, 3)
b.Assert(errors[1].Position().ColumnNumber, qt.Equals, 6)
b.Assert(errors[1].ErrorContext().Lines, qt.DeepEquals, []string{"line 1", "line 2", "123{{ .ThisDoesNotExist }}", "line 4"})
}
// https://github.com/gohugoio/hugo/issues/5375

View File

@@ -169,8 +169,7 @@ func (s *IntegrationTestBuilder) destinationExists(filename string) bool {
}
func (s *IntegrationTestBuilder) AssertIsFileError(err error) {
var ferr *herrors.ErrorWithFileContext
s.Assert(err, qt.ErrorAs, &ferr)
s.Assert(err, qt.ErrorAs, new(herrors.FileError))
}
func (s *IntegrationTestBuilder) AssertRenderCountContent(count int) {

View File

@@ -39,8 +39,9 @@ import (
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/parser/metadecoders"
"errors"
"github.com/gohugoio/hugo/parser/pageparser"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/output"
@@ -482,7 +483,7 @@ func (p *pageState) renderResources() (err error) {
src, ok := r.(resource.Source)
if !ok {
err = errors.Errorf("Resource %T does not support resource.Source", src)
err = fmt.Errorf("Resource %T does not support resource.Source", src)
return
}
@@ -560,23 +561,37 @@ func (p *pageState) addDependency(dep identity.Provider) {
// wrapError adds some more context to the given error if possible/needed
func (p *pageState) wrapError(err error) error {
if _, ok := err.(*herrors.ErrorWithFileContext); ok {
// Preserve the first file context.
return err
}
var filename string
if !p.File().IsZero() {
filename = p.File().Filename()
if err == nil {
panic("wrapError with nil")
}
err, _ = herrors.WithFileContextForFile(
err,
filename,
filename,
p.s.SourceSpec.Fs.Source,
herrors.SimpleLineMatcher)
if p.File().IsZero() {
// No more details to add.
return fmt.Errorf("%q: %w", p.Pathc(), err)
}
filename := p.File().Filename()
if ferr := herrors.UnwrapFileError(err); ferr != nil {
errfilename := ferr.Position().Filename
if ferr.ErrorContext() != nil || errfilename == "" || !(errfilename == pageFileErrorName || filepath.IsAbs(errfilename)) {
return err
}
if filepath.IsAbs(errfilename) {
filename = errfilename
}
f, ferr2 := p.s.SourceSpec.Fs.Source.Open(filename)
if ferr2 != nil {
return err
}
defer f.Close()
pos := ferr.Position()
pos.Filename = filename
return ferr.UpdatePosition(pos).UpdateContent(f, herrors.SimpleLineMatcher)
}
return herrors.NewFileErrorFromFile(err, filename, filename, p.s.SourceSpec.Fs.Source, herrors.SimpleLineMatcher)
return err
}
func (p *pageState) getContentConverter() converter.Converter {
@@ -606,6 +621,9 @@ func (p *pageState) mapContent(bucket *pagesMapBucket, meta *pageMeta) error {
iter := p.source.parsed.Iterator()
fail := func(err error, i pageparser.Item) error {
if fe, ok := err.(herrors.FileError); ok {
return fe
}
return p.parseError(err, iter.Input(), i.Pos)
}
@@ -626,7 +644,17 @@ Loop:
m, err := metadecoders.Default.UnmarshalToMap(it.Val, f)
if err != nil {
if fe, ok := err.(herrors.FileError); ok {
return herrors.ToFileErrorWithOffset(fe, iter.LineNumber()-1)
// Offset the starting position of front matter.
pos := fe.Position()
offset := iter.LineNumber() - 1
if f == metadecoders.YAML {
offset -= 1
}
pos.LineNumber += offset
fe.UpdatePosition(pos)
return fe
} else {
return err
}
@@ -682,7 +710,7 @@ Loop:
currShortcode, err := s.extractShortcode(ordinal, 0, iter)
if err != nil {
return fail(errors.Wrap(err, "failed to extract shortcode"), it)
return fail(err, it)
}
currShortcode.pos = it.Pos
@@ -715,7 +743,7 @@ Loop:
case it.IsEOF():
break Loop
case it.IsError():
err := fail(errors.WithStack(errors.New(it.ValStr())), it)
err := fail(errors.New(it.ValStr()), it)
currShortcode.err = err
return err
@@ -738,17 +766,17 @@ Loop:
}
func (p *pageState) errorf(err error, format string, a ...any) error {
if herrors.UnwrapErrorWithFileContext(err) != nil {
if herrors.UnwrapFileError(err) != nil {
// More isn't always better.
return err
}
args := append([]any{p.Language().Lang, p.pathOrTitle()}, a...)
format = "[%s] page %q: " + format
args = append(args, err)
format = "[%s] page %q: " + format + ": %w"
if err == nil {
errors.Errorf(format, args...)
return fmt.Errorf(format, args...)
}
return errors.Wrapf(err, format, args...)
return fmt.Errorf(format, args...)
}
func (p *pageState) outputFormat() (f output.Format) {
@@ -759,12 +787,8 @@ func (p *pageState) outputFormat() (f output.Format) {
}
func (p *pageState) parseError(err error, input []byte, offset int) error {
if herrors.UnwrapFileError(err) != nil {
// Use the most specific location.
return err
}
pos := p.posFromInput(input, offset)
return herrors.NewFileError("md", -1, pos.LineNumber, pos.ColumnNumber, err)
return herrors.NewFileError("page.md", err).UpdatePosition(pos)
}
func (p *pageState) pathOrTitle() string {

View File

@@ -34,7 +34,6 @@ import (
"github.com/gohugoio/hugo/related"
"github.com/gohugoio/hugo/source"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config"
@@ -765,7 +764,7 @@ func (p *pageMeta) newContentConverter(ps *pageState, markup string, renderingCo
}
cp := p.s.ContentSpec.Converters.Get(markup)
if cp == nil {
return converter.NopConverter, errors.Errorf("no content renderer found for markup %q", p.markup)
return converter.NopConverter, fmt.Errorf("no content renderer found for markup %q", p.markup)
}
var id string

View File

@@ -23,11 +23,12 @@ import (
"sync"
"unicode/utf8"
"errors"
"github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/common/types/hstring"
"github.com/gohugoio/hugo/identity"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/spf13/cast"
"github.com/gohugoio/hugo/markup/converter/hooks"
@@ -348,7 +349,7 @@ func (p *pageContentOutput) RenderString(args ...any) (template.HTML, error) {
}
if err := mapstructure.WeakDecode(m, &opts); err != nil {
return "", errors.WithMessage(err, "failed to decode options")
return "", fmt.Errorf("failed to decode options: %w", err)
}
}
@@ -416,7 +417,7 @@ func (p *pageContentOutput) Render(layout ...string) (template.HTML, error) {
// Make sure to send the *pageState and not the *pageContentOutput to the template.
res, err := executeToString(p.p.s.Tmpl(), templ, p.p)
if err != nil {
return "", p.p.wrapError(errors.Wrapf(err, "failed to execute template %q v", layout))
return "", p.p.wrapError(fmt.Errorf("failed to execute template %q v: %w", layout, err))
}
return template.HTML(res), nil
}

View File

@@ -19,7 +19,6 @@ import (
"github.com/gohugoio/hugo/common/text"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
func newPageRef(p *pageState) pageRef {
@@ -77,7 +76,7 @@ func (p pageRef) decodeRefArgs(args map[string]any) (refArgs, *Site, error) {
func (p pageRef) ref(argsm map[string]any, source any) (string, error) {
args, s, err := p.decodeRefArgs(argsm)
if err != nil {
return "", errors.Wrap(err, "invalid arguments to Ref")
return "", fmt.Errorf("invalid arguments to Ref: %w", err)
}
if s == nil {
@@ -94,7 +93,7 @@ func (p pageRef) ref(argsm map[string]any, source any) (string, error) {
func (p pageRef) relRef(argsm map[string]any, source any) (string, error) {
args, s, err := p.decodeRefArgs(argsm)
if err != nil {
return "", errors.Wrap(err, "invalid arguments to Ref")
return "", fmt.Errorf("invalid arguments to Ref: %w", err)
}
if s == nil {

View File

@@ -14,7 +14,7 @@
package hugolib
import (
"github.com/pkg/errors"
"fmt"
"github.com/gohugoio/hugo/resources/page"
)
@@ -36,7 +36,7 @@ func unwrapPage(in any) (page.Page, error) {
case nil:
return nil, nil
default:
return nil, errors.Errorf("unwrapPage: %T not supported", in)
return nil, fmt.Errorf("unwrapPage: %T not supported", in)
}
}

View File

@@ -22,7 +22,6 @@ import (
"github.com/gohugoio/hugo/source"
"github.com/gohugoio/hugo/hugofs/files"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"github.com/gohugoio/hugo/common/herrors"
@@ -156,7 +155,7 @@ func (p *sitePagesProcessor) copyFile(fim hugofs.FileMetaInfo) error {
meta := fim.Meta()
f, err := meta.Open()
if err != nil {
return errors.Wrap(err, "copyFile: failed to open")
return fmt.Errorf("copyFile: failed to open: %w", err)
}
s := p.m.s

View File

@@ -23,7 +23,6 @@ import (
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/modules"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/hugofs"
)
@@ -83,7 +82,7 @@ func New(fs *hugofs.Fs, cfg config.Provider) (*Paths, error) {
baseURLstr := cfg.GetString("baseURL")
baseURL, err := newBaseURLFromString(baseURLstr)
if err != nil {
return nil, errors.Wrapf(err, "Failed to create baseURL from %q:", baseURLstr)
return nil, fmt.Errorf("Failed to create baseURL from %q:: %w", baseURLstr, err)
}
contentDir := filepath.Clean(cfg.GetString("contentDir"))

View File

@@ -27,8 +27,9 @@ import (
"github.com/gohugoio/hugo/helpers"
"errors"
"github.com/gohugoio/hugo/common/herrors"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/parser/pageparser"
"github.com/gohugoio/hugo/resources/page"
@@ -269,6 +270,7 @@ const (
innerNewlineRegexp = "\n"
innerCleanupRegexp = `\A<p>(.*)</p>\n\z`
innerCleanupExpand = "$1"
pageFileErrorName = "page.md"
)
func renderShortcode(
@@ -297,9 +299,10 @@ func renderShortcode(
var err error
tmpl, err = s.TextTmpl().Parse(templName, templStr)
if err != nil {
fe := herrors.ToFileError("html", err)
l1, l2 := p.posOffset(sc.pos).LineNumber, fe.Position().LineNumber
fe = herrors.ToFileErrorWithLineNumber(fe, l1+l2-1)
fe := herrors.NewFileError(pageFileErrorName, err)
pos := fe.Position()
pos.LineNumber += p.posOffset(sc.pos).LineNumber
fe = fe.UpdatePosition(pos)
return "", false, p.wrapError(fe)
}
@@ -308,7 +311,7 @@ func renderShortcode(
var found bool
tmpl, found = s.TextTmpl().Lookup(templName)
if !found {
return "", false, errors.Errorf("no earlier definition of shortcode %q found", sc.name)
return "", false, fmt.Errorf("no earlier definition of shortcode %q found", sc.name)
}
}
} else {
@@ -389,9 +392,10 @@ func renderShortcode(
result, err := renderShortcodeWithPage(s.Tmpl(), tmpl, data)
if err != nil && sc.isInline {
fe := herrors.ToFileError("html", err)
l1, l2 := p.posFromPage(sc.pos).LineNumber, fe.Position().LineNumber
fe = herrors.ToFileErrorWithLineNumber(fe, l1+l2-1)
fe := herrors.NewFileError("shortcode.md", err)
pos := fe.Position()
pos.LineNumber += p.posOffset(sc.pos).LineNumber
fe = fe.UpdatePosition(pos)
return "", false, fe
}
@@ -415,7 +419,7 @@ func (s *shortcodeHandler) renderShortcodesForPage(p *pageState, f output.Format
for _, v := range s.shortcodes {
s, more, err := renderShortcode(0, s.s, tplVariants, v, nil, p)
if err != nil {
err = p.parseError(errors.Wrapf(err, "failed to render shortcode %q", v.name), p.source.parsed.Input(), v.pos)
err = p.parseError(fmt.Errorf("failed to render shortcode %q: %w", v.name, err), p.source.parsed.Input(), v.pos)
return nil, false, err
}
hasVariants = hasVariants || more
@@ -447,9 +451,10 @@ func (s *shortcodeHandler) extractShortcode(ordinal, level int, pt *pageparser.I
cnt := 0
nestedOrdinal := 0
nextLevel := level + 1
const errorPrefix = "failed to extract shortcode"
fail := func(err error, i pageparser.Item) error {
return s.parseError(err, pt.Input(), i.Pos)
return s.parseError(fmt.Errorf("%s: %w", errorPrefix, err), pt.Input(), i.Pos)
}
Loop:
@@ -508,7 +513,7 @@ Loop:
// return that error, more specific
continue
}
return sc, fail(errors.Errorf("shortcode %q has no .Inner, yet a closing tag was provided", next.Val), next)
return sc, fail(fmt.Errorf("shortcode %q has no .Inner, yet a closing tag was provided", next.Val), next)
}
}
if next.IsRightShortcodeDelim() {
@@ -538,7 +543,7 @@ Loop:
// Used to check if the template expects inner content.
templs := s.s.Tmpl().LookupVariants(sc.name)
if templs == nil {
return nil, errors.Errorf("template for shortcode %q not found", sc.name)
return nil, fmt.Errorf("%s: template for shortcode %q not found", errorPrefix, sc.name)
}
sc.info = templs[0].(tpl.Info)
@@ -639,7 +644,7 @@ func renderShortcodeWithPage(h tpl.TemplateHandler, tmpl tpl.Template, data *Sho
err := h.Execute(tmpl, buffer, data)
if err != nil {
return "", errors.Wrap(err, "failed to process shortcode")
return "", fmt.Errorf("failed to process shortcode: %w", err)
}
return buffer.String(), nil
}

View File

@@ -1340,7 +1340,7 @@ func TestShortcodeNoInner(t *testing.T) {
b := newTestSitesBuilder(t)
b.WithContent("page.md", `---
b.WithContent("mypage.md", `---
title: "No Inner!"
---
{{< noinner >}}{{< /noinner >}}
@@ -1350,7 +1350,7 @@ title: "No Inner!"
"layouts/shortcodes/noinner.html", `No inner here.`)
err := b.BuildE(BuildCfg{})
b.Assert(err.Error(), qt.Contains, `failed to extract shortcode: shortcode "noinner" has no .Inner, yet a closing tag was provided`)
b.Assert(err.Error(), qt.Contains, filepath.FromSlash(`"content/mypage.md:4:21": failed to extract shortcode: shortcode "noinner" has no .Inner, yet a closing tag was provided`))
}
func TestShortcodeStableOutputFormatTemplates(t *testing.T) {

View File

@@ -59,8 +59,6 @@ import (
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/publisher"
"github.com/pkg/errors"
_errors "github.com/pkg/errors"
"github.com/gohugoio/hugo/langs"
@@ -508,7 +506,7 @@ But this also means that your site configuration may not do what you expect. If
if cfg.Language.IsSet("related") {
relatedContentConfig, err = related.DecodeConfig(cfg.Language.GetParams("related"))
if err != nil {
return nil, errors.Wrap(err, "failed to decode related config")
return nil, fmt.Errorf("failed to decode related config: %w", err)
}
} else {
relatedContentConfig = related.DefaultConfig
@@ -546,7 +544,7 @@ But this also means that your site configuration may not do what you expect. If
var err error
cascade, err := page.DecodeCascade(cfg.Language.Get("cascade"))
if err != nil {
return nil, errors.Errorf("failed to decode cascade config: %s", err)
return nil, fmt.Errorf("failed to decode cascade config: %s", err)
}
siteBucket = &pagesMapBucket{
@@ -1211,11 +1209,11 @@ func (s *Site) processPartial(config *BuildCfg, init func(config *BuildCfg) erro
func (s *Site) process(config BuildCfg) (err error) {
if err = s.initialize(); err != nil {
err = errors.Wrap(err, "initialize")
err = fmt.Errorf("initialize: %w", err)
return
}
if err = s.readAndProcessContent(config); err != nil {
err = errors.Wrap(err, "readAndProcessContent")
err = fmt.Errorf("readAndProcessContent: %w", err)
return
}
return err
@@ -1534,7 +1532,7 @@ func (s *Site) assembleMenus() {
for name, me := range p.pageMenus.menus() {
if _, ok := flat[twoD{name, me.KeyName()}]; ok {
err := p.wrapError(errors.Errorf("duplicate menu entry with identifier %q in menu %q", me.KeyName(), name))
err := p.wrapError(fmt.Errorf("duplicate menu entry with identifier %q in menu %q", me.KeyName(), name))
s.Log.Warnln(err)
continue
}
@@ -1819,7 +1817,7 @@ func (s *Site) renderForTemplate(name, outputFormat string, d any, w io.Writer,
}
if err = s.Tmpl().Execute(templ, w, d); err != nil {
return _errors.Wrapf(err, "render of %q failed", name)
return fmt.Errorf("render of %q failed: %w", name, err)
}
return
}

View File

@@ -23,8 +23,9 @@ import (
"github.com/gohugoio/hugo/config"
"errors"
"github.com/gohugoio/hugo/output"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/resources/page"
"github.com/gohugoio/hugo/resources/page/pagemeta"
@@ -95,7 +96,7 @@ func (s *Site) renderPages(ctx *siteRenderContext) error {
err := <-errs
if err != nil {
return errors.Wrap(err, "failed to render pages")
return fmt.Errorf("failed to render pages: %w", err)
}
return nil
}

View File

@@ -28,10 +28,8 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/gohugoio/hugo/parser"
"github.com/pkg/errors"
"github.com/fsnotify/fsnotify"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hexec"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/config"
@@ -471,7 +469,6 @@ func (s *sitesBuilder) writeFilePairs(folder string, files []filenameContent) *s
func (s *sitesBuilder) CreateSites() *sitesBuilder {
if err := s.CreateSitesE(); err != nil {
herrors.PrintStackTraceFromErr(err)
s.Fatalf("Failed to create sites: %s", err)
}
@@ -517,7 +514,7 @@ func (s *sitesBuilder) CreateSitesE() error {
"i18n",
} {
if err := os.MkdirAll(filepath.Join(s.workingDir, dir), 0777); err != nil {
return errors.Wrapf(err, "failed to create %q", dir)
return fmt.Errorf("failed to create %q: %w", dir, err)
}
}
}
@@ -536,7 +533,7 @@ func (s *sitesBuilder) CreateSitesE() error {
}
if err := s.LoadConfig(); err != nil {
return errors.Wrap(err, "failed to load config")
return fmt.Errorf("failed to load config: %w", err)
}
s.Fs.PublishDir = hugofs.NewCreateCountingFs(s.Fs.PublishDir)
@@ -549,7 +546,7 @@ func (s *sitesBuilder) CreateSitesE() error {
sites, err := NewHugoSites(depsCfg)
if err != nil {
return errors.Wrap(err, "failed to create sites")
return fmt.Errorf("failed to create sites: %w", err)
}
s.H = sites
@@ -612,7 +609,6 @@ func (s *sitesBuilder) build(cfg BuildCfg, shouldFail bool) *sitesBuilder {
}
}
if err != nil && !shouldFail {
herrors.PrintStackTraceFromErr(err)
s.Fatalf("Build failed: %s", err)
} else if err == nil && shouldFail {
s.Fatalf("Expected error")