]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Improve error messages, esp. when the server is running
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 2 May 2022 14:07:52 +0000 (16:07 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 6 May 2022 17:43:22 +0000 (19:43 +0200)
* 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

109 files changed:
cache/filecache/filecache_config.go
cache/filecache/filecache_pruner.go
commands/commandeer.go
commands/convert.go
commands/hugo.go
commands/new_site.go
commands/server.go
commands/server_errors.go
common/herrors/error_locator.go
common/herrors/error_locator_test.go
common/herrors/errors.go
common/herrors/file_error.go
common/herrors/file_error_test.go
common/herrors/line_number_extractors.go
common/hugio/copy.go
config/commonConfig.go
config/configLoader.go
create/content.go
deploy/deploy.go
deploy/deployConfig.go
deps/deps.go
helpers/path.go
hugofs/decorators.go
hugofs/fileinfo.go
hugofs/rootmapping_fs.go
hugofs/slice_fs.go
hugofs/walk.go
hugofs/walk_test.go
hugolib/config.go
hugolib/configdir_test.go
hugolib/content_factory.go
hugolib/content_map.go
hugolib/content_map_page.go
hugolib/fileInfo.go
hugolib/filesystems/basefs.go
hugolib/hugo_sites.go
hugolib/hugo_sites_build.go
hugolib/hugo_sites_build_errors_test.go
hugolib/integrationtest_builder.go
hugolib/page.go
hugolib/page__meta.go
hugolib/page__per_output.go
hugolib/page__ref.go
hugolib/page_unwrap.go
hugolib/pages_process.go
hugolib/paths/paths.go
hugolib/shortcode.go
hugolib/shortcode_test.go
hugolib/site.go
hugolib/site_render.go
hugolib/testhelpers_test.go
langs/config.go
langs/i18n/translationProvider.go
langs/language.go
lazy/init.go
markup/blackfriday/blackfriday_config/config.go
modules/client.go
modules/collect.go
modules/config.go
modules/npm/package_builder.go
navigation/menu.go
navigation/pagemenus.go
output/outputFormat.go
parser/metadecoders/decoder.go
parser/pageparser/pageparser.go
publisher/publisher.go
releaser/releaser.go
resources/image.go
resources/images/color.go
resources/images/config.go
resources/images/image.go
resources/page/page_generate/generate_page_wrappers.go
resources/page/page_matcher.go
resources/page/pages_related.go
resources/page/permalinks.go
resources/resource.go
resources/resource_factories/create/remote.go
resources/resource_metadata.go
resources/resource_transformers/babel/babel.go
resources/resource_transformers/integrity/integrity.go
resources/resource_transformers/js/build.go
resources/resource_transformers/js/options.go
resources/resource_transformers/postcss/postcss.go
resources/resource_transformers/templates/execute_as_template.go
resources/resource_transformers/tocss/dartsass/transform.go
resources/resource_transformers/tocss/scss/tocss.go
resources/transform.go
source/fileInfo.go
source/filesystem.go
tpl/collections/collections.go
tpl/collections/merge.go
tpl/collections/reflect_helpers.go
tpl/collections/symdiff.go
tpl/data/data.go
tpl/data/resources.go
tpl/images/images.go
tpl/internal/resourcehelpers/helpers.go
tpl/lang/lang.go
tpl/openapi/openapi3/openapi3.go
tpl/resources/resources.go
tpl/strings/strings.go
tpl/tplimpl/embedded/templates/server/error.html [new file with mode: 0644]
tpl/tplimpl/template.go
tpl/tplimpl/template_ast_transformers.go
tpl/tplimpl/template_errors.go
tpl/transform/remarshal.go
tpl/transform/unmarshal.go
tpl/urls/urls.go
transform/chain.go

index 816c6b8a6d9d8eab867123f8c7cfb07552e344ec..a82133ab7f9fdfa537999b1bc6159b8daa51c3e8 100644 (file)
@@ -14,6 +14,7 @@
 package filecache
 
 import (
+       "fmt"
        "path"
        "path/filepath"
        "strings"
@@ -25,8 +26,9 @@ import (
 
        "github.com/gohugoio/hugo/helpers"
 
+       "errors"
+
        "github.com/mitchellh/mapstructure"
-       "github.com/pkg/errors"
        "github.com/spf13/afero"
 )
 
@@ -153,7 +155,7 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
                }
 
                if err := decoder.Decode(v); err != nil {
-                       return nil, errors.Wrap(err, "failed to decode filecache config")
+                       return nil, fmt.Errorf("failed to decode filecache config: %w", err)
                }
 
                if cc.Dir == "" {
@@ -162,7 +164,7 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
 
                name := strings.ToLower(k)
                if !valid[name] {
-                       return nil, errors.Errorf("%q is not a valid cache name", name)
+                       return nil, fmt.Errorf("%q is not a valid cache name", name)
                }
 
                c[name] = cc
@@ -197,12 +199,12 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
 
                if !v.isResourceDir {
                        if isOsFs && !filepath.IsAbs(v.Dir) {
-                               return c, errors.Errorf("%q must resolve to an absolute directory", v.Dir)
+                               return c, fmt.Errorf("%q must resolve to an absolute directory", v.Dir)
                        }
 
                        // Avoid cache in root, e.g. / (Unix) or c:\ (Windows)
                        if len(strings.TrimPrefix(v.Dir, filepath.VolumeName(v.Dir))) == 1 {
-                               return c, errors.Errorf("%q is a root folder and not allowed as cache dir", v.Dir)
+                               return c, fmt.Errorf("%q is a root folder and not allowed as cache dir", v.Dir)
                        }
                }
 
@@ -242,5 +244,5 @@ func resolveDirPlaceholder(fs afero.Fs, cfg config.Provider, placeholder string)
                return filepath.Base(workingDir), false, nil
        }
 
-       return "", false, errors.Errorf("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)", placeholder)
+       return "", false, fmt.Errorf("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)", placeholder)
 }
index db18757015779ff95c75e698ee8b57ad294f1ad5..e5e5719725df72ece457709598df06a8dedef3aa 100644 (file)
 package filecache
 
 import (
+       "fmt"
        "io"
        "os"
 
        "github.com/gohugoio/hugo/hugofs"
 
-       "github.com/pkg/errors"
        "github.com/spf13/afero"
 )
 
@@ -39,7 +39,7 @@ func (c Caches) Prune() (int, error) {
                        if os.IsNotExist(err) {
                                continue
                        }
-                       return counter, errors.Wrapf(err, "failed to prune cache %q", k)
+                       return counter, fmt.Errorf("failed to prune cache %q: %w", k, err)
                }
 
        }
index c42de5d11a52741abd7b2cb9340a62d8dceb2188..5b192c1725033596d07237a94e90624136eebc64 100644 (file)
@@ -14,7 +14,6 @@
 package commands
 
 import (
-       "bytes"
        "errors"
        "io/ioutil"
        "net"
@@ -141,19 +140,11 @@ func (c *commandeer) getErrorWithContext() any {
 
        m := make(map[string]any)
 
-       m["Error"] = errors.New(removeErrorPrefixFromLog(c.logger.Errors()))
+       //xwm["Error"] = errors.New(cleanErrorLog(removeErrorPrefixFromLog(c.logger.Errors())))
+       m["Error"] = errors.New(cleanErrorLog(removeErrorPrefixFromLog(c.logger.Errors())))
        m["Version"] = hugo.BuildVersionString()
-
-       fe := herrors.UnwrapErrorWithFileContext(c.buildErr)
-       if fe != nil {
-               m["File"] = fe
-       }
-
-       if c.h.verbose {
-               var b bytes.Buffer
-               herrors.FprintStackTraceFromErr(&b, c.buildErr)
-               m["StackTrace"] = b.String()
-       }
+       ferrors := herrors.UnwrapFileErrorsWithErrorContext(c.buildErr)
+       m["Files"] = ferrors
 
        return m
 }
index d3cad2bd65cf28b0441c37e31b83c322ad16b422..1ec965a0b1883086a60b1ba909627f0471b167ce 100644 (file)
@@ -31,8 +31,6 @@ import (
        "github.com/gohugoio/hugo/parser"
        "github.com/gohugoio/hugo/parser/metadecoders"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/hugolib"
 
        "github.com/spf13/cobra"
@@ -193,7 +191,7 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
 
        fs := hugofs.Os
        if err := helpers.WriteToDisk(newFilename, &newContent, fs); err != nil {
-               return errors.Wrapf(err, "Failed to save file %q:", newFilename)
+               return fmt.Errorf("Failed to save file %q:: %w", newFilename, err)
        }
 
        return nil
index 9033fac90cb43d3f171346dd60208eee391b100f..6bd0605db65ddd52d26c4ba27c8bb002d9297cc3 100644 (file)
@@ -39,9 +39,6 @@ import (
 
        "github.com/gohugoio/hugo/resources/page"
 
-       "github.com/pkg/errors"
-
-       "github.com/gohugoio/hugo/common/herrors"
        "github.com/gohugoio/hugo/common/hugo"
        "github.com/gohugoio/hugo/common/loggers"
        "github.com/gohugoio/hugo/common/terminal"
@@ -300,14 +297,14 @@ func (c *commandeer) fullBuild(noBuildLock bool) error {
        copyStaticFunc := func() error {
                cnt, err := c.copyStatic()
                if err != nil {
-                       return errors.Wrap(err, "Error copying static files")
+                       return fmt.Errorf("Error copying static files: %w", err)
                }
                langCount = cnt
                return nil
        }
        buildSitesFunc := func() error {
                if err := c.buildSites(noBuildLock); err != nil {
-                       return errors.Wrap(err, "Error building site")
+                       return fmt.Errorf("Error building site: %w", err)
                }
                return nil
        }
@@ -354,10 +351,10 @@ func (c *commandeer) initCPUProfile() (func(), error) {
 
        f, err := os.Create(c.h.cpuprofile)
        if err != nil {
-               return nil, errors.Wrap(err, "failed to create CPU profile")
+               return nil, fmt.Errorf("failed to create CPU profile: %w", err)
        }
        if err := pprof.StartCPUProfile(f); err != nil {
-               return nil, errors.Wrap(err, "failed to start CPU profile")
+               return nil, fmt.Errorf("failed to start CPU profile: %w", err)
        }
        return func() {
                pprof.StopCPUProfile()
@@ -388,11 +385,11 @@ func (c *commandeer) initTraceProfile() (func(), error) {
 
        f, err := os.Create(c.h.traceprofile)
        if err != nil {
-               return nil, errors.Wrap(err, "failed to create trace file")
+               return nil, fmt.Errorf("failed to create trace file: %w", err)
        }
 
        if err := trace.Start(f); err != nil {
-               return nil, errors.Wrap(err, "failed to start trace")
+               return nil, fmt.Errorf("failed to start trace: %w", err)
        }
 
        return func() {
@@ -735,9 +732,7 @@ func (c *commandeer) handleBuildErr(err error, msg string) {
 
        c.logger.Errorln(msg + ":\n")
        c.logger.Errorln(helpers.FirstUpper(err.Error()))
-       if !c.h.quiet && c.h.verbose {
-               herrors.PrintStackTraceFromErr(err)
-       }
+
 }
 
 func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
index e49a6020284f7445b749dd224426bdaaa437b7fa..384c6365bee827b1fbde932beebf4695632b1c3e 100644 (file)
@@ -16,14 +16,13 @@ package commands
 import (
        "bytes"
        "errors"
+       "fmt"
        "path/filepath"
        "strings"
 
        "github.com/gohugoio/hugo/config"
        "github.com/gohugoio/hugo/parser/metadecoders"
 
-       _errors "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/create"
        "github.com/gohugoio/hugo/helpers"
        "github.com/gohugoio/hugo/hugofs"
@@ -94,7 +93,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
 
        for _, dir := range dirs {
                if err := fs.Source.MkdirAll(dir, 0777); err != nil {
-                       return _errors.Wrap(err, "Failed to create dir")
+                       return fmt.Errorf("Failed to create dir: %w", err)
                }
        }
 
index 145a889bb8c417d91736fdae9294b74975fc1c58..9857753368b6b06c4fa6a9a9493f26ac32c97ff8 100644 (file)
@@ -36,8 +36,6 @@ import (
        "github.com/gohugoio/hugo/common/paths"
        "golang.org/x/sync/errgroup"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/livereload"
 
        "github.com/gohugoio/hugo/config"
@@ -366,7 +364,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
        // We're only interested in the path
        u, err := url.Parse(baseURL)
        if err != nil {
-               return nil, nil, "", "", errors.Wrap(err, "Invalid baseURL")
+               return nil, nil, "", "", fmt.Errorf("Invalid baseURL: %w", err)
        }
 
        decorate := func(h http.Handler) http.Handler {
@@ -480,6 +478,21 @@ var logErrorRe = regexp.MustCompile(`(?s)ERROR \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{
 func removeErrorPrefixFromLog(content string) string {
        return logErrorRe.ReplaceAllLiteralString(content, "")
 }
+func cleanErrorLog(content string) string {
+       content = strings.ReplaceAll(content, "Rebuild failed:\n", "")
+       content = strings.ReplaceAll(content, "\n", "")
+       seen := make(map[string]bool)
+       parts := strings.Split(content, ": ")
+       keep := make([]string, 0, len(parts))
+       for _, part := range parts {
+               if seen[part] {
+                       continue
+               }
+               seen[part] = true
+               keep = append(keep, part)
+       }
+       return strings.Join(keep, ": ")
+}
 
 func (c *commandeer) serve(s *serverCmd) error {
        isMultiHost := c.hugo().IsMultihost()
@@ -500,17 +513,16 @@ func (c *commandeer) serve(s *serverCmd) error {
                roots = []string{""}
        }
 
-       templ, err := c.hugo().TextTmpl().Parse("__default_server_error", buildErrorTemplate)
-       if err != nil {
-               return err
-       }
-
        srv := &fileServer{
                baseURLs: baseURLs,
                roots:    roots,
                c:        c,
                s:        s,
                errorTemplate: func(ctx any) (io.Reader, error) {
+                       templ, found := c.hugo().Tmpl().Lookup("server/error.html")
+                       if !found {
+                               panic("template server/error.html not found")
+                       }
                        b := &bytes.Buffer{}
                        err := c.hugo().Tmpl().Execute(templ, b, ctx)
                        return b, err
@@ -627,7 +639,7 @@ func (sc *serverCmd) fixURL(cfg config.Provider, s string, port int) (string, er
                if strings.Contains(u.Host, ":") {
                        u.Host, _, err = net.SplitHostPort(u.Host)
                        if err != nil {
-                               return "", errors.Wrap(err, "Failed to split baseURL hostpost")
+                               return "", fmt.Errorf("Failed to split baseURL hostpost: %w", err)
                        }
                }
                u.Host += fmt.Sprintf(":%d", port)
index 0e3bc50deae854a6b94501596c78defd6ed8ef9e..edf6581560f89ac85721e047280e12e373a29efe 100644 (file)
@@ -22,67 +22,6 @@ import (
        "github.com/gohugoio/hugo/transform/livereloadinject"
 )
 
-var buildErrorTemplate = `<!doctype html>
-<html class="no-js" lang="">
-       <head>
-               <meta charset="utf-8">
-               <title>Hugo Server: Error</title>
-               <style type="text/css">
-               body {
-                       font-family: "Muli",avenir, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
-                       font-size: 16px;
-                       background-color: #2f1e2e;
-               }
-               main {
-                       margin: auto;
-                       width: 95%;
-                       padding: 1rem;
-               }               
-               .version {
-                       color: #ccc;
-                       padding: 1rem 0;
-               }
-               .stack {
-                       margin-top: 4rem;
-               }
-               pre {
-                       white-space: pre-wrap;      
-                       white-space: -moz-pre-wrap;  
-                       white-space: -pre-wrap;     
-                       white-space: -o-pre-wrap;    
-                       word-wrap: break-word;     
-               }
-               .highlight {
-                       overflow-x: auto;
-                       margin-bottom: 1rem;
-               }
-               a {
-                       color: #0594cb;
-                       text-decoration: none;
-               }
-               a:hover {
-                       color: #ccc;
-               }
-               </style>
-       </head>
-       <body>
-               <main>
-                       {{ highlight .Error "apl" "linenos=false,noclasses=true,style=paraiso-dark" }}
-                       {{ with .File }}
-                       {{ $params := printf "noclasses=true,style=paraiso-dark,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
-                       {{ $lexer := .ChromaLexer | default "go-html-template" }}
-                       {{  highlight (delimit .Lines "\n") $lexer $params }}
-                       {{ end }}
-                       {{ with .StackTrace }}
-                       {{ highlight . "apl" "noclasses=true,style=paraiso-dark" }}
-                       {{ end }}
-                       <p class="version">{{ .Version }}</p>
-                       <a href="">Reload Page</a>
-               </main>
-</body>
-</html>
-`
-
 func injectLiveReloadScript(src io.Reader, baseURL url.URL) string {
        var b bytes.Buffer
        chain := transform.Chain{livereloadinject.New(baseURL)}
index 2c0d215b163a4b5df20957072ed5653a92bde4cd..5d2c10c0403e39805f26dba10a7155e487a457b1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2018 The Hugo Authors. All rights reserved.
+// Copyright 2022 The Hugo Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -21,8 +21,6 @@ import (
        "strings"
 
        "github.com/gohugoio/hugo/common/text"
-
-       "github.com/spf13/afero"
 )
 
 // LineMatcher contains the elements used to match an error to a line
@@ -43,8 +41,6 @@ var SimpleLineMatcher = func(m LineMatcher) bool {
        return m.Position.LineNumber == m.LineNumber
 }
 
-var _ text.Positioner = ErrorContext{}
-
 // ErrorContext contains contextual information about an error. This will
 // typically be the lines surrounding some problem in a file.
 type ErrorContext struct {
@@ -56,125 +52,11 @@ type ErrorContext struct {
        // The position of the error in the Lines above. 0 based.
        LinesPos int
 
-       position text.Position
-
        // The lexer to use for syntax highlighting.
        // https://gohugo.io/content-management/syntax-highlighting/#list-of-chroma-highlighting-languages
        ChromaLexer string
 }
 
-// Position returns the text position of this error.
-func (e ErrorContext) Position() text.Position {
-       return e.position
-}
-
-var _ causer = (*ErrorWithFileContext)(nil)
-
-// ErrorWithFileContext is an error with some additional file context related
-// to that error.
-type ErrorWithFileContext struct {
-       cause error
-       ErrorContext
-}
-
-func (e *ErrorWithFileContext) Error() string {
-       pos := e.Position()
-       if pos.IsValid() {
-               return pos.String() + ": " + e.cause.Error()
-       }
-       return e.cause.Error()
-}
-
-func (e *ErrorWithFileContext) Cause() error {
-       return e.cause
-}
-
-// WithFileContextForFile will try to add a file context with lines matching the given matcher.
-// If no match could be found, the original error is returned with false as the second return value.
-func WithFileContextForFile(e error, realFilename, filename string, fs afero.Fs, matcher LineMatcherFn) (error, bool) {
-       f, err := fs.Open(filename)
-       if err != nil {
-               return e, false
-       }
-       defer f.Close()
-       return WithFileContext(e, realFilename, f, matcher)
-}
-
-// WithFileContextForFileDefault tries to add file context using the default line matcher.
-func WithFileContextForFileDefault(err error, filename string, fs afero.Fs) error {
-       err, _ = WithFileContextForFile(
-               err,
-               filename,
-               filename,
-               fs,
-               SimpleLineMatcher)
-       return err
-}
-
-// WithFileContextForFile will try to add a file context with lines matching the given matcher.
-// If no match could be found, the original error is returned with false as the second return value.
-func WithFileContext(e error, realFilename string, r io.Reader, matcher LineMatcherFn) (error, bool) {
-       if e == nil {
-               panic("error missing")
-       }
-       le := UnwrapFileError(e)
-
-       if le == nil {
-               var ok bool
-               if le, ok = ToFileError("", e).(FileError); !ok {
-                       return e, false
-               }
-       }
-
-       var errCtx ErrorContext
-
-       posle := le.Position()
-
-       if posle.Offset != -1 {
-               errCtx = locateError(r, le, func(m LineMatcher) bool {
-                       if posle.Offset >= m.Offset && posle.Offset < m.Offset+len(m.Line) {
-                               lno := posle.LineNumber - m.Position.LineNumber + m.LineNumber
-                               m.Position = text.Position{LineNumber: lno}
-                       }
-                       return matcher(m)
-               })
-       } else {
-               errCtx = locateError(r, le, matcher)
-       }
-
-       pos := &errCtx.position
-
-       if pos.LineNumber == -1 {
-               return e, false
-       }
-
-       pos.Filename = realFilename
-
-       if le.Type() != "" {
-               errCtx.ChromaLexer = chromaLexerFromType(le.Type())
-       } else {
-               errCtx.ChromaLexer = chromaLexerFromFilename(realFilename)
-       }
-
-       return &ErrorWithFileContext{cause: e, ErrorContext: errCtx}, true
-}
-
-// UnwrapErrorWithFileContext tries to unwrap an ErrorWithFileContext from err.
-// It returns nil if this is not possible.
-func UnwrapErrorWithFileContext(err error) *ErrorWithFileContext {
-       for err != nil {
-               switch v := err.(type) {
-               case *ErrorWithFileContext:
-                       return v
-               case causer:
-                       err = v.Cause()
-               default:
-                       return nil
-               }
-       }
-       return nil
-}
-
 func chromaLexerFromType(fileType string) string {
        switch fileType {
        case "html", "htm":
@@ -196,23 +78,23 @@ func chromaLexerFromFilename(filename string) string {
        return chromaLexerFromType(ext)
 }
 
-func locateErrorInString(src string, matcher LineMatcherFn) ErrorContext {
+func locateErrorInString(src string, matcher LineMatcherFn) (*ErrorContext, text.Position) {
        return locateError(strings.NewReader(src), &fileError{}, matcher)
 }
 
-func locateError(r io.Reader, le FileError, matches LineMatcherFn) ErrorContext {
+func locateError(r io.Reader, le FileError, matches LineMatcherFn) (*ErrorContext, text.Position) {
        if le == nil {
                panic("must provide an error")
        }
 
-       errCtx := ErrorContext{position: text.Position{LineNumber: -1, ColumnNumber: 1, Offset: -1}, LinesPos: -1}
+       errCtx := &ErrorContext{LinesPos: -1}
+       pos := text.Position{LineNumber: -1, ColumnNumber: 1, Offset: -1}
 
        b, err := ioutil.ReadAll(r)
        if err != nil {
-               return errCtx
+               return errCtx, pos
        }
 
-       pos := &errCtx.position
        lepos := le.Position()
 
        lines := strings.Split(string(b), "\n")
@@ -262,5 +144,5 @@ func locateError(r io.Reader, le FileError, matches LineMatcherFn) ErrorContext
 
        }
 
-       return errCtx
+       return errCtx, pos
 }
index 0cd5fb2d74af8e800a69b7edcf9c3a69fd3ae1f8..10b016fa82b41927ee9385d2e336bdec4cb78092 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2018 The Hugo Authors. All rights reserved.
+// Copyright 2022 The Hugo Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -38,44 +38,48 @@ LINE 7
 LINE 8
 `
 
-       location := locateErrorInString(lines, lineMatcher)
+       location, pos := locateErrorInString(lines, lineMatcher)
        c.Assert(location.Lines, qt.DeepEquals, []string{"LINE 3", "LINE 4", "This is THEONE", "LINE 6", "LINE 7"})
 
-       pos := location.Position()
        c.Assert(pos.LineNumber, qt.Equals, 5)
        c.Assert(location.LinesPos, qt.Equals, 2)
 
-       c.Assert(locateErrorInString(`This is THEONE`, lineMatcher).Lines, qt.DeepEquals, []string{"This is THEONE"})
+       locate := func(s string, m LineMatcherFn) *ErrorContext {
+               ctx, _ := locateErrorInString(s, m)
+               return ctx
+       }
+
+       c.Assert(locate(`This is THEONE`, lineMatcher).Lines, qt.DeepEquals, []string{"This is THEONE"})
 
-       location = locateErrorInString(`L1
+       location, pos = locateErrorInString(`L1
 This is THEONE
 L2
 `, lineMatcher)
-       c.Assert(location.Position().LineNumber, qt.Equals, 2)
+       c.Assert(pos.LineNumber, qt.Equals, 2)
        c.Assert(location.LinesPos, qt.Equals, 1)
        c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "This is THEONE", "L2", ""})
 
-       location = locateErrorInString(`This is THEONE
+       location = locate(`This is THEONE
 L2
 `, lineMatcher)
        c.Assert(location.LinesPos, qt.Equals, 0)
        c.Assert(location.Lines, qt.DeepEquals, []string{"This is THEONE", "L2", ""})
 
-       location = locateErrorInString(`L1
+       location = locate(`L1
 This THEONE
 `, lineMatcher)
        c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "This THEONE", ""})
        c.Assert(location.LinesPos, qt.Equals, 1)
 
-       location = locateErrorInString(`L1
+       location = locate(`L1
 L2
 This THEONE
 `, lineMatcher)
        c.Assert(location.Lines, qt.DeepEquals, []string{"L1", "L2", "This THEONE", ""})
        c.Assert(location.LinesPos, qt.Equals, 2)
 
-       location = locateErrorInString("NO MATCH", lineMatcher)
-       c.Assert(location.Position().LineNumber, qt.Equals, -1)
+       location, pos = locateErrorInString("NO MATCH", lineMatcher)
+       c.Assert(pos.LineNumber, qt.Equals, -1)
        c.Assert(location.LinesPos, qt.Equals, -1)
        c.Assert(len(location.Lines), qt.Equals, 0)
 
@@ -83,7 +87,7 @@ This THEONE
                return m.LineNumber == 6
        }
 
-       location = locateErrorInString(`A
+       location, pos = locateErrorInString(`A
 B
 C
 D
@@ -95,7 +99,7 @@ I
 J`, lineMatcher)
 
        c.Assert(location.Lines, qt.DeepEquals, []string{"D", "E", "F", "G", "H"})
-       c.Assert(location.Position().LineNumber, qt.Equals, 6)
+       c.Assert(pos.LineNumber, qt.Equals, 6)
        c.Assert(location.LinesPos, qt.Equals, 2)
 
        // Test match EOF
@@ -103,26 +107,26 @@ J`, lineMatcher)
                return m.LineNumber == 4
        }
 
-       location = locateErrorInString(`A
+       location, pos = locateErrorInString(`A
 B
 C
 `, lineMatcher)
 
        c.Assert(location.Lines, qt.DeepEquals, []string{"B", "C", ""})
-       c.Assert(location.Position().LineNumber, qt.Equals, 4)
+       c.Assert(pos.LineNumber, qt.Equals, 4)
        c.Assert(location.LinesPos, qt.Equals, 2)
 
        offsetMatcher := func(m LineMatcher) bool {
                return m.Offset == 1
        }
 
-       location = locateErrorInString(`A
+       location, pos = locateErrorInString(`A
 B
 C
 D
 E`, offsetMatcher)
 
        c.Assert(location.Lines, qt.DeepEquals, []string{"A", "B", "C", "D"})
-       c.Assert(location.Position().LineNumber, qt.Equals, 2)
+       c.Assert(pos.LineNumber, qt.Equals, 2)
        c.Assert(location.LinesPos, qt.Equals, 1)
 }
index 27cfd26937e3dafa295897b66e36470dfe0af743..6ce90885353241da12d08edf6262572e141ce1e9 100644 (file)
@@ -19,37 +19,11 @@ import (
        "errors"
        "fmt"
        "io"
-       "os"
        "runtime"
        "runtime/debug"
        "strconv"
-
-       _errors "github.com/pkg/errors"
 )
 
-// As defined in https://godoc.org/github.com/pkg/errors
-type causer interface {
-       Cause() error
-}
-
-type stackTracer interface {
-       StackTrace() _errors.StackTrace
-}
-
-// PrintStackTraceFromErr prints the error's stack trace to stdoud.
-func PrintStackTraceFromErr(err error) {
-       FprintStackTraceFromErr(os.Stdout, err)
-}
-
-// FprintStackTraceFromErr prints the error's stack trace to w.
-func FprintStackTraceFromErr(w io.Writer, err error) {
-       if err, ok := err.(stackTracer); ok {
-               for _, f := range err.StackTrace() {
-                       fmt.Fprintf(w, "%+s:%d\n", f, f)
-               }
-       }
-}
-
 // PrintStackTrace prints the current stacktrace to w.
 func PrintStackTrace(w io.Writer) {
        buf := make([]byte, 1<<16)
index 1cb31ff9f25b6c603cf5d1ffe4bcb80dc7c4fdfd..abd36cfbca6aaa4e2bb2114dc1ca50c459f7105b 100644 (file)
@@ -1,11 +1,11 @@
-// Copyright 2018 The Hugo Authors. All rights reserved.
+// Copyright 2022 The Hugo Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 // http://www.apache.org/licenses/LICENSE-2.0
 //
-// Unless required by applicable law or agreed to in writing, software
+// Unless required by applicable lfmtaw or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
@@ -15,59 +15,217 @@ package herrors
 
 import (
        "encoding/json"
+       "fmt"
+       "io"
+       "path/filepath"
 
+       "github.com/gohugoio/hugo/common/paths"
        "github.com/gohugoio/hugo/common/text"
+       "github.com/pelletier/go-toml/v2"
+       "github.com/spf13/afero"
+       "github.com/tdewolff/parse/v2"
 
-       "github.com/pkg/errors"
+       "errors"
 )
 
-var _ causer = (*fileError)(nil)
-
 // FileError represents an error when handling a file: Parsing a config file,
 // execute a template etc.
 type FileError interface {
        error
 
+       // ErroContext holds some context information about the error.
+       ErrorContext() *ErrorContext
+
        text.Positioner
 
-       // A string identifying the type of file, e.g. JSON, TOML, markdown etc.
-       Type() string
+       // UpdatePosition updates the position of the error.
+       UpdatePosition(pos text.Position) FileError
+
+       // UpdateContent updates the error with a new ErrorContext from the content of the file.
+       UpdateContent(r io.Reader, linematcher LineMatcherFn) FileError
+}
+
+// Unwrapper can unwrap errors created with fmt.Errorf.
+type Unwrapper interface {
+       Unwrap() error
 }
 
-var _ FileError = (*fileError)(nil)
+var (
+       _ FileError = (*fileError)(nil)
+       _ Unwrapper = (*fileError)(nil)
+)
+
+func (fe *fileError) UpdatePosition(pos text.Position) FileError {
+       oldFilename := fe.Position().Filename
+       if pos.Filename != "" && fe.fileType == "" {
+               _, fe.fileType = paths.FileAndExtNoDelimiter(filepath.Clean(pos.Filename))
+       }
+       if pos.Filename == "" {
+               pos.Filename = oldFilename
+       }
+       fe.position = pos
+       return fe
+}
+
+func (fe *fileError) UpdateContent(r io.Reader, linematcher LineMatcherFn) FileError {
+       if linematcher == nil {
+               linematcher = SimpleLineMatcher
+       }
+
+       var (
+               contentPos   text.Position
+               posle        = fe.position
+               errorContext *ErrorContext
+       )
+
+       if posle.LineNumber <= 1 && posle.Offset > 0 {
+               // Try to locate the line number from the content if offset is set.
+               errorContext, contentPos = locateError(r, fe, func(m LineMatcher) bool {
+                       if posle.Offset >= m.Offset && posle.Offset < m.Offset+len(m.Line) {
+                               lno := posle.LineNumber - m.Position.LineNumber + m.LineNumber
+                               m.Position = text.Position{LineNumber: lno}
+                               return linematcher(m)
+                       }
+                       return false
+               })
+       } else {
+               errorContext, contentPos = locateError(r, fe, linematcher)
+       }
+
+       if errorContext.ChromaLexer == "" {
+               if fe.fileType != "" {
+                       errorContext.ChromaLexer = chromaLexerFromType(fe.fileType)
+               } else {
+                       errorContext.ChromaLexer = chromaLexerFromFilename(fe.Position().Filename)
+               }
+       }
+
+       fe.errorContext = errorContext
+
+       if contentPos.LineNumber > 0 {
+               fe.position.LineNumber = contentPos.LineNumber
+       }
+
+       return fe
+
+}
 
 type fileError struct {
-       position text.Position
+       position     text.Position
+       errorContext *ErrorContext
 
        fileType string
 
        cause error
 }
 
+type fileErrorWithErrorContext struct {
+       *fileError
+}
+
+func (e *fileError) ErrorContext() *ErrorContext {
+       return e.errorContext
+}
+
 // Position returns the text position of this error.
 func (e fileError) Position() text.Position {
        return e.position
 }
 
-func (e *fileError) Type() string {
-       return e.fileType
+func (e *fileError) Error() string {
+       return fmt.Sprintf("%s: %s", e.position, e.cause)
 }
 
-func (e *fileError) Error() string {
-       if e.cause == nil {
-               return ""
+func (e *fileError) Unwrap() error {
+       return e.cause
+}
+
+// NewFileError creates a new FileError that wraps err.
+// The value for name should identify the file, the best
+// being the full filename to the file on disk.
+func NewFileError(name string, err error) FileError {
+       if err == nil {
+               panic("err is nil")
+       }
+
+       // Filetype is used to determine the Chroma lexer to use.
+       fileType, pos := extractFileTypePos(err)
+       pos.Filename = name
+       if fileType == "" {
+               _, fileType = paths.FileAndExtNoDelimiter(filepath.Clean(name))
        }
-       return e.cause.Error()
+
+       if pos.LineNumber < 0 {
+               panic(fmt.Sprintf("invalid line number: %d", pos.LineNumber))
+       }
+
+       return &fileError{cause: err, fileType: fileType, position: pos}
+
 }
 
-func (f *fileError) Cause() error {
-       return f.cause
+// NewFileErrorFromFile is a convenience method to create a new FileError from a file.
+func NewFileErrorFromFile(err error, filename, realFilename string, fs afero.Fs, linematcher LineMatcherFn) FileError {
+       if err == nil {
+               panic("err is nil")
+       }
+       if linematcher == nil {
+               linematcher = SimpleLineMatcher
+       }
+       f, err2 := fs.Open(filename)
+       if err2 != nil {
+               return NewFileError(realFilename, err)
+       }
+       defer f.Close()
+       return NewFileError(realFilename, err).UpdateContent(f, linematcher)
 }
 
-// NewFileError creates a new FileError.
-func NewFileError(fileType string, offset, lineNumber, columnNumber int, err error) FileError {
-       pos := text.Position{Offset: offset, LineNumber: lineNumber, ColumnNumber: columnNumber}
-       return &fileError{cause: err, fileType: fileType, position: pos}
+// Cause returns the underlying error or itself if it does not implement Unwrap.
+func Cause(err error) error {
+       if u := errors.Unwrap(err); u != nil {
+               return u
+       }
+       return err
+}
+
+func extractFileTypePos(err error) (string, text.Position) {
+       err = Cause(err)
+       var fileType string
+
+       // Fall back to line/col 1:1 if we cannot find any better information.
+       pos := text.Position{
+               Offset:       -1,
+               LineNumber:   1,
+               ColumnNumber: 1,
+       }
+
+       // JSON errors.
+       offset, typ := extractOffsetAndType(err)
+       if fileType == "" {
+               fileType = typ
+       }
+
+       if offset >= 0 {
+               pos.Offset = offset
+       }
+
+       // The error type from the minifier contains line number and column number.
+       if line, col := exctractLineNumberAndColumnNumber(err); line >= 0 {
+               pos.LineNumber = line
+               pos.ColumnNumber = col
+               return fileType, pos
+       }
+
+       // Look in the error message for the line number.
+       for _, handle := range lineNumberExtractors {
+               lno, col := handle(err)
+               if lno > 0 {
+                       pos.ColumnNumber = col
+                       pos.LineNumber = lno
+                       break
+               }
+       }
+
+       return fileType, pos
 }
 
 // UnwrapFileError tries to unwrap a FileError from err.
@@ -77,49 +235,26 @@ func UnwrapFileError(err error) FileError {
                switch v := err.(type) {
                case FileError:
                        return v
-               case causer:
-                       err = v.Cause()
                default:
-                       return nil
+                       err = errors.Unwrap(err)
                }
        }
        return nil
 }
 
-// ToFileErrorWithOffset will return a new FileError with a line number
-// with the given offset from the original.
-func ToFileErrorWithOffset(fe FileError, offset int) FileError {
-       pos := fe.Position()
-       return ToFileErrorWithLineNumber(fe, pos.LineNumber+offset)
-}
-
-// ToFileErrorWithOffset will return a new FileError with the given line number.
-func ToFileErrorWithLineNumber(fe FileError, lineNumber int) FileError {
-       pos := fe.Position()
-       pos.LineNumber = lineNumber
-       return &fileError{cause: fe, fileType: fe.Type(), position: pos}
-}
-
-// ToFileError will convert the given error to an error supporting
-// the FileError interface.
-func ToFileError(fileType string, err error) FileError {
-       for _, handle := range lineNumberExtractors {
-               lno, col := handle(err)
-               offset, typ := extractOffsetAndType(err)
-               if fileType == "" {
-                       fileType = typ
-               }
-
-               if lno > 0 || offset != -1 {
-                       return NewFileError(fileType, offset, lno, col, err)
+// UnwrapFileErrorsWithErrorContext tries to unwrap all FileError in err that has an ErrorContext.
+func UnwrapFileErrorsWithErrorContext(err error) []FileError {
+       var errs []FileError
+       for err != nil {
+               if v, ok := err.(FileError); ok && v.ErrorContext() != nil {
+                       errs = append(errs, v)
                }
+               err = errors.Unwrap(err)
        }
-       // Fall back to the pointing to line number 1.
-       return NewFileError(fileType, -1, 1, 1, err)
+       return errs
 }
 
 func extractOffsetAndType(e error) (int, string) {
-       e = errors.Cause(e)
        switch v := e.(type) {
        case *json.UnmarshalTypeError:
                return int(v.Offset), "json"
@@ -129,3 +264,15 @@ func extractOffsetAndType(e error) (int, string) {
                return -1, ""
        }
 }
+
+func exctractLineNumberAndColumnNumber(e error) (int, int) {
+       switch v := e.(type) {
+       case *parse.Error:
+               return v.Line, v.Column
+       case *toml.DecodeError:
+               return v.Position()
+
+       }
+
+       return -1, -1
+}
index 675be94e8776f96634232b938b90ee4e838d3de2..e6595aa28c3b261d555f86ea247af8a3e51f2666 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2018 The Hugo Authors. All rights reserved.
+// Copyright 2022 The Hugo Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 package herrors
 
 import (
+       "fmt"
+       "strings"
        "testing"
 
-       "github.com/pkg/errors"
+       "errors"
+
+       "github.com/gohugoio/hugo/common/text"
 
        qt "github.com/frankban/quicktest"
 )
 
-func TestToLineNumberError(t *testing.T) {
+func TestNewFileError(t *testing.T) {
+       t.Parallel()
+
+       c := qt.New(t)
+
+       fe := NewFileError("foo.html", errors.New("bar"))
+       c.Assert(fe.Error(), qt.Equals, `"foo.html:1:1": bar`)
+
+       lines := ""
+       for i := 1; i <= 100; i++ {
+               lines += fmt.Sprintf("line %d\n", i)
+       }
+
+       fe.UpdatePosition(text.Position{LineNumber: 32, ColumnNumber: 2})
+       c.Assert(fe.Error(), qt.Equals, `"foo.html:32:2": bar`)
+       fe.UpdatePosition(text.Position{LineNumber: 0, ColumnNumber: 0, Offset: 212})
+       fe.UpdateContent(strings.NewReader(lines), SimpleLineMatcher)
+       c.Assert(fe.Error(), qt.Equals, `"foo.html:32:0": bar`)
+       errorContext := fe.ErrorContext()
+       c.Assert(errorContext, qt.IsNotNil)
+       c.Assert(errorContext.Lines, qt.DeepEquals, []string{"line 30", "line 31", "line 32", "line 33", "line 34"})
+       c.Assert(errorContext.LinesPos, qt.Equals, 2)
+       c.Assert(errorContext.ChromaLexer, qt.Equals, "go-html-template")
+
+}
+
+func TestNewFileErrorExtractFromMessage(t *testing.T) {
        t.Parallel()
 
        c := qt.New(t)
@@ -37,18 +67,16 @@ func TestToLineNumberError(t *testing.T) {
                {errors.New("parse failed: template: _default/bundle-resource-meta.html:11: unexpected in operand"), 0, 11, 1},
                {errors.New(`failed:: template: _default/bundle-resource-meta.html:2:7: executing "main" at <.Titles>`), 0, 2, 7},
                {errors.New(`failed to load translations: (6, 7): was expecting token =, but got "g" instead`), 0, 6, 7},
+               {errors.New(`execute of template failed: template: index.html:2:5: executing "index.html" at <partial "foo.html" .>: error calling partial: "/layouts/partials/foo.html:3:6": execute of template failed: template: partials/foo.html:3:6: executing "partials/foo.html" at <.ThisDoesNotExist>: can't evaluate field ThisDoesNotExist in type *hugolib.pageStat`), 0, 2, 5},
        } {
 
-               got := ToFileError("template", test.in)
+               got := NewFileError("test.txt", test.in)
 
                errMsg := qt.Commentf("[%d][%T]", i, got)
-               le, ok := got.(FileError)
-               c.Assert(ok, qt.Equals, true)
 
-               c.Assert(ok, qt.Equals, true, errMsg)
-               pos := le.Position()
+               pos := got.Position()
                c.Assert(pos.LineNumber, qt.Equals, test.lineNumber, errMsg)
                c.Assert(pos.ColumnNumber, qt.Equals, test.columnNumber, errMsg)
-               c.Assert(errors.Cause(got), qt.Not(qt.IsNil))
+               c.Assert(errors.Unwrap(got), qt.Not(qt.IsNil))
        }
 }
index 3df62bdfe3ae049e4c202ccaec3678842a7bb05c..f70a2691fc3141bda51710437754b4575bc199e8 100644 (file)
@@ -16,36 +16,22 @@ package herrors
 import (
        "regexp"
        "strconv"
-
-       "github.com/pkg/errors"
-
-       "github.com/pelletier/go-toml/v2"
 )
 
 var lineNumberExtractors = []lineNumberExtractor{
        // Template/shortcode parse errors
-       newLineNumberErrHandlerFromRegexp(".*:(\\d+):(\\d*):"),
-       newLineNumberErrHandlerFromRegexp(".*:(\\d+):"),
+       newLineNumberErrHandlerFromRegexp(`:(\d+):(\d*):`),
+       newLineNumberErrHandlerFromRegexp(`:(\d+):`),
 
-       // TOML parse errors
-       tomlLineNumberExtractor,
        // YAML parse errors
-       newLineNumberErrHandlerFromRegexp("line (\\d+):"),
+       newLineNumberErrHandlerFromRegexp(`line (\d+):`),
 
        // i18n bundle errors
-       newLineNumberErrHandlerFromRegexp("\\((\\d+),\\s(\\d*)"),
+       newLineNumberErrHandlerFromRegexp(`\((\d+),\s(\d*)`),
 }
 
 type lineNumberExtractor func(e error) (int, int)
 
-var tomlLineNumberExtractor = func(e error) (int, int) {
-       e = errors.Cause(e)
-       if terr, ok := e.(*toml.DecodeError); ok {
-               return terr.Position()
-       }
-       return -1, -1
-}
-
 func newLineNumberErrHandlerFromRegexp(expression string) lineNumberExtractor {
        re := regexp.MustCompile(expression)
        return extractLineNo(re)
@@ -72,6 +58,6 @@ func extractLineNo(re *regexp.Regexp) lineNumberExtractor {
                        return lno, col
                }
 
-               return -1, col
+               return 0, col
        }
 }
index be4506f4cd192044cf8b48e52ee37ffcc5e04908..7c52f872346f3cb2a2b7e1eae7e84abc8109d32d 100644 (file)
 package hugio
 
 import (
+       "fmt"
        "io"
        "io/ioutil"
        "os"
        "path/filepath"
 
-       "github.com/pkg/errors"
-
        "github.com/spf13/afero"
 )
 
@@ -60,7 +59,7 @@ func CopyDir(fs afero.Fs, from, to string, shouldCopy func(filename string) bool
        }
 
        if !fi.IsDir() {
-               return errors.Errorf("%q is not a directory", from)
+               return fmt.Errorf("%q is not a directory", from)
        }
 
        err = fs.MkdirAll(to, 0777) // before umask
index f34d1bac845bbbbfa15c46e8fe5203683fa885a3..efaa589d18e439fe3af015d6dd278b7b0d01a022 100644 (file)
 package config
 
 import (
+       "fmt"
        "sort"
        "strings"
        "sync"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/types"
 
        "github.com/gobwas/glob"
@@ -207,7 +206,7 @@ func DecodeServer(cfg Provider) (*Server, error) {
                        // There are some tricky infinite loop situations when dealing
                        // when the target does not have a trailing slash.
                        // This can certainly be handled better, but not time for that now.
-                       return nil, errors.Errorf("unsupported redirect to value %q in server config; currently this must be either a remote destination or a local folder, e.g. \"/blog/\" or \"/blog/index.html\"", redir.To)
+                       return nil, fmt.Errorf("unsupported redirect to value %q in server config; currently this must be either a remote destination or a local folder, e.g. \"/blog/\" or \"/blog/index.html\"", redir.To)
                }
                s.Redirects[i] = redir
        }
index 76a7e2635d9d5a096d83bebab17fb60ea2fbd598..6bbad7002bb2f55b73e77b38be20cef4645684ec 100644 (file)
 package config
 
 import (
+       "fmt"
        "os"
        "path/filepath"
        "strings"
 
        "github.com/gohugoio/hugo/common/herrors"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/paths"
 
        "github.com/gohugoio/hugo/common/maps"
@@ -60,7 +59,7 @@ func FromConfigString(config, configType string) (Provider, error) {
 func FromFile(fs afero.Fs, filename string) (Provider, error) {
        m, err := loadConfigFromFile(fs, filename)
        if err != nil {
-               return nil, herrors.WithFileContextForFileDefault(err, filename, fs)
+               return nil, herrors.NewFileErrorFromFile(err, filename, filename, fs, herrors.SimpleLineMatcher)
        }
        return NewFrom(m), nil
 }
@@ -132,7 +131,7 @@ func LoadConfigFromDir(sourceFs afero.Fs, configDir, environment string) (Provid
                        if err != nil {
                                // This will be used in error reporting, use the most specific value.
                                dirnames = []string{path}
-                               return errors.Wrapf(err, "failed to unmarshl config for path %q", path)
+                               return fmt.Errorf("failed to unmarshl config for path %q: %w", path, err)
                        }
 
                        var keyPath []string
index 9034ba29935072fedaec2539aef11cd38ade409c..5f05e25f9d95bdf0d2967aecc0c3d3a93b116ca3 100644 (file)
@@ -27,7 +27,7 @@ import (
        "github.com/gohugoio/hugo/common/hexec"
        "github.com/gohugoio/hugo/common/paths"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/hugofs/files"
 
@@ -94,11 +94,11 @@ func NewContent(h *hugolib.HugoSites, kind, targetPath string) error {
                }
 
                if ext == "" {
-                       return "", errors.Errorf("failed to resolve %q to a archetype template", targetPath)
+                       return "", fmt.Errorf("failed to resolve %q to a archetype template", targetPath)
                }
 
                if !files.IsContentFile(b.targetPath) {
-                       return "", errors.Errorf("target path %q is not a known content format", b.targetPath)
+                       return "", fmt.Errorf("target path %q is not a known content format", b.targetPath)
                }
 
                return b.buildFile()
@@ -188,14 +188,14 @@ func (b *contentBuilder) buildDir() error {
 
                in, err := meta.Open()
                if err != nil {
-                       return errors.Wrap(err, "failed to open non-content file")
+                       return fmt.Errorf("failed to open non-content file: %w", err)
                }
 
                targetFilename := filepath.Join(baseDir, b.targetPath, strings.TrimPrefix(filename, b.archetypeFilename))
                targetDir := filepath.Dir(targetFilename)
 
                if err := b.sourceFs.MkdirAll(targetDir, 0o777); err != nil && !os.IsExist(err) {
-                       return errors.Wrapf(err, "failed to create target directory for %q", targetDir)
+                       return fmt.Errorf("failed to create target directory for %q: %w", targetDir, err)
                }
 
                out, err := b.sourceFs.Create(targetFilename)
@@ -329,7 +329,7 @@ func (b *contentBuilder) mapArcheTypeDir() error {
        w := hugofs.NewWalkway(walkCfg)
 
        if err := w.Walk(); err != nil {
-               return errors.Wrapf(err, "failed to walk archetype dir %q", b.archetypeFilename)
+               return fmt.Errorf("failed to walk archetype dir %q: %w", b.archetypeFilename, err)
        }
 
        b.dirMap = m
@@ -374,7 +374,7 @@ func (b *contentBuilder) usesSiteVar(filename string) (bool, error) {
        }
        bb, err := afero.ReadFile(b.archeTypeFs, filename)
        if err != nil {
-               return false, errors.Wrap(err, "failed to open archetype file")
+               return false, fmt.Errorf("failed to open archetype file: %w", err)
        }
 
        return bytes.Contains(bb, []byte(".Site")) || bytes.Contains(bb, []byte("site.")), nil
index e33bbf3f2a342a96698566f119faa0337d2ea09d..f0a4e01783798517660fb3f66be86ff7afc819fa 100644 (file)
@@ -34,11 +34,12 @@ import (
        "strings"
        "sync"
 
+       "errors"
+
        "github.com/dustin/go-humanize"
        "github.com/gobwas/glob"
        "github.com/gohugoio/hugo/config"
        "github.com/gohugoio/hugo/media"
-       "github.com/pkg/errors"
        "github.com/spf13/afero"
        jww "github.com/spf13/jwalterweatherman"
        "golang.org/x/text/unicode/norm"
index cdc146f217acdbebca71110104444fe71b153709..ad251692249f39ec34352133ce0a39cca937b144 100644 (file)
@@ -20,12 +20,13 @@ import (
        "fmt"
        "regexp"
 
+       "errors"
+
        "github.com/gobwas/glob"
        "github.com/gohugoio/hugo/config"
        hglob "github.com/gohugoio/hugo/hugofs/glob"
        "github.com/gohugoio/hugo/media"
        "github.com/mitchellh/mapstructure"
-       "github.com/pkg/errors"
 )
 
 const deploymentConfigKey = "deployment"
index a9e78860de1682594b9e582efe68ca627cb06a10..ece4203024f9af128a6c882d65bba92a65f0b0fb 100644 (file)
@@ -1,12 +1,11 @@
 package deps
 
 import (
+       "fmt"
        "sync"
        "sync/atomic"
        "time"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/cache/filecache"
        "github.com/gohugoio/hugo/common/hexec"
        "github.com/gohugoio/hugo/common/loggers"
@@ -186,11 +185,11 @@ func (d *Deps) SetTextTmpl(tmpl tpl.TemplateParseFinder) {
 func (d *Deps) LoadResources() error {
        // Note that the translations need to be loaded before the templates.
        if err := d.translationProvider.Update(d); err != nil {
-               return errors.Wrap(err, "loading translations")
+               return fmt.Errorf("loading translations: %w", err)
        }
 
        if err := d.templateProvider.Update(d); err != nil {
-               return errors.Wrap(err, "loading templates")
+               return fmt.Errorf("loading templates: %w", err)
        }
 
        return nil
@@ -236,18 +235,18 @@ func New(cfg DepsCfg) (*Deps, error) {
 
        securityConfig, err := security.DecodeConfig(cfg.Cfg)
        if err != nil {
-               return nil, errors.WithMessage(err, "failed to create security config from configuration")
+               return nil, fmt.Errorf("failed to create security config from configuration: %w", err)
        }
        execHelper := hexec.New(securityConfig)
 
        ps, err := helpers.NewPathSpec(fs, cfg.Language, logger)
        if err != nil {
-               return nil, errors.Wrap(err, "create PathSpec")
+               return nil, fmt.Errorf("create PathSpec: %w", err)
        }
 
        fileCaches, err := filecache.NewCaches(ps)
        if err != nil {
-               return nil, errors.WithMessage(err, "failed to create file caches from configuration")
+               return nil, fmt.Errorf("failed to create file caches from configuration: %w", err)
        }
 
        errorHandler := &globalErrHandler{}
index 73970d5581ed2e93a8d03d75503f80ec9990dedd..0fb365f43bb85b7350f711892a3805bd8673218b 100644 (file)
@@ -31,7 +31,6 @@ import (
        "github.com/gohugoio/hugo/hugofs"
 
        "github.com/gohugoio/hugo/common/hugio"
-       _errors "github.com/pkg/errors"
        "github.com/spf13/afero"
 )
 
@@ -403,7 +402,7 @@ func GetCacheDir(fs afero.Fs, cfg config.Provider) (string, error) {
                if !exists {
                        err := fs.MkdirAll(cacheDir, 0777) // Before umask
                        if err != nil {
-                               return "", _errors.Wrap(err, "failed to create cache dir")
+                               return "", fmt.Errorf("failed to create cache dir: %w", err)
                        }
                }
                return cacheDir, nil
index be0ae495d39c81a1b66385f767c28477cfd40ab8..3762d753b0eccc19d565ba62dcc31ee154989b9f 100644 (file)
 package hugofs
 
 import (
+       "fmt"
        "os"
        "path/filepath"
        "strings"
 
-       "github.com/pkg/errors"
-
        "github.com/spf13/afero"
 )
 
@@ -232,7 +231,7 @@ func (l *baseFileDecoratorFile) Readdir(c int) (ofi []os.FileInfo, err error) {
                }
                fi, err = l.fs.decorate(fi, filename)
                if err != nil {
-                       return nil, errors.Wrap(err, "decorate")
+                       return nil, fmt.Errorf("decorate: %w", err)
                }
                fisp = append(fisp, fi)
        }
index 29ac3c240e87d199595e5d5bb9a77a8521f11c7a..af37fce7e66edab1c01a87e3818c45eb04df74f2 100644 (file)
@@ -28,7 +28,7 @@ import (
        "github.com/gohugoio/hugo/hugofs/files"
        "golang.org/x/text/unicode/norm"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/common/hreflect"
 
index a891ba8def94b8c940463264a1b2ce6884663396..90df48f8cae96fa753389f82f15d69bbd569129a 100644 (file)
@@ -21,8 +21,6 @@ import (
 
        "github.com/gohugoio/hugo/hugofs/files"
 
-       "github.com/pkg/errors"
-
        radix "github.com/armon/go-radix"
        "github.com/spf13/afero"
 )
@@ -191,7 +189,7 @@ func (fs *RootMappingFs) Dirs(base string) ([]FileMetaInfo, error) {
                fs = decorateDirs(fs, r.Meta)
                fi, err := fs.Stat("")
                if err != nil {
-                       return nil, errors.Wrap(err, "RootMappingFs.Dirs")
+                       return nil, fmt.Errorf("RootMappingFs.Dirs: %w", err)
                }
 
                if !fi.IsDir() {
@@ -560,7 +558,7 @@ func (fs *RootMappingFs) doLstat(name string) ([]FileMetaInfo, error) {
 
        if fileCount > 1 {
                // Not supported by this filesystem.
-               return nil, errors.Errorf("found multiple files with name %q, use .Readdir or the source filesystem directly", name)
+               return nil, fmt.Errorf("found multiple files with name %q, use .Readdir or the source filesystem directly", name)
        }
 
        return []FileMetaInfo{roots[0].fi}, nil
index a9a3f1bbcf69724e10c9cb9221f602781fce6694..7edaf75137da3112350e198878342d1de7852948 100644 (file)
 package hugofs
 
 import (
+       "fmt"
        "os"
        "syscall"
        "time"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/spf13/afero"
 )
@@ -83,7 +84,7 @@ func (fs *SliceFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
                return decorateFileInfo(fi, fs, fs.getOpener(name), "", "", nil), false, nil
        }
 
-       return nil, false, errors.Errorf("lstat: files not supported: %q", name)
+       return nil, false, fmt.Errorf("lstat: files not supported: %q", name)
 }
 
 func (fs *SliceFs) Mkdir(n string, p os.FileMode) error {
index 26f1b74e0389588e74c82d09b18196b6920069e3..22a99402f326afbb2f820fbe940199e3c8d149dd 100644 (file)
@@ -22,7 +22,7 @@ import (
 
        "github.com/gohugoio/hugo/common/loggers"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/spf13/afero"
 )
@@ -125,7 +125,7 @@ func (w *Walkway) Walk() error {
                        if w.checkErr(w.root, err) {
                                return nil
                        }
-                       return w.walkFn(w.root, nil, errors.Wrapf(err, "walk: %q", w.root))
+                       return w.walkFn(w.root, nil, fmt.Errorf("walk: %q: %w", w.root, err))
                }
                fi = info.(FileMetaInfo)
        }
@@ -192,7 +192,7 @@ func (w *Walkway) walk(path string, info FileMetaInfo, dirEntries []FileMetaInfo
                        if w.checkErr(path, err) {
                                return nil
                        }
-                       return walkFn(path, info, errors.Wrapf(err, "walk: open %q (%q)", path, w.root))
+                       return walkFn(path, info, fmt.Errorf("walk: open %q (%q): %w", path, w.root, err))
                }
 
                fis, err := f.Readdir(-1)
@@ -201,7 +201,7 @@ func (w *Walkway) walk(path string, info FileMetaInfo, dirEntries []FileMetaInfo
                        if w.checkErr(filename, err) {
                                return nil
                        }
-                       return walkFn(path, info, errors.Wrap(err, "walk: Readdir"))
+                       return walkFn(path, info, fmt.Errorf("walk: Readdir: %w", err))
                }
 
                dirEntries = fileInfosToFileMetaInfos(fis)
index 2d9ec784d571ca943a15eb07b23c661e5d01d052..2e162fa7213243cd416796a56014b5f3c78469f2 100644 (file)
@@ -22,7 +22,7 @@ import (
        "strings"
        "testing"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/common/para"
        "github.com/gohugoio/hugo/htesting"
index 5d2c6ddf7a1e783171bc6d982d971e2c9de22c83..b2713758ac208a2d7da5b63a83f08db8d42daa7f 100644 (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)
 }
index 99801031848e0720daf217cff2bcac2d5700a8ee..7ac3f969dacfda57de239d8590bae6a4d91e18ef 100644 (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"))
 }
index bea98894da60b258c6431c4a6a8635f69e7a0787..e6e82979f02286214a8b157690d63a9ea0e461d3 100644 (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))
index 330391dcb6890bfcbab0e75f77971c483c2f8bfe..6849998b6f5f30ac2c5e90c379495a62499f5bae 100644 (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
        }
 
index 21a4e8f2abe162e88e0711dbfdb24c05991ba91d..a16e4720d9d1e6faea3b12702c5230f0511a0c3c 100644 (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 {
index fdfd34b168a6aa266c1a0ad6b02dcb5a1f0379e6..1cdd7041d63f03863d81e199758e964e74c6a712 100644 (file)
 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
index d02f8c624c58c3a8dcf719f837a44937b3a81181..2447246d6369d744bf28bd2a1755b4014d82d677 100644 (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)
index d67652dab7e9bf35b6fb1649a0b37b7287ed91b4..e0d69a8af4829809139ab1e11b6ef1440c8d9d28 100644 (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)
index 4616b6dbb59e678559419abe3c668ec9135ea396..1a191257c18295064db64af7e99981c92a6e32c1 100644 (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() {
index 8b23e7ac734a989802464e7a33a40a4b02805dee..8f983075da180f5323da4bf3d879b38bd766b126 100644 (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
index 58e75189270623d2fa675783fedbe71b10467e9b..c3fb9fffc1c50fe9cb0cea38e10b2d03b8728440 100644 (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) {
index 77165c072921ad0d1b4e182671197a2e35a8f6d7..4faefa3ccb34bb719f34d4efaebb0d8ed3c48012 100644 (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
+       if err == nil {
+               panic("wrapError with nil")
        }
-       var filename string
-       if !p.File().IsZero() {
-               filename = p.File().Filename()
+
+       if p.File().IsZero() {
+               // No more details to add.
+               return fmt.Errorf("%q: %w", p.Pathc(), err)
        }
 
-       err, _ = herrors.WithFileContextForFile(
-               err,
-               filename,
-               filename,
-               p.s.SourceSpec.Fs.Source,
-               herrors.SimpleLineMatcher)
+       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 {
index 0c269d57a6461676a5e207f232a2d0bfa11c7319..1c8748869a81971f056ed679cc82e6240c6d4947 100644 (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
index c77d7c32e125e4b29066d11bb7ee0d90d75b9331..fdce8e802e6ec4879e873c9e8262581518d97a96 100644 (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
 }
index 24231797358fd2e4733ac2988a307107a98bb805..e55a8a3e4902387f6fa76b73289340bee321c021 100644 (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 {
index 0e985953b16a088e644e08ecbe25cc57dffd58d8..c3e1ce8dddf38ec71ade5a0724aa2107cafdb786 100644 (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)
        }
 }
 
index 47687eaad8ac7077bec2e2767bca0e469eb4e054..04ac0218ad4c01659ee4dc0a41e157860eefbaf7 100644 (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
index 9d5716e161bd70b456e9d360107dfdebc88b8761..501665676c2e46bf5aaa1c23532084445096590c 100644 (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"))
index ac9e4a69947257b671a97438c283634f7e7a660d..42877b53780f8ef21e4a2770341dd65d9b76d7f2 100644 (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
 }
index c2c5abe8723ecfe118629e8bed6120454c2b2d1a..d1a844423907678c929413ac7110f3b5976896bd 100644 (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) {
index bbabf91a3a1e4fe6b211412ebfa1e07b05fb6a93..cf7f0ff8249d2143b4b08b7b4c5f577795f9899b 100644 (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
 }
index c09e5cc997f154e9f139e5ca42bb903e4cb5ac65..b572c443e1b05bf363a7b48124919146534e22cc 100644 (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
 }
index 6c1aa6fd09da1feafbd2cf284d4a64ecc3e093b4..4a72836af62f03114b387bb251f79696c6421a55 100644 (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")
index ef63e700ecfcbbf148905903b23bd3531045e50f..81e6fc2aba210c2fbfb61beabb446f137e38e7ea 100644 (file)
@@ -23,7 +23,7 @@ import (
 
        "github.com/spf13/cast"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/config"
 )
@@ -72,7 +72,7 @@ func LoadLanguageSettings(cfg config.Provider, oldLangs Languages) (c LanguagesC
        } else {
                languages2, err = toSortedLanguages(cfg, languages)
                if err != nil {
-                       return c, errors.Wrap(err, "Failed to parse multilingual config")
+                       return c, fmt.Errorf("Failed to parse multilingual config: %w", err)
                }
        }
 
index 44bd52f0c369300de272acf790d4ee84878b9955..52f9349c27dde602422f89d1bec424cc06cc0e06 100644 (file)
@@ -15,6 +15,7 @@ package i18n
 
 import (
        "encoding/json"
+       "fmt"
        "strings"
 
        "github.com/gohugoio/hugo/common/paths"
@@ -30,7 +31,6 @@ import (
        "github.com/gohugoio/hugo/deps"
        "github.com/gohugoio/hugo/hugofs"
        "github.com/gohugoio/hugo/source"
-       _errors "github.com/pkg/errors"
 )
 
 // TranslationProvider provides translation handling, i.e. loading
@@ -83,7 +83,7 @@ const artificialLangTagPrefix = "art-x-"
 func addTranslationFile(bundle *i18n.Bundle, r source.File) error {
        f, err := r.FileInfo().Meta().Open()
        if err != nil {
-               return _errors.Wrapf(err, "failed to open translations file %q:", r.LogicalName())
+               return fmt.Errorf("failed to open translations file %q:: %w", r.LogicalName(), err)
        }
 
        b := helpers.ReaderToBytes(f)
@@ -96,7 +96,7 @@ func addTranslationFile(bundle *i18n.Bundle, r source.File) error {
                try := artificialLangTagPrefix + lang
                _, err = language.Parse(try)
                if err != nil {
-                       return _errors.Errorf("%q %s.", try, err)
+                       return fmt.Errorf("%q: %s", try, err)
                }
                name = artificialLangTagPrefix + name
        }
@@ -111,7 +111,7 @@ func addTranslationFile(bundle *i18n.Bundle, r source.File) error {
                                return nil
                        }
                }
-               return errWithFileContext(_errors.Wrapf(err, "failed to load translations"), r)
+               return errWithFileContext(fmt.Errorf("failed to load translations: %w", err), r)
        }
 
        return nil
@@ -138,11 +138,6 @@ func errWithFileContext(inerr error, r source.File) error {
        }
        defer f.Close()
 
-       err, _ = herrors.WithFileContext(
-               inerr,
-               realFilename,
-               f,
-               herrors.SimpleLineMatcher)
+       return herrors.NewFileError(realFilename, inerr).UpdateContent(f, herrors.SimpleLineMatcher)
 
-       return err
 }
index a0294a10341654a839d6d221e2a46d0533b0ae4e..d6b30ec100535a0433273553aeacc084de0cc97f 100644 (file)
@@ -14,6 +14,7 @@
 package langs
 
 import (
+       "fmt"
        "sort"
        "strings"
        "sync"
@@ -22,8 +23,6 @@ import (
        "golang.org/x/text/collate"
        "golang.org/x/text/language"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/htime"
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/config"
@@ -311,7 +310,7 @@ func GetCollator(l *Language) *Collator {
 func (l *Language) loadLocation(tzStr string) error {
        location, err := time.LoadLocation(tzStr)
        if err != nil {
-               return errors.Wrapf(err, "invalid timeZone for language %q", l.Lang)
+               return fmt.Errorf("invalid timeZone for language %q: %w", l.Lang, err)
        }
        l.location = location
 
index 48e9e2489a4ea2c4a877836e8988faaf56cc6338..b998d0305d32ec98c1c536919a4d7698cc464de1 100644 (file)
@@ -19,7 +19,7 @@ import (
        "sync/atomic"
        "time"
 
-       "github.com/pkg/errors"
+       "errors"
 )
 
 // New creates a new empty Init.
index 668478ece9eabdcac9eb5382066bf38cfe818482..8c276c9f6eccca37f73dcf6600200d30ef8e3ca2 100644 (file)
@@ -19,8 +19,9 @@
 package blackfriday_config
 
 import (
+       "fmt"
+
        "github.com/mitchellh/mapstructure"
-       "github.com/pkg/errors"
 )
 
 // Default holds the default BlackFriday config.
@@ -64,7 +65,7 @@ type Config struct {
 
 func UpdateConfig(b Config, m map[string]any) (Config, error) {
        if err := mapstructure.Decode(m, &b); err != nil {
-               return b, errors.WithMessage(err, "failed to decode rendering config")
+               return b, fmt.Errorf("failed to decode rendering config: %w", err)
        }
        return b, nil
 }
index 6e1cfe881c386c6d493c6ba9dc28ef465db41ba0..78ba9f5aeec353d8e16a5f3501f0ae96ac311ca8 100644 (file)
@@ -47,7 +47,8 @@ import (
 
        "github.com/gohugoio/hugo/common/hugio"
 
-       "github.com/pkg/errors"
+       "errors"
+
        "github.com/spf13/afero"
 )
 
@@ -241,7 +242,7 @@ func (c *Client) Vendor() error {
                // See https://github.com/gohugoio/hugo/issues/8239
                // This is an error situation. We need something to vendor.
                if t.Mounts() == nil {
-                       return errors.Errorf("cannot vendor module %q, need at least one mount", t.Path())
+                       return fmt.Errorf("cannot vendor module %q, need at least one mount", t.Path())
                }
 
                fmt.Fprintln(&modulesContent, "# "+t.Path()+" "+t.Version())
@@ -253,22 +254,22 @@ func (c *Client) Vendor() error {
                        targetFilename := filepath.Join(vendorDir, t.Path(), mount.Source)
                        fi, err := c.fs.Stat(sourceFilename)
                        if err != nil {
-                               return errors.Wrap(err, "failed to vendor module")
+                               return fmt.Errorf("failed to vendor module: %w", err)
                        }
 
                        if fi.IsDir() {
                                if err := hugio.CopyDir(c.fs, sourceFilename, targetFilename, nil); err != nil {
-                                       return errors.Wrap(err, "failed to copy module to vendor dir")
+                                       return fmt.Errorf("failed to copy module to vendor dir: %w", err)
                                }
                        } else {
                                targetDir := filepath.Dir(targetFilename)
 
                                if err := c.fs.MkdirAll(targetDir, 0755); err != nil {
-                                       return errors.Wrap(err, "failed to make target dir")
+                                       return fmt.Errorf("failed to make target dir: %w", err)
                                }
 
                                if err := hugio.CopyFile(c.fs, sourceFilename, targetFilename); err != nil {
-                                       return errors.Wrap(err, "failed to copy module file to vendor")
+                                       return fmt.Errorf("failed to copy module file to vendor: %w", err)
                                }
                        }
                }
@@ -278,7 +279,7 @@ func (c *Client) Vendor() error {
                _, err := c.fs.Stat(resourcesDir)
                if err == nil {
                        if err := hugio.CopyDir(c.fs, resourcesDir, filepath.Join(vendorDir, t.Path(), files.FolderResources), nil); err != nil {
-                               return errors.Wrap(err, "failed to copy resources to vendor dir")
+                               return fmt.Errorf("failed to copy resources to vendor dir: %w", err)
                        }
                }
 
@@ -287,7 +288,7 @@ func (c *Client) Vendor() error {
                _, err = c.fs.Stat(configDir)
                if err == nil {
                        if err := hugio.CopyDir(c.fs, configDir, filepath.Join(vendorDir, t.Path(), "config"), nil); err != nil {
-                               return errors.Wrap(err, "failed to copy config dir to vendor dir")
+                               return fmt.Errorf("failed to copy config dir to vendor dir: %w", err)
                        }
                }
 
@@ -361,7 +362,7 @@ func (c *Client) get(args ...string) error {
                args = append([]string{"-d"}, args...)
        }
        if err := c.runGo(context.Background(), c.logger.Out(), append([]string{"get"}, args...)...); err != nil {
-               errors.Wrapf(err, "failed to get %q", args)
+               return fmt.Errorf("failed to get %q: %w", args, err)
        }
        return nil
 }
@@ -372,7 +373,7 @@ func (c *Client) get(args ...string) error {
 func (c *Client) Init(path string) error {
        err := c.runGo(context.Background(), c.logger.Out(), "mod", "init", path)
        if err != nil {
-               return errors.Wrap(err, "failed to init modules")
+               return fmt.Errorf("failed to init modules: %w", err)
        }
 
        c.GoModulesFilename = filepath.Join(c.ccfg.WorkingDir, goModFilename)
@@ -458,7 +459,7 @@ func (c *Client) listGoMods() (goModules, error) {
                out := ioutil.Discard
                err := c.runGo(context.Background(), out, args...)
                if err != nil {
-                       return errors.Wrap(err, "failed to download modules")
+                       return fmt.Errorf("failed to download modules: %w", err)
                }
                return nil
        }
@@ -477,7 +478,7 @@ func (c *Client) listGoMods() (goModules, error) {
                }
                err := c.runGo(context.Background(), b, args...)
                if err != nil {
-                       return errors.Wrap(err, "failed to list modules")
+                       return fmt.Errorf("failed to list modules: %w", err)
                }
 
                dec := json.NewDecoder(b)
@@ -487,7 +488,7 @@ func (c *Client) listGoMods() (goModules, error) {
                                if err == io.EOF {
                                        break
                                }
-                               return errors.Wrap(err, "failed to decode modules list")
+                               return fmt.Errorf("failed to decode modules list: %w", err)
                        }
 
                        if err := handle(m); err != nil {
@@ -657,7 +658,7 @@ If you then run 'hugo mod graph' it should resolve itself to the most recent ver
 
                _, ok := err.(*exec.ExitError)
                if !ok {
-                       return errors.Errorf("failed to execute 'go %v': %s %T", args, err, err)
+                       return fmt.Errorf("failed to execute 'go %v': %s %T", args, err, err)
                }
 
                // Too old Go version
@@ -666,7 +667,7 @@ If you then run 'hugo mod graph' it should resolve itself to the most recent ver
                        return nil
                }
 
-               return errors.Errorf("go command failed: %s", stderr)
+               return fmt.Errorf("go command failed: %s", stderr)
 
        }
 
@@ -706,7 +707,7 @@ func (c *Client) shouldVendor(path string) bool {
 }
 
 func (c *Client) createThemeDirname(modulePath string, isProjectMod bool) (string, error) {
-       invalid := errors.Errorf("invalid module path %q; must be relative to themesDir when defined outside of the project", modulePath)
+       invalid := fmt.Errorf("invalid module path %q; must be relative to themesDir when defined outside of the project", modulePath)
 
        modulePath = filepath.Clean(modulePath)
        if filepath.IsAbs(modulePath) {
index e012d4696a0a70e504af9a000c8de7167fc5633f..ff83f9ecca86f28f0dc8b445b2042bbf8aa0aed6 100644 (file)
@@ -36,7 +36,7 @@ import (
 
        "github.com/rogpeppe/go-internal/module"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/config"
        "github.com/spf13/afero"
@@ -48,7 +48,7 @@ const vendorModulesFilename = "modules.txt"
 
 // IsNotExist returns whether an error means that a module could not be found.
 func IsNotExist(err error) bool {
-       return errors.Cause(err) == ErrNotExist
+       return errors.Is(err, os.ErrNotExist)
 }
 
 // CreateProjectModule creates modules from the given config.
@@ -289,7 +289,7 @@ func (c *collector) add(owner *moduleAdapter, moduleImport Import, disabled bool
                                        return nil, nil
                                }
                                if found, _ := afero.Exists(c.fs, moduleDir); !found {
-                                       c.err = c.wrapModuleNotFound(errors.Errorf(`module %q not found; either add it as a Hugo Module or store it in %q.`, modulePath, c.ccfg.ThemesDir))
+                                       c.err = c.wrapModuleNotFound(fmt.Errorf(`module %q not found; either add it as a Hugo Module or store it in %q.`, modulePath, c.ccfg.ThemesDir))
                                        return nil, nil
                                }
                        }
@@ -297,7 +297,7 @@ func (c *collector) add(owner *moduleAdapter, moduleImport Import, disabled bool
        }
 
        if found, _ := afero.Exists(c.fs, moduleDir); !found {
-               c.err = c.wrapModuleNotFound(errors.Errorf("%q not found", moduleDir))
+               c.err = c.wrapModuleNotFound(fmt.Errorf("%q not found", moduleDir))
                return nil, nil
        }
 
@@ -557,7 +557,7 @@ func (c *collector) collectModulesTXT(owner Module) error {
                line = strings.TrimSpace(line)
                parts := strings.Fields(line)
                if len(parts) != 2 {
-                       return errors.Errorf("invalid modules list: %q", filename)
+                       return fmt.Errorf("invalid modules list: %q", filename)
                }
                path := parts[0]
 
@@ -662,7 +662,7 @@ func (c *collector) normalizeMounts(owner *moduleAdapter, mounts []Mount) ([]Mou
                        targetBase = mnt.Target[0:idxPathSep]
                }
                if !files.IsComponentFolder(targetBase) {
-                       return nil, errors.Errorf("%s: mount target must be one of: %v", errMsg, files.ComponentFolders)
+                       return nil, fmt.Errorf("%s: mount target must be one of: %v", errMsg, files.ComponentFolders)
                }
 
                out = append(out, mnt)
@@ -672,7 +672,7 @@ func (c *collector) normalizeMounts(owner *moduleAdapter, mounts []Mount) ([]Mou
 }
 
 func (c *collector) wrapModuleNotFound(err error) error {
-       err = errors.Wrap(ErrNotExist, err.Error())
+       err = fmt.Errorf(err.Error()+": %w", ErrNotExist)
        if c.GoModulesFilename == "" {
                return err
        }
@@ -681,9 +681,9 @@ func (c *collector) wrapModuleNotFound(err error) error {
 
        switch c.goBinaryStatus {
        case goBinaryStatusNotFound:
-               return errors.Wrap(err, baseMsg+" you need to install Go to use it. See https://golang.org/dl/.")
+               return fmt.Errorf(baseMsg+" you need to install Go to use it. See https://golang.org/dl/ : %q", err)
        case goBinaryStatusTooOld:
-               return errors.Wrap(err, baseMsg+" you need to a newer version of Go to use it. See https://golang.org/dl/.")
+               return fmt.Errorf(baseMsg+" you need to a newer version of Go to use it. See https://golang.org/dl/ : %w", err)
        }
 
        return err
index 04bf1b42206c85fbbf31078586e510da8f194b5e..08154bc110fa8413d563960c31c7b7de26252f2e 100644 (file)
@@ -18,8 +18,6 @@ import (
        "path/filepath"
        "strings"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/hugo"
 
        "github.com/gohugoio/hugo/config"
@@ -226,7 +224,7 @@ func decodeConfig(cfg config.Provider, pathReplacements map[string]string) (Conf
                        for _, repl := range c.Replacements {
                                parts := strings.Split(repl, "->")
                                if len(parts) != 2 {
-                                       return c, errors.Errorf(`invalid module.replacements: %q; configure replacement pairs on the form "oldpath->newpath" `, repl)
+                                       return c, fmt.Errorf(`invalid module.replacements: %q; configure replacement pairs on the form "oldpath->newpath" `, repl)
                                }
 
                                c.replacementsMap[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
index 911241813b32932815fb123b190162c5ca80c171..9bdc7eb78a9b9665754060262d60c8a16e09fb79 100644 (file)
@@ -24,8 +24,6 @@ import (
 
        "github.com/gohugoio/hugo/hugofs/files"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/hugofs"
        "github.com/spf13/afero"
 
@@ -57,7 +55,7 @@ func Pack(fs afero.Fs, fis []hugofs.FileMetaInfo) error {
                if err == nil {
                        // Preserve the original in package.hugo.json.
                        if err = hugio.CopyFile(fs, packageJSONName, files.FilenamePackageHugoJSON); err != nil {
-                               return errors.Wrap(err, "npm pack: failed to copy package file")
+                               return fmt.Errorf("npm pack: failed to copy package file: %w", err)
                        }
                } else {
                        // Create one.
@@ -83,7 +81,7 @@ func Pack(fs afero.Fs, fis []hugofs.FileMetaInfo) error {
        masterFilename := meta.Filename
        f, err := meta.Open()
        if err != nil {
-               return errors.Wrap(err, "npm pack: failed to open package file")
+               return fmt.Errorf("npm pack: failed to open package file: %w", err)
        }
        b = newPackageBuilder(meta.Module, f)
        f.Close()
@@ -106,14 +104,14 @@ func Pack(fs afero.Fs, fis []hugofs.FileMetaInfo) error {
 
                f, err := meta.Open()
                if err != nil {
-                       return errors.Wrap(err, "npm pack: failed to open package file")
+                       return fmt.Errorf("npm pack: failed to open package file: %w", err)
                }
                b.Add(meta.Module, f)
                f.Close()
        }
 
        if b.Err() != nil {
-               return errors.Wrap(b.Err(), "npm pack: failed to build")
+               return fmt.Errorf("npm pack: failed to build: %w", b.Err())
        }
 
        // Replace the dependencies in the original template with the merged set.
@@ -136,11 +134,11 @@ func Pack(fs afero.Fs, fis []hugofs.FileMetaInfo) error {
        encoder.SetEscapeHTML(false)
        encoder.SetIndent("", strings.Repeat(" ", 2))
        if err := encoder.Encode(b.originalPackageJSON); err != nil {
-               return errors.Wrap(err, "npm pack: failed to marshal JSON")
+               return fmt.Errorf("npm pack: failed to marshal JSON: %w", err)
        }
 
        if err := afero.WriteFile(fs, packageJSONName, packageJSONData.Bytes(), 0666); err != nil {
-               return errors.Wrap(err, "npm pack: failed to write package.json")
+               return fmt.Errorf("npm pack: failed to write package.json: %w", err)
        }
 
        return nil
index 02e1f8fec3fedde88b02099453b59912d76948ec..5e4996f39640db79df022f2f1435a4c5f5facb61 100644 (file)
@@ -19,8 +19,6 @@ import (
        "sort"
        "strings"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/common/types"
        "github.com/gohugoio/hugo/compare"
@@ -190,7 +188,7 @@ func (m *MenuEntry) MarshallMap(ime map[string]any) error {
        }
 
        if err != nil {
-               return errors.Wrapf(err, "failed to marshal menu entry %q", m.KeyName())
+               return fmt.Errorf("failed to marshal menu entry %q: %w", m.KeyName(), err)
        }
 
        return nil
index 46ed5221e6a3487508089187a106532c75344c32..7b4f6f6486c829183ca73f9214e2fda789c1562a 100644 (file)
 package navigation
 
 import (
+       "fmt"
+
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/common/types"
 
-       "github.com/pkg/errors"
        "github.com/spf13/cast"
 )
 
@@ -76,7 +77,7 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
        }
 
        var wrapErr = func(err error) error {
-               return errors.Wrapf(err, "unable to process menus for page %q", p.Path())
+               return fmt.Errorf("unable to process menus for page %q: %w", p.Path(), err)
        }
 
        // Could be a structured menu entry
index 34bec991185a5435de1535b0e1b17db8c366a3d6..1f1556eafe4a9947eae3c3dae2ae2fc5cc5fa055 100644 (file)
@@ -20,8 +20,6 @@ import (
        "sort"
        "strings"
 
-       "github.com/pkg/errors"
-
        "github.com/mitchellh/mapstructure"
 
        "github.com/gohugoio/hugo/media"
@@ -364,7 +362,7 @@ func decode(mediaTypes media.Types, input any, output *Format) error {
                                                        }
                                                        dataVal.SetMapIndex(key, reflect.ValueOf(mediaType))
                                                default:
-                                                       return nil, errors.Errorf("invalid output format configuration; wrong type for media type, expected string (e.g. text/html), got %T", vvi)
+                                                       return nil, fmt.Errorf("invalid output format configuration; wrong type for media type, expected string (e.g. text/html), got %T", vvi)
                                                }
                                        }
                                }
@@ -379,7 +377,7 @@ func decode(mediaTypes media.Types, input any, output *Format) error {
        }
 
        if err = decoder.Decode(input); err != nil {
-               return errors.Wrap(err, "failed to decode output format configuration")
+               return fmt.Errorf("failed to decode output format configuration: %w", err)
        }
 
        return nil
index 5bf96b2d88af13bf6d0ce08c4c4ac51d03349a8e..fe0581734eeba9b81bafdfb81d8ca5d57125aecc 100644 (file)
@@ -26,7 +26,6 @@ import (
 
        xml "github.com/clbanning/mxj/v2"
        toml "github.com/pelletier/go-toml/v2"
-       "github.com/pkg/errors"
        "github.com/spf13/afero"
        "github.com/spf13/cast"
        jww "github.com/spf13/jwalterweatherman"
@@ -74,7 +73,7 @@ func (d Decoder) UnmarshalToMap(data []byte, f Format) (map[string]any, error) {
 func (d Decoder) UnmarshalFileToMap(fs afero.Fs, filename string) (map[string]any, error) {
        format := FormatFromString(filename)
        if format == "" {
-               return nil, errors.Errorf("%q is not a valid configuration format", filename)
+               return nil, fmt.Errorf("%q is not a valid configuration format", filename)
        }
 
        data, err := afero.ReadFile(fs, filename)
@@ -106,7 +105,7 @@ func (d Decoder) UnmarshalStringTo(data string, typ any) (any, error) {
        case float64:
                return cast.ToFloat64E(data)
        default:
-               return nil, errors.Errorf("unmarshal: %T not supported", typ)
+               return nil, fmt.Errorf("unmarshal: %T not supported", typ)
        }
 }
 
@@ -144,7 +143,7 @@ func (d Decoder) UnmarshalTo(data []byte, f Format, v any) error {
                if err == nil {
                        xmlRootName, err := xmlRoot.Root()
                        if err != nil {
-                               return toFileError(f, errors.Wrap(err, "failed to unmarshal XML"))
+                               return toFileError(f, data, fmt.Errorf("failed to unmarshal XML: %w", err))
                        }
                        xmlValue = xmlRoot[xmlRootName].(map[string]any)
                }
@@ -160,7 +159,7 @@ func (d Decoder) UnmarshalTo(data []byte, f Format, v any) error {
        case YAML:
                err = yaml.Unmarshal(data, v)
                if err != nil {
-                       return toFileError(f, errors.Wrap(err, "failed to unmarshal YAML"))
+                       return toFileError(f, data, fmt.Errorf("failed to unmarshal YAML: %w", err))
                }
 
                // To support boolean keys, the YAML package unmarshals maps to
@@ -191,14 +190,14 @@ func (d Decoder) UnmarshalTo(data []byte, f Format, v any) error {
                return d.unmarshalCSV(data, v)
 
        default:
-               return errors.Errorf("unmarshal of format %q is not supported", f)
+               return fmt.Errorf("unmarshal of format %q is not supported", f)
        }
 
        if err == nil {
                return nil
        }
 
-       return toFileError(f, errors.Wrap(err, "unmarshal failed"))
+       return toFileError(f, data, fmt.Errorf("unmarshal failed: %w", err))
 }
 
 func (d Decoder) unmarshalCSV(data []byte, v any) error {
@@ -215,7 +214,7 @@ func (d Decoder) unmarshalCSV(data []byte, v any) error {
        case *any:
                *v.(*any) = records
        default:
-               return errors.Errorf("CSV cannot be unmarshaled into %T", v)
+               return fmt.Errorf("CSV cannot be unmarshaled into %T", v)
 
        }
 
@@ -260,8 +259,8 @@ func (d Decoder) unmarshalORG(data []byte, v any) error {
        return nil
 }
 
-func toFileError(f Format, err error) error {
-       return herrors.ToFileError(string(f), err)
+func toFileError(f Format, data []byte, err error) error {
+       return herrors.NewFileError(fmt.Sprintf("_stream.%s", f), err).UpdateContent(bytes.NewReader(data), nil)
 }
 
 // stringifyMapKeys recurses into in and changes all instances of
index 3338e063e1d8f5c4a4337ce961b3cf066b9fbf3c..bfbedcf26638f22da02b4f87d709c18448cab3c2 100644 (file)
@@ -15,11 +15,11 @@ package pageparser
 
 import (
        "bytes"
+       "fmt"
        "io"
        "io/ioutil"
 
        "github.com/gohugoio/hugo/parser/metadecoders"
-       "github.com/pkg/errors"
 )
 
 // Result holds the parse result.
@@ -102,7 +102,7 @@ func ParseMain(r io.Reader, cfg Config) (Result, error) {
 func parseSection(r io.Reader, cfg Config, start stateFunc) (Result, error) {
        b, err := ioutil.ReadAll(r)
        if err != nil {
-               return nil, errors.Wrap(err, "failed to read page content")
+               return nil, fmt.Errorf("failed to read page content: %w", err)
        }
        return parseBytes(b, cfg, start)
 }
index fc1fc0799fd177d39ce28cfb80597a106843898b..63eb1011f0de1bf8d57d93ca0c729fda8dd4d9a6 100644 (file)
@@ -15,6 +15,7 @@ package publisher
 
 import (
        "errors"
+       "fmt"
        "io"
        "net/url"
        "sync/atomic"
@@ -104,7 +105,7 @@ func (p DestinationPublisher) Publish(d Descriptor) error {
                defer bp.PutBuffer(b)
 
                if err := transformers.Apply(b, d.Src); err != nil {
-                       return err
+                       return fmt.Errorf("failed to process %q: %w", d.TargetPath, err)
                }
 
                // This is now what we write to disk.
index cdfba3c7a8684fef2a80dffd01ab4d17c36bb079..6bcfe3c8098f1293aab4b4080e49a48d2d46b254 100644 (file)
@@ -26,8 +26,9 @@ import (
 
        "github.com/gohugoio/hugo/common/hexec"
 
+       "errors"
+
        "github.com/gohugoio/hugo/common/hugo"
-       "github.com/pkg/errors"
 )
 
 const commitPrefix = "releaser:"
@@ -217,7 +218,7 @@ func (r *ReleaseHandler) release(releaseNotesFile string) error {
        cmd.Stderr = os.Stderr
        err := cmd.Run()
        if err != nil {
-               return errors.Wrap(err, "goreleaser failed")
+               return fmt.Errorf("goreleaser failed: %w", err)
        }
        return nil
 }
index 253caf735f353bddd6f0aef92b6668a5226d6c92..f431784b4a7a531f17d9652ceaf21f2580cd729a 100644 (file)
@@ -38,9 +38,6 @@ import (
 
        "github.com/gohugoio/hugo/resources/resource"
 
-       "github.com/pkg/errors"
-       _errors "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/helpers"
        "github.com/gohugoio/hugo/resources/images"
 
@@ -325,7 +322,7 @@ func (i *imageResource) doWithImageConfig(conf images.ImageConfig, f func(src im
        })
        if err != nil {
                if i.root != nil && i.root.getFileInfo() != nil {
-                       return nil, errors.Wrapf(err, "image %q", i.root.getFileInfo().Meta().Filename)
+                       return nil, fmt.Errorf("image %q: %w", i.root.getFileInfo().Meta().Filename, err)
                }
        }
        return img, nil
@@ -345,7 +342,7 @@ func (i *imageResource) decodeImageConfig(action, spec string) (images.ImageConf
 func (i *imageResource) DecodeImage() (image.Image, error) {
        f, err := i.ReadSeekCloser()
        if err != nil {
-               return nil, _errors.Wrap(err, "failed to open image for decode")
+               return nil, fmt.Errorf("failed to open image for decode: %w", err)
        }
        defer f.Close()
        img, _, err := image.Decode(f)
index 0a0db9fe0c55700d4a20d82c32fa4ad9dc4b7cc4..057a9fb71379c1ba362657dc9f09f0926892f760 100644 (file)
@@ -15,10 +15,9 @@ package images
 
 import (
        "encoding/hex"
+       "fmt"
        "image/color"
        "strings"
-
-       "github.com/pkg/errors"
 )
 
 // AddColorToPalette adds c as the first color in p if not already there.
@@ -50,7 +49,7 @@ func hexStringToColor(s string) (color.Color, error) {
        s = strings.TrimPrefix(s, "#")
 
        if len(s) != 3 && len(s) != 6 {
-               return nil, errors.Errorf("invalid color code: %q", s)
+               return nil, fmt.Errorf("invalid color code: %q", s)
        }
 
        s = strings.ToLower(s)
index d553bda0fc96313c80e7ad13a674c5105e9b4698..62b5c72d8cf9cfe52d9ca473fea2532684e2bec1 100644 (file)
@@ -22,7 +22,7 @@ import (
        "github.com/gohugoio/hugo/helpers"
        "github.com/gohugoio/hugo/media"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/bep/gowebp/libwebp/webpoptions"
 
@@ -158,7 +158,7 @@ func DecodeConfig(m map[string]any) (ImagingConfig, error) {
        if i.Cfg.Anchor != "" && i.Cfg.Anchor != smartCropIdentifier {
                anchor, found := anchorPositions[i.Cfg.Anchor]
                if !found {
-                       return i, errors.Errorf("invalid anchor value %q in imaging config", i.Anchor)
+                       return i, fmt.Errorf("invalid anchor value %q in imaging config", i.Anchor)
                }
                i.Anchor = anchor
        } else {
@@ -263,7 +263,7 @@ func DecodeImageConfig(action, config string, defaults ImagingConfig, sourceForm
                        return c, errors.New("must provide Width or Height")
                }
        default:
-               return c, errors.Errorf("BUG: unknown action %q encountered while decoding image configuration", c.Action)
+               return c, fmt.Errorf("BUG: unknown action %q encountered while decoding image configuration", c.Action)
        }
 
        if c.FilterStr == "" {
index e8cca7769886d1fe743fec157e9473418dc10a43..b12f03b4e33c50efc05130469c33d952c69b7f6e 100644 (file)
@@ -34,8 +34,9 @@ import (
        "golang.org/x/image/bmp"
        "golang.org/x/image/tiff"
 
+       "errors"
+
        "github.com/gohugoio/hugo/common/hugio"
-       "github.com/pkg/errors"
 )
 
 func NewImage(f Format, proc *ImageProcessor, img image.Image, s Spec) *Image {
@@ -163,7 +164,7 @@ func (i *Image) initConfig() error {
        })
 
        if err != nil {
-               return errors.Wrap(err, "failed to load image config")
+               return fmt.Errorf("failed to load image config: %w", err)
        }
 
        return nil
@@ -239,7 +240,7 @@ func (p *ImageProcessor) ApplyFiltersFromConfig(src image.Image, conf ImageConfi
        case "fit":
                filters = append(filters, gift.ResizeToFit(conf.Width, conf.Height, conf.Filter))
        default:
-               return nil, errors.Errorf("unsupported action: %q", conf.Action)
+               return nil, fmt.Errorf("unsupported action: %q", conf.Action)
        }
 
        img, err := p.Filter(src, filters...)
index 9d790cc014e29178625d83d00cd355634918b705..f4b40f717633a79d501a6aefc52cb2cf24b51dba 100644 (file)
@@ -20,7 +20,7 @@ import (
        "path/filepath"
        "reflect"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/common/maps"
 
@@ -55,15 +55,15 @@ var (
 
 func Generate(c *codegen.Inspector) error {
        if err := generateMarshalJSON(c); err != nil {
-               return errors.Wrap(err, "failed to generate JSON marshaler")
+               return fmt.Errorf("failed to generate JSON marshaler: %w", err)
        }
 
        if err := generateDeprecatedWrappers(c); err != nil {
-               return errors.Wrap(err, "failed to generate deprecate wrappers")
+               return fmt.Errorf("failed to generate deprecate wrappers: %w", err)
        }
 
        if err := generateFileIsZeroWrappers(c); err != nil {
-               return errors.Wrap(err, "failed to generate file wrappers")
+               return fmt.Errorf("failed to generate file wrappers: %w", err)
        }
 
        return nil
index 4626186c5cf3f115983dbc52cdfb2fc1ab5def1e..c302ff21a9a13bee45aaaa2dab6fc4810bbbe59d 100644 (file)
 package page
 
 import (
+       "fmt"
        "path/filepath"
        "strings"
 
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/hugofs/glob"
        "github.com/mitchellh/mapstructure"
-       "github.com/pkg/errors"
 )
 
 // A PageMatcher can be used to match a Page with Glob patterns.
@@ -132,7 +132,7 @@ func DecodePageMatcher(m any, v *PageMatcher) error {
                        }
                }
                if !found {
-                       return errors.Errorf("%q did not match a valid Page Kind", v.Kind)
+                       return fmt.Errorf("%q did not match a valid Page Kind", v.Kind)
                }
        }
 
index 83910e0d4d07de5f92aa065f40104472579fd4b5..35bb2965a3d38dedd9b370a2b90b81980928cabf 100644 (file)
 package page
 
 import (
+       "fmt"
        "sync"
 
        "github.com/gohugoio/hugo/common/types"
        "github.com/gohugoio/hugo/related"
-       "github.com/pkg/errors"
        "github.com/spf13/cast"
 )
 
@@ -108,7 +108,7 @@ func (p Pages) withInvertedIndex(search func(idx *related.InvertedIndex) ([]rela
 
        d, ok := p[0].(InternalDependencies)
        if !ok {
-               return nil, errors.Errorf("invalid type %T in related search", p[0])
+               return nil, fmt.Errorf("invalid type %T in related search", p[0])
        }
 
        cache := d.GetRelatedDocsHandler()
index aa20da4ed68bc72a4d0d2daa0c5b48dc9d5a3638..cd9c1dc1532f7ef4837058264bf312659a373b57 100644 (file)
@@ -23,7 +23,7 @@ import (
        "strings"
        "time"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/helpers"
 )
index 01f20f09d2f547ef52e91bd17f6438688ec0a3aa..ead483d65a189034c8b50ed873bcc54741c81beb 100644 (file)
@@ -31,7 +31,7 @@ import (
        "github.com/gohugoio/hugo/media"
        "github.com/gohugoio/hugo/source"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/common/hugio"
        "github.com/gohugoio/hugo/common/maps"
@@ -633,7 +633,7 @@ func (fi *resourceFileInfo) hash() (string, error) {
                var f hugio.ReadSeekCloser
                f, err = fi.ReadSeekCloser()
                if err != nil {
-                       err = errors.Wrap(err, "failed to open source file")
+                       err = fmt.Errorf("failed to open source file: %w", err)
                        return
                }
                defer f.Close()
index 32dfafe5cab93567d01678f377b9cdac3d5918dd..51199dc935b07925f220528728450a063ec27950 100644 (file)
@@ -16,6 +16,7 @@ package create
 import (
        "bufio"
        "bytes"
+       "fmt"
        "io"
        "io/ioutil"
        "mime"
@@ -34,7 +35,6 @@ import (
        "github.com/gohugoio/hugo/resources"
        "github.com/gohugoio/hugo/resources/resource"
        "github.com/mitchellh/mapstructure"
-       "github.com/pkg/errors"
 )
 
 type HTTPError struct {
@@ -77,7 +77,7 @@ func toHTTPError(err error, res *http.Response) *HTTPError {
 func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resource, error) {
        rURL, err := url.Parse(uri)
        if err != nil {
-               return nil, errors.Wrapf(err, "failed to parse URL for resource %s", uri)
+               return nil, fmt.Errorf("failed to parse URL for resource %s: %w", uri, err)
        }
 
        resourceID := calculateResourceID(uri, optionsm)
@@ -85,7 +85,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
        _, httpResponse, err := c.cacheGetResource.GetOrCreate(resourceID, func() (io.ReadCloser, error) {
                options, err := decodeRemoteOptions(optionsm)
                if err != nil {
-                       return nil, errors.Wrapf(err, "failed to decode options for resource %s", uri)
+                       return nil, fmt.Errorf("failed to decode options for resource %s: %w", uri, err)
                }
                if err := c.validateFromRemoteArgs(uri, options); err != nil {
                        return nil, err
@@ -93,7 +93,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
 
                req, err := http.NewRequest(options.Method, uri, options.BodyReader())
                if err != nil {
-                       return nil, errors.Wrapf(err, "failed to create request for resource %s", uri)
+                       return nil, fmt.Errorf("failed to create request for resource %s: %w", uri, err)
                }
                addDefaultHeaders(req)
 
@@ -113,7 +113,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
 
                if res.StatusCode != http.StatusNotFound {
                        if res.StatusCode < 200 || res.StatusCode > 299 {
-                               return nil, toHTTPError(errors.Errorf("failed to fetch remote resource: %s", http.StatusText(res.StatusCode)), res)
+                               return nil, toHTTPError(fmt.Errorf("failed to fetch remote resource: %s", http.StatusText(res.StatusCode)), res)
 
                        }
                }
@@ -137,7 +137,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
 
        body, err := ioutil.ReadAll(res.Body)
        if err != nil {
-               return nil, errors.Wrapf(err, "failed to read remote resource %q", uri)
+               return nil, fmt.Errorf("failed to read remote resource %q: %w", uri, err)
        }
 
        filename := path.Base(rURL.Path)
@@ -172,7 +172,7 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
        // Now resolve the media type primarily using the content.
        mediaType := media.FromContent(c.rs.MediaTypes, extensionHints, body)
        if mediaType.IsZero() {
-               return nil, errors.Errorf("failed to resolve media type for remote resource %q", uri)
+               return nil, fmt.Errorf("failed to resolve media type for remote resource %q", uri)
        }
 
        resourceID = filename[:len(filename)-len(path.Ext(filename))] + "_" + resourceID + mediaType.FirstSuffix.FullSuffix
index 6c979b4bfb252eb3793925dc8ffca2dce9ed30bc..8954a51092920de081f7aa97fd25dda14316ed9c 100644 (file)
@@ -22,7 +22,6 @@ import (
        "github.com/gohugoio/hugo/media"
        "github.com/gohugoio/hugo/resources/resource"
 
-       "github.com/pkg/errors"
        "github.com/spf13/cast"
 
        "github.com/gohugoio/hugo/common/maps"
@@ -85,7 +84,7 @@ func AssignMetadata(metadata []map[string]any, resources ...resource.Resource) e
 
                        glob, err := glob.GetGlob(srcKey)
                        if err != nil {
-                               return errors.Wrap(err, "failed to match resource with metadata")
+                               return fmt.Errorf("failed to match resource with metadata: %w", err)
                        }
 
                        match := glob.Match(resourceSrcKey)
index a4744961e08d479f441d34bec20192669309988d..9a9110f62bdd2a4853e80babb54caeef23d3d03d 100644 (file)
@@ -15,6 +15,7 @@ package babel
 
 import (
        "bytes"
+       "fmt"
        "io"
        "io/ioutil"
        "os"
@@ -34,7 +35,6 @@ import (
        "github.com/gohugoio/hugo/common/herrors"
        "github.com/gohugoio/hugo/resources"
        "github.com/gohugoio/hugo/resources/resource"
-       "github.com/pkg/errors"
 )
 
 // Options from https://babeljs.io/docs/en/options
@@ -141,7 +141,7 @@ func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx
                configFile = t.rs.BaseFs.ResolveJSConfigFile(configFile)
                if configFile == "" && t.options.Config != "" {
                        // Only fail if the user specified config file is not found.
-                       return errors.Errorf("babel config %q not found:", configFile)
+                       return fmt.Errorf("babel config %q not found:", configFile)
                }
        }
 
@@ -203,7 +203,7 @@ func (t *babelTransformation) Transform(ctx *resources.ResourceTransformationCtx
                if hexec.IsNotFound(err) {
                        return herrors.ErrFeatureNotAvailable
                }
-               return errors.Wrap(err, errBuf.String())
+               return fmt.Errorf(errBuf.String()+": %w", err)
        }
 
        content, err := ioutil.ReadAll(compileOutput)
index bbd0b6675cdca1a85d1ac5d364f795eee4b15624..e1575468581e5d90df370f07ae3936080b5f3ffa 100644 (file)
@@ -19,14 +19,13 @@ import (
        "crypto/sha512"
        "encoding/base64"
        "encoding/hex"
+       "fmt"
        "hash"
        "html/template"
        "io"
 
        "github.com/gohugoio/hugo/resources/internal"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/resources"
        "github.com/gohugoio/hugo/resources/resource"
 )
@@ -92,7 +91,7 @@ func newHash(algo string) (hash.Hash, error) {
        case "sha512":
                return sha512.New(), nil
        default:
-               return nil, errors.Errorf("unsupported crypto algo: %q, use either md5, sha256, sha384 or sha512", algo)
+               return nil, fmt.Errorf("unsupported crypto algo: %q, use either md5, sha256, sha384 or sha512", algo)
        }
 }
 
index 3c6f24fc072cca4a1f5a0d62604791028fca5b03..d2fbf5065a32311692b06c0b5a68b9671b719a65 100644 (file)
@@ -22,13 +22,14 @@ import (
        "regexp"
        "strings"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/spf13/afero"
 
        "github.com/gohugoio/hugo/hugofs"
 
        "github.com/gohugoio/hugo/common/herrors"
+       "github.com/gohugoio/hugo/common/text"
 
        "github.com/gohugoio/hugo/hugolib/filesystems"
        "github.com/gohugoio/hugo/media"
@@ -109,13 +110,13 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
                for i, ext := range opts.Inject {
                        impPath := filepath.FromSlash(ext)
                        if filepath.IsAbs(impPath) {
-                               return errors.Errorf("inject: absolute paths not supported, must be relative to /assets")
+                               return fmt.Errorf("inject: absolute paths not supported, must be relative to /assets")
                        }
 
                        m := resolveComponentInAssets(t.c.rs.Assets.Fs, impPath)
 
                        if m == nil {
-                               return errors.Errorf("inject: file %q not found", ext)
+                               return fmt.Errorf("inject: file %q not found", ext)
                        }
 
                        opts.Inject[i] = m.Filename
@@ -157,10 +158,12 @@ func (t *buildTransformation) Transform(ctx *resources.ResourceTransformationCtx
                        }
 
                        if err == nil {
-                               fe := herrors.NewFileError("js", 0, loc.Line, loc.Column, errors.New(msg.Text))
-                               err, _ := herrors.WithFileContext(fe, path, f, herrors.SimpleLineMatcher)
+                               fe := herrors.NewFileError(path, errors.New(msg.Text)).
+                                       UpdatePosition(text.Position{Offset: -1, LineNumber: loc.Line, ColumnNumber: loc.Column}).
+                                       UpdateContent(f, herrors.SimpleLineMatcher)
+
                                f.Close()
-                               return err
+                               return fe
                        }
 
                        return fmt.Errorf("%s", msg.Text)
index 675e40d43aeaae320eef0495764f0149a3232ab2..a0d1b506fddaa48cc15bf2910b742532e85ec7eb 100644 (file)
@@ -21,7 +21,6 @@ import (
        "strings"
 
        "github.com/gohugoio/hugo/common/maps"
-       "github.com/pkg/errors"
        "github.com/spf13/afero"
 
        "github.com/evanw/esbuild/pkg/api"
@@ -251,7 +250,7 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) {
                                func(args api.OnLoadArgs) (api.OnLoadResult, error) {
                                        b, err := ioutil.ReadFile(args.Path)
                                        if err != nil {
-                                               return api.OnLoadResult{}, errors.Wrapf(err, "failed to read %q", args.Path)
+                                               return api.OnLoadResult{}, fmt.Errorf("failed to read %q: %w", args.Path, err)
                                        }
                                        c := string(b)
                                        return api.OnLoadResult{
@@ -274,7 +273,7 @@ func createBuildPlugins(c *Client, opts Options) ([]api.Plugin, error) {
 
        b, err := json.Marshal(params)
        if err != nil {
-               return nil, errors.Wrap(err, "failed to marshal params")
+               return nil, fmt.Errorf("failed to marshal params: %w", err)
        }
        bs := string(b)
        paramsPlugin := api.Plugin{
index 61209fb23bc9406bd9f8e4fa4afa2670b47871df..733c958cfa96fe63b86f536c54e17b96ad12ef92 100644 (file)
@@ -17,6 +17,7 @@ import (
        "bytes"
        "crypto/sha256"
        "encoding/hex"
+       "fmt"
        "io"
        "io/ioutil"
        "path"
@@ -36,8 +37,9 @@ import (
        "github.com/spf13/afero"
        "github.com/spf13/cast"
 
+       "errors"
+
        "github.com/gohugoio/hugo/hugofs"
-       "github.com/pkg/errors"
 
        "github.com/mitchellh/mapstructure"
 
@@ -161,7 +163,7 @@ func (t *postcssTransformation) Transform(ctx *resources.ResourceTransformationC
                configFile = t.rs.BaseFs.ResolveJSConfigFile(configFile)
                if configFile == "" && t.options.Config != "" {
                        // Only fail if the user specified config file is not found.
-                       return errors.Errorf("postcss config %q not found:", configFile)
+                       return fmt.Errorf("postcss config %q not found:", configFile)
                }
        }
 
@@ -388,15 +390,9 @@ func (imp *importResolver) toFileError(output string) error {
        if err != nil {
                return inErr
        }
-       realFilename := fi.(hugofs.FileMetaInfo).Meta().Filename
-
-       ferr := herrors.NewFileError("css", -1, file.Offset+1, 1, inErr)
 
-       werr, ok := herrors.WithFileContextForFile(ferr, realFilename, file.Filename, imp.fs, herrors.SimpleLineMatcher)
+       realFilename := fi.(hugofs.FileMetaInfo).Meta().Filename
 
-       if !ok {
-               return ferr
-       }
+       return herrors.NewFileErrorFromFile(inErr, file.Filename, realFilename, hugofs.Os, herrors.SimpleLineMatcher)
 
-       return werr
 }
index 5c2033ff9a38e275e61352b0791224bed8dcb6a5..5fe4230f13361e44120adcb4184919f243d0fa9d 100644 (file)
 package templates
 
 import (
+       "fmt"
+
        "github.com/gohugoio/hugo/helpers"
        "github.com/gohugoio/hugo/resources"
        "github.com/gohugoio/hugo/resources/internal"
        "github.com/gohugoio/hugo/resources/resource"
        "github.com/gohugoio/hugo/tpl"
-       "github.com/pkg/errors"
 )
 
 // Client contains methods to perform template processing of Resource objects.
@@ -55,7 +56,7 @@ func (t *executeAsTemplateTransform) Transform(ctx *resources.ResourceTransforma
        tplStr := helpers.ReaderToString(ctx.From)
        templ, err := t.t.TextTmpl().Parse(ctx.InPath, tplStr)
        if err != nil {
-               return errors.Wrapf(err, "failed to parse Resource %q as Template:", ctx.InPath)
+               return fmt.Errorf("failed to parse Resource %q as Template:: %w", ctx.InPath, err)
        }
 
        ctx.OutPath = t.targetPath
index 79c32fcfdb67c7e4ddba3b26bf0b8e121a709cd7..082e30710a1d1d86451cc740028b16c8e5886e29 100644 (file)
@@ -120,18 +120,8 @@ func (t *transform) Transform(ctx *resources.ResourceTransformationCtx) error {
                                return m.Offset+len(m.Line) >= start.Offset && strings.Contains(m.Line, context)
                        }
 
-                       ferr, ok := herrors.WithFileContextForFile(
-                               herrors.NewFileError("scss", -1, -1, start.Column, sassErr),
-                               filename,
-                               filename,
-                               hugofs.Os,
-                               offsetMatcher)
-
-                       if !ok {
-                               return sassErr
-                       }
+                       return herrors.NewFileErrorFromFile(sassErr, filename, filename, hugofs.Os, offsetMatcher)
 
-                       return ferr
                }
                return err
        }
index 802798e59c7337a87c79b70bef697396c990ef6d..f9f4786f572bd14bd60a01cd700234327138702a 100644 (file)
@@ -28,7 +28,6 @@ import (
        "github.com/gohugoio/hugo/hugofs"
        "github.com/gohugoio/hugo/media"
        "github.com/gohugoio/hugo/resources"
-       "github.com/pkg/errors"
 )
 
 // Used in tests. This feature requires Hugo to be built with the extended tag.
@@ -172,7 +171,7 @@ func (c *Client) toCSS(options libsass.Options, dst io.Writer, src io.Reader) (l
        in := helpers.ReaderToString(src)
 
        // See https://github.com/gohugoio/hugo/issues/7059
-       // We need to preserver the regular CSS imports. This is by far
+       // We need to preserve the regular CSS imports. This is by far
        // a perfect solution, and only works for the main entry file, but
        // that should cover many use cases, e.g. using SCSS as a preprocessor
        // for Tailwind.
@@ -181,7 +180,7 @@ func (c *Client) toCSS(options libsass.Options, dst io.Writer, src io.Reader) (l
 
        res, err = transpiler.Execute(in)
        if err != nil {
-               return res, errors.Wrap(err, "SCSS processing failed")
+               return res, fmt.Errorf("SCSS processing failed: %w", err)
        }
 
        out := res.CSS
index e269b7b10d61d31145c03cc6fb32d86b6dc27d6f..a470c94daf4421c6d1bb08fa8fab70f9c5bf959c 100644 (file)
@@ -24,8 +24,6 @@ import (
 
        "github.com/gohugoio/hugo/common/paths"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/resources/images"
        "github.com/gohugoio/hugo/resources/images/exif"
        "github.com/spf13/afero"
@@ -431,10 +429,10 @@ func (r *resourceAdapter) transform(publish, setContent bool) error {
                                        errMsg = ". You need to install Babel, see https://gohugo.io/hugo-pipes/babel/"
                                }
 
-                               return errors.Wrap(err, msg+errMsg)
+                               return fmt.Errorf(msg+errMsg+": %w", err)
                        }
 
-                       return errors.Wrap(err, msg)
+                       return fmt.Errorf(msg+": %w", err)
                }
 
                var tryFileCache bool
@@ -461,7 +459,7 @@ func (r *resourceAdapter) transform(publish, setContent bool) error {
                                if err != nil {
                                        return newErr(err)
                                }
-                               return newErr(errors.Errorf("resource %q not found in file cache", key))
+                               return newErr(fmt.Errorf("resource %q not found in file cache", key))
                        }
                        transformedContentr = f
                        updates.sourceFs = cache.fileCache.Fs
index 13c4495bf26d6e712fc2ee14b0ceab5759cb95c2..f882eb898b04f810738ec65536051ff2049fdafa 100644 (file)
@@ -14,6 +14,7 @@
 package source
 
 import (
+       "fmt"
        "path/filepath"
        "strings"
        "sync"
@@ -22,8 +23,6 @@ import (
 
        "github.com/gohugoio/hugo/hugofs/files"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/hugio"
 
        "github.com/gohugoio/hugo/hugofs"
@@ -244,11 +243,11 @@ func (sp *SourceSpec) NewFileInfo(fi hugofs.FileMetaInfo) (*FileInfo, error) {
        relPath := m.Path
 
        if relPath == "" {
-               return nil, errors.Errorf("no Path provided by %v (%T)", m, m.Fs)
+               return nil, fmt.Errorf("no Path provided by %v (%T)", m, m.Fs)
        }
 
        if filename == "" {
-               return nil, errors.Errorf("no Filename provided by %v (%T)", m, m.Fs)
+               return nil, fmt.Errorf("no Filename provided by %v (%T)", m, m.Fs)
        }
 
        relDir := filepath.Dir(relPath)
index 4d509c56609dd44736ed70d82061ac27022871c3..79d027c5c489d871fb22c3fbd5b16f92f5290c6f 100644 (file)
 package source
 
 import (
+       "fmt"
        "path/filepath"
        "sync"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/hugofs"
 )
 
@@ -49,7 +48,7 @@ func (f *Filesystem) Files() ([]File, error) {
        f.filesInit.Do(func() {
                err := f.captureFiles()
                if err != nil {
-                       f.filesInitErr = errors.Wrap(err, "capture files")
+                       f.filesInitErr = fmt.Errorf("capture files: %w", err)
                }
        })
        return f.files, f.filesInitErr
index 24f43e62c39ec310f7fd35c002e08aec9b344760..516e2c272fb841d91f26c08b9cac44dc0398ccce 100644 (file)
@@ -24,12 +24,13 @@ import (
        "strings"
        "time"
 
+       "errors"
+
        "github.com/gohugoio/hugo/common/collections"
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/common/types"
        "github.com/gohugoio/hugo/deps"
        "github.com/gohugoio/hugo/helpers"
-       "github.com/pkg/errors"
        "github.com/spf13/cast"
 )
 
@@ -736,7 +737,7 @@ func (ns *Namespace) Uniq(seq any) (any, error) {
        case reflect.Array:
                slice = reflect.MakeSlice(reflect.SliceOf(v.Type().Elem()), 0, 0)
        default:
-               return nil, errors.Errorf("type %T not supported", seq)
+               return nil, fmt.Errorf("type %T not supported", seq)
        }
 
        seen := make(map[any]bool)
index abfc2da9cc2d1c75b16fc73b26895fccc6a36e12..4d408302b18bd5748cdd6c8c543d0ac6b9a0544f 100644 (file)
 package collections
 
 import (
+       "fmt"
        "reflect"
        "strings"
 
        "github.com/gohugoio/hugo/common/hreflect"
        "github.com/gohugoio/hugo/common/maps"
 
-       "github.com/pkg/errors"
+       "errors"
 )
 
 // Merge creates a copy of the final parameter and merges the preceding
@@ -49,7 +50,7 @@ func (ns *Namespace) merge(src, dst any) (any, error) {
        vdst, vsrc := reflect.ValueOf(dst), reflect.ValueOf(src)
 
        if vdst.Kind() != reflect.Map {
-               return nil, errors.Errorf("destination must be a map, got %T", dst)
+               return nil, fmt.Errorf("destination must be a map, got %T", dst)
        }
 
        if !hreflect.IsTruthfulValue(vsrc) {
@@ -57,11 +58,11 @@ func (ns *Namespace) merge(src, dst any) (any, error) {
        }
 
        if vsrc.Kind() != reflect.Map {
-               return nil, errors.Errorf("source must be a map, got %T", src)
+               return nil, fmt.Errorf("source must be a map, got %T", src)
        }
 
        if vsrc.Type().Key() != vdst.Type().Key() {
-               return nil, errors.Errorf("incompatible map types, got %T to %T", src, dst)
+               return nil, fmt.Errorf("incompatible map types, got %T to %T", src, dst)
        }
 
        return mergeMap(vdst, vsrc).Interface(), nil
index 4aa137e880f50b4a59c83377a596fac230d34708..4178850aa35fee9e91cef3514eeb242fd37f1e01 100644 (file)
@@ -18,8 +18,9 @@ import (
        "reflect"
        "time"
 
+       "errors"
+
        "github.com/mitchellh/hashstructure"
-       "github.com/pkg/errors"
 )
 
 var (
@@ -103,7 +104,7 @@ func convertValue(v reflect.Value, to reflect.Type) (reflect.Value, error) {
        case isNumber(kind):
                return convertNumber(v, kind)
        default:
-               return reflect.Value{}, errors.Errorf("%s is not assignable to %s", v.Type(), to)
+               return reflect.Value{}, fmt.Errorf("%s is not assignable to %s", v.Type(), to)
        }
 }
 
index 1c411bc35f0df9e1d51748f9aa99ace760df693c..8ecee3c4a9727b94fe57a320c211b94eb896f02f 100644 (file)
@@ -16,8 +16,6 @@ package collections
 import (
        "fmt"
        "reflect"
-
-       "github.com/pkg/errors"
 )
 
 // SymDiff returns the symmetric difference of s1 and s2.
@@ -54,7 +52,7 @@ func (ns *Namespace) SymDiff(s2, s1 any) (any, error) {
                                if ids1[key] != ids2[key] {
                                        v, err := convertValue(ev, sliceElemType)
                                        if err != nil {
-                                               return nil, errors.WithMessage(err, "symdiff: failed to convert value")
+                                               return nil, fmt.Errorf("symdiff: failed to convert value: %w", err)
                                        }
                                        slice = reflect.Append(slice, v)
                                }
index 5e03d52c37f05d3f3edeea81f7cd47313f084fee..926f6773d4b4cbf34561f37f12eece568a5a82cc 100644 (file)
@@ -20,6 +20,7 @@ import (
        "encoding/csv"
        "encoding/json"
        "errors"
+       "fmt"
        "net/http"
        "strings"
 
@@ -35,7 +36,6 @@ import (
 
        "github.com/gohugoio/hugo/cache/filecache"
        "github.com/gohugoio/hugo/deps"
-       _errors "github.com/pkg/errors"
 )
 
 // New returns a new instance of the data-namespaced template functions.
@@ -69,7 +69,7 @@ func (ns *Namespace) GetCSV(sep string, args ...any) (d [][]string, err error) {
 
        unmarshal := func(b []byte) (bool, error) {
                if d, err = parseCSV(b, sep); err != nil {
-                       err = _errors.Wrapf(err, "failed to parse CSV file %s", url)
+                       err = fmt.Errorf("failed to parse CSV file %s: %w", url, err)
 
                        return true, err
                }
@@ -80,7 +80,7 @@ func (ns *Namespace) GetCSV(sep string, args ...any) (d [][]string, err error) {
        var req *http.Request
        req, err = http.NewRequest("GET", url, nil)
        if err != nil {
-               return nil, _errors.Wrapf(err, "failed to create request for getCSV for resource %s", url)
+               return nil, fmt.Errorf("failed to create request for getCSV for resource %s: %w", url, err)
        }
 
        // Add custom user headers.
@@ -109,7 +109,7 @@ func (ns *Namespace) GetJSON(args ...any) (any, error) {
 
        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
-               return nil, _errors.Wrapf(err, "Failed to create request for getJSON resource %s", url)
+               return nil, fmt.Errorf("Failed to create request for getJSON resource %s: %w", url, err)
        }
 
        unmarshal := func(b []byte) (bool, error) {
index dca25efb236e213559209aebdca360596dc3632a..0470faf51ae9079bafcc65283cbab1e34c436904 100644 (file)
@@ -15,14 +15,13 @@ package data
 
 import (
        "bytes"
+       "fmt"
        "io/ioutil"
        "net/http"
        "net/url"
        "path/filepath"
        "time"
 
-       "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/cache/filecache"
 
        "github.com/gohugoio/hugo/config"
@@ -70,7 +69,7 @@ func (ns *Namespace) getRemote(cache *filecache.Cache, unmarshal func([]byte) (b
                        res.Body.Close()
 
                        if isHTTPError(res) {
-                               return nil, errors.Errorf("Failed to retrieve remote file: %s, body: %q", http.StatusText(res.StatusCode), b)
+                               return nil, fmt.Errorf("Failed to retrieve remote file: %s, body: %q", http.StatusText(res.StatusCode), b)
                        }
 
                        retry, err = unmarshal(b)
index 20af019cf61d605f799c942c2043f163832d5920..1abee1b0c409acde410fda9afc3c86016604c575 100644 (file)
@@ -18,7 +18,7 @@ import (
        "image"
        "sync"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/resources/images"
 
index d1c9bbb75ad16d4cf88ebcbb800c587794fe84ec..2d50c59a4ccfd2b61700a468107c085d38e331db 100644 (file)
@@ -19,8 +19,6 @@ import (
        "errors"
        "fmt"
 
-       _errors "github.com/pkg/errors"
-
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/resources"
 )
@@ -64,7 +62,7 @@ func ResolveArgs(args []any) (resources.ResourceTransformer, map[string]any, err
 
        m, err := maps.ToStringMapE(args[0])
        if err != nil {
-               return nil, nil, _errors.Wrap(err, "invalid options type")
+               return nil, nil, fmt.Errorf("invalid options type: %w", err)
        }
 
        return r, m, nil
index ee349bd1d70cc9ba423f3979e99d3a5c598b9989..17d37faa495286ec62aefce70bc10828f83cc8e0 100644 (file)
@@ -20,9 +20,10 @@ import (
        "strconv"
        "strings"
 
+       "errors"
+
        "github.com/gohugoio/locales"
        translators "github.com/gohugoio/localescompressed"
-       "github.com/pkg/errors"
 
        "github.com/gohugoio/hugo/common/hreflect"
        "github.com/gohugoio/hugo/deps"
@@ -49,7 +50,7 @@ func (ns *Namespace) Translate(id any, args ...any) (string, error) {
 
        if len(args) > 0 {
                if len(args) > 1 {
-                       return "", errors.Errorf("wrong number of arguments, expecting at most 2, got %d", len(args)+1)
+                       return "", fmt.Errorf("wrong number of arguments, expecting at most 2, got %d", len(args)+1)
                }
                templateData = args[0]
        }
index 27667388960db9d0b5e44eaeb3b74b6ade8a466b..1eea04b2562515d00532ba7adbe58cfa5aa9f698 100644 (file)
 package openapi3
 
 import (
+       "fmt"
        "io/ioutil"
 
        gyaml "github.com/ghodss/yaml"
 
-       "github.com/pkg/errors"
+       "errors"
 
        kopenapi3 "github.com/getkin/kin-openapi/openapi3"
        "github.com/gohugoio/hugo/cache/namedmemcache"
@@ -57,7 +58,7 @@ func (ns *Namespace) Unmarshal(r resource.UnmarshableResource) (*kopenapi3.T, er
        v, err := ns.cache.GetOrCreate(key, func() (any, error) {
                f := metadecoders.FormatFromMediaType(r.MediaType())
                if f == "" {
-                       return nil, errors.Errorf("MIME %q not supported", r.MediaType())
+                       return nil, fmt.Errorf("MIME %q not supported", r.MediaType())
                }
 
                reader, err := r.ReadSeekCloser()
index d3a98002fc5253dadff71c3998e3d812419e088f..2adec358ce81b36c5dba29bce4f858ae95a783ba 100644 (file)
@@ -20,8 +20,9 @@ import (
 
        "github.com/gohugoio/hugo/common/herrors"
 
+       "errors"
+
        "github.com/gohugoio/hugo/common/maps"
-       "github.com/pkg/errors"
 
        "github.com/gohugoio/hugo/tpl/internal/resourcehelpers"
 
@@ -162,7 +163,7 @@ func (ns *Namespace) GetRemote(args ...any) resource.Resource {
                case *create.HTTPError:
                        return resources.NewErrorResource(resource.NewResourceError(v, v.Data))
                default:
-                       return resources.NewErrorResource(resource.NewResourceError(errors.Wrap(err, "error calling resources.GetRemote"), make(map[string]any)))
+                       return resources.NewErrorResource(resource.NewResourceError(fmt.Errorf("error calling resources.GetRemote: %w", err), make(map[string]any)))
                }
 
        }
@@ -354,7 +355,7 @@ func (ns *Namespace) ToCSS(args ...any) (resource.Resource, error) {
                        case transpilerDart, transpilerLibSass:
                                transpiler = cast.ToString(t)
                        default:
-                               return nil, errors.Errorf("unsupported transpiler %q; valid values are %q or %q", t, transpilerLibSass, transpilerDart)
+                               return nil, fmt.Errorf("unsupported transpiler %q; valid values are %q or %q", t, transpilerLibSass, transpilerDart)
                        }
                }
        }
index 000490f857b193835d82f57a7701b6129f059d0f..482a8a837e98ceb564e8a00f6d8bb799baa647d9 100644 (file)
@@ -16,6 +16,7 @@ package strings
 
 import (
        "errors"
+       "fmt"
        "html/template"
        "regexp"
        "strings"
@@ -25,7 +26,6 @@ import (
        "github.com/gohugoio/hugo/deps"
        "github.com/gohugoio/hugo/helpers"
 
-       _errors "github.com/pkg/errors"
        "github.com/spf13/cast"
 )
 
@@ -48,7 +48,7 @@ type Namespace struct {
 func (ns *Namespace) CountRunes(s any) (int, error) {
        ss, err := cast.ToStringE(s)
        if err != nil {
-               return 0, _errors.Wrap(err, "Failed to convert content to string")
+               return 0, fmt.Errorf("Failed to convert content to string: %w", err)
        }
 
        counter := 0
@@ -65,7 +65,7 @@ func (ns *Namespace) CountRunes(s any) (int, error) {
 func (ns *Namespace) RuneCount(s any) (int, error) {
        ss, err := cast.ToStringE(s)
        if err != nil {
-               return 0, _errors.Wrap(err, "Failed to convert content to string")
+               return 0, fmt.Errorf("Failed to convert content to string: %w", err)
        }
        return utf8.RuneCountInString(ss), nil
 }
@@ -74,12 +74,12 @@ func (ns *Namespace) RuneCount(s any) (int, error) {
 func (ns *Namespace) CountWords(s any) (int, error) {
        ss, err := cast.ToStringE(s)
        if err != nil {
-               return 0, _errors.Wrap(err, "Failed to convert content to string")
+               return 0, fmt.Errorf("Failed to convert content to string: %w", err)
        }
 
        isCJKLanguage, err := regexp.MatchString(`\p{Han}|\p{Hangul}|\p{Hiragana}|\p{Katakana}`, ss)
        if err != nil {
-               return 0, _errors.Wrap(err, "Failed to match regex pattern against string")
+               return 0, fmt.Errorf("Failed to match regex pattern against string: %w", err)
        }
 
        if !isCJKLanguage {
@@ -104,11 +104,11 @@ func (ns *Namespace) CountWords(s any) (int, error) {
 func (ns *Namespace) Count(substr, s any) (int, error) {
        substrs, err := cast.ToStringE(substr)
        if err != nil {
-               return 0, _errors.Wrap(err, "Failed to convert substr to string")
+               return 0, fmt.Errorf("Failed to convert substr to string: %w", err)
        }
        ss, err := cast.ToStringE(s)
        if err != nil {
-               return 0, _errors.Wrap(err, "Failed to convert s to string")
+               return 0, fmt.Errorf("Failed to convert s to string: %w", err)
        }
        return strings.Count(ss, substrs), nil
 }
diff --git a/tpl/tplimpl/embedded/templates/server/error.html b/tpl/tplimpl/embedded/templates/server/error.html
new file mode 100644 (file)
index 0000000..e5c6d0c
--- /dev/null
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="no-js" lang="">
+  <head>
+    <meta charset="utf-8" />
+    <title>Hugo Server: Error</title>
+    <style type="text/css">
+      body {
+        font-family: "Muli", avenir, -apple-system, BlinkMacSystemFont,
+          "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
+          "Segoe UI Emoji", "Segoe UI Symbol";
+        font-size: 16px;
+        color: #48b685;
+        background-color: #2f1e2e;
+      }
+      main {
+        margin: auto;
+        width: 95%;
+        padding: 1rem;
+      }
+      .version {
+        color: #ccc;
+        padding: 1rem 0;
+      }
+      .stack {
+        margin-top: 4rem;
+      }
+      pre {
+        white-space: pre-wrap;
+        white-space: -moz-pre-wrap;
+        white-space: -pre-wrap;
+        white-space: -o-pre-wrap;
+        word-wrap: break-word;
+      }
+      .highlight {
+        overflow-x: auto;
+        margin-bottom: 1rem;
+      }
+      a {
+        color: #0594cb;
+        text-decoration: none;
+      }
+      a:hover {
+        color: #ccc;
+      }
+    </style>
+  </head>
+  <body>
+    <main>
+      {{ highlight .Error "apl" "linenos=false,noclasses=true,style=paraiso-dark" }}
+      {{ range $i, $e := .Files }}
+        {{ if not .ErrorContext }}
+          {{ continue }}
+        {{ end }}
+        {{ $params := printf "noclasses=true,style=paraiso-dark,linenos=table,hl_lines=%d,linenostart=%d" (add .ErrorContext.LinesPos 1) (sub .Position.LineNumber .ErrorContext.LinesPos) }}
+        {{ $lexer := .ErrorContext.ChromaLexer | default "go-html-template" }}
+        <h3><code>{{ path.Base .Position.Filename }}:</code></h3>
+        {{ highlight (delimit .ErrorContext.Lines "\n") $lexer $params }}
+      {{ end }}
+      <p class="version">{{ .Version }}</p>
+      <a href="">Reload Page</a>
+    </main>
+  </body>
+</html>
index 4cee19a2015f27327c6427e6464774e428cbd326..c092ff638165ea2c766519c245d8701fc7b5a713 100644 (file)
@@ -17,6 +17,7 @@ import (
        "bytes"
        "context"
        "embed"
+       "fmt"
        "io"
        "io/fs"
        "os"
@@ -42,7 +43,6 @@ import (
        "github.com/gohugoio/hugo/common/herrors"
        "github.com/gohugoio/hugo/hugofs"
        "github.com/gohugoio/hugo/hugofs/files"
-       "github.com/pkg/errors"
 
        htmltemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"
        texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
@@ -551,14 +551,10 @@ func (t *templateHandler) addFileContext(templ tpl.Template, inerr error) error
                }
                defer f.Close()
 
-               fe, ok := herrors.WithFileContext(inErr, info.realFilename, f, lineMatcher)
-               if ok {
-                       return fe, true
-               }
-               return inErr, false
+               return herrors.NewFileError(info.realFilename, inErr).UpdateContent(f, lineMatcher), true
        }
 
-       inerr = errors.Wrap(inerr, "execute of template failed")
+       inerr = fmt.Errorf("execute of template failed: %w", inerr)
 
        if err, ok := checkFilename(ts.info, inerr); ok {
                return err
@@ -736,6 +732,7 @@ func (t *templateHandler) extractIdentifiers(line string) []string {
 
 //go:embed embedded/templates/*
 //go:embed embedded/templates/_default/*
+//go:embed embedded/templates/server/*
 var embededTemplatesFs embed.FS
 
 func (t *templateHandler) loadEmbedded() error {
@@ -755,10 +752,10 @@ func (t *templateHandler) loadEmbedded() error {
                name := strings.TrimPrefix(filepath.ToSlash(path), "embedded/templates/")
                templateName := name
 
-               // For the render hooks it does not make sense to preseve the
+               // For the render hooks and the server templates it does not make sense to preseve the
                // double _indternal double book-keeping,
                // just add it if its now provided by the user.
-               if !strings.Contains(path, "_default/_markup") {
+               if !strings.Contains(path, "_default/_markup") && !strings.HasPrefix(name, "server/") {
                        templateName = internalPathPrefix + name
                }
 
index 33461dc7d2343382bb06db7f5f4abfcb689e285b..dee1fd6c2ecc030208d63e8f3379dd8e060e7d76 100644 (file)
@@ -14,6 +14,7 @@
 package tplimpl
 
 import (
+       "fmt"
        "regexp"
        "strings"
 
@@ -22,10 +23,11 @@ import (
 
        "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
 
+       "errors"
+
        "github.com/gohugoio/hugo/common/maps"
        "github.com/gohugoio/hugo/tpl"
        "github.com/mitchellh/mapstructure"
-       "github.com/pkg/errors"
 )
 
 type templateType int
@@ -239,14 +241,14 @@ func (c *templateContext) collectConfig(n *parse.PipeNode) {
        }
 
        if s, ok := cmd.Args[0].(*parse.StringNode); ok {
-               errMsg := "failed to decode $_hugo_config in template"
+               errMsg := "failed to decode $_hugo_config in template: %w"
                m, err := maps.ToStringMapE(s.Text)
                if err != nil {
-                       c.err = errors.Wrap(err, errMsg)
+                       c.err = fmt.Errorf(errMsg, err)
                        return
                }
                if err := mapstructure.WeakDecode(m, &c.t.parseInfo.Config); err != nil {
-                       c.err = errors.Wrap(err, errMsg)
+                       c.err = fmt.Errorf(errMsg, err)
                }
        }
 }
index 06d895536930e7409300a819c88b904f9ea0b9fc..d553a12e94a97cd2938a5835964e9e665e97c845 100644 (file)
@@ -14,8 +14,9 @@
 package tplimpl
 
 import (
+       "fmt"
+
        "github.com/gohugoio/hugo/common/herrors"
-       "github.com/pkg/errors"
        "github.com/spf13/afero"
 )
 
@@ -51,14 +52,13 @@ func (t templateInfo) resolveType() templateType {
 }
 
 func (info templateInfo) errWithFileContext(what string, err error) error {
-       err = errors.Wrapf(err, what)
-
-       err, _ = herrors.WithFileContextForFile(
-               err,
-               info.realFilename,
-               info.filename,
-               info.fs,
-               herrors.SimpleLineMatcher)
+       err = fmt.Errorf(what+": %w", err)
+       fe := herrors.NewFileError(info.realFilename, err)
+       f, err := info.fs.Open(info.filename)
+       if err != nil {
+               return err
+       }
+       defer f.Close()
+       return fe.UpdateContent(f, herrors.SimpleLineMatcher)
 
-       return err
 }
index b5d6821442a57bce6ade07f97c60556868c141c0..0ad54bb961a6757c6d2c5dbc4edf66cc05dd611b 100644 (file)
@@ -4,7 +4,7 @@ import (
        "bytes"
        "strings"
 
-       "github.com/pkg/errors"
+       "errors"
 
        "github.com/gohugoio/hugo/parser"
        "github.com/gohugoio/hugo/parser/metadecoders"
index 62682557c0aaaec651eab55eae042ef0c7e67b5d..340235fa4445abd3e2536304a84b68294f397005 100644 (file)
@@ -14,6 +14,7 @@
 package transform
 
 import (
+       "fmt"
        "io/ioutil"
        "strings"
 
@@ -23,9 +24,10 @@ import (
 
        "github.com/mitchellh/mapstructure"
 
+       "errors"
+
        "github.com/gohugoio/hugo/helpers"
        "github.com/gohugoio/hugo/parser/metadecoders"
-       "github.com/pkg/errors"
 
        "github.com/spf13/cast"
 )
@@ -54,7 +56,7 @@ func (ns *Namespace) Unmarshal(args ...any) (any, error) {
                data = args[1]
                decoder, err = decodeDecoder(m)
                if err != nil {
-                       return nil, errors.WithMessage(err, "failed to decode options")
+                       return nil, fmt.Errorf("failed to decode options: %w", err)
                }
        }
 
@@ -72,7 +74,7 @@ func (ns *Namespace) Unmarshal(args ...any) (any, error) {
                return ns.cache.GetOrCreate(key, func() (any, error) {
                        f := metadecoders.FormatFromMediaType(r.MediaType())
                        if f == "" {
-                               return nil, errors.Errorf("MIME %q not supported", r.MediaType())
+                               return nil, fmt.Errorf("MIME %q not supported", r.MediaType())
                        }
 
                        reader, err := r.ReadSeekCloser()
@@ -92,7 +94,7 @@ func (ns *Namespace) Unmarshal(args ...any) (any, error) {
 
        dataStr, err := types.ToStringE(data)
        if err != nil {
-               return nil, errors.Errorf("type %T not supported", data)
+               return nil, fmt.Errorf("type %T not supported", data)
        }
 
        if dataStr == "" {
@@ -160,7 +162,7 @@ func stringToRune(v any) (rune, error) {
                if i == 0 {
                        r = rr
                } else {
-                       return 0, errors.Errorf("invalid character: %q", v)
+                       return 0, fmt.Errorf("invalid character: %q", v)
                }
        }
 
index 3d6f67789aa3e1735c7c029d337418b7a43c1d1f..bfbd7304ffb13225b7b06cfb01a21b4bf36bce8f 100644 (file)
@@ -22,7 +22,6 @@ import (
 
        "github.com/gohugoio/hugo/common/urls"
        "github.com/gohugoio/hugo/deps"
-       _errors "github.com/pkg/errors"
        "github.com/spf13/cast"
 )
 
@@ -55,7 +54,7 @@ func (ns *Namespace) AbsURL(s any) (template.HTML, error) {
 func (ns *Namespace) Parse(rawurl any) (*url.URL, error) {
        s, err := cast.ToStringE(rawurl)
        if err != nil {
-               return nil, _errors.Wrap(err, "Error in Parse")
+               return nil, fmt.Errorf("Error in Parse: %w", err)
        }
 
        return url.Parse(s)
index 74217dc7226f0557dfe744f443a9edd85cfa4c0d..2d70b93562ce163e404e58606ae066a9dd7710bd 100644 (file)
@@ -16,8 +16,11 @@ package transform
 import (
        "bytes"
        "io"
+       "io/ioutil"
 
        bp "github.com/gohugoio/hugo/bufferpool"
+       "github.com/gohugoio/hugo/common/herrors"
+       "github.com/gohugoio/hugo/hugofs"
 )
 
 // Transformer is the func that needs to be implemented by a transformation step.
@@ -103,7 +106,17 @@ func (c *Chain) Apply(to io.Writer, from io.Reader) error {
                }
 
                if err := tr(fb); err != nil {
-                       return err
+                       // Write output to a temp file so it can be read by the user for trouble shooting.
+                       filename := "output.html"
+                       tempfile, ferr := ioutil.TempFile("", "hugo-transform-error")
+                       if ferr == nil {
+                               filename = tempfile.Name()
+                               defer tempfile.Close()
+                               _, _ = io.Copy(tempfile, fb.from)
+                               return herrors.NewFileErrorFromFile(err, filename, filename, hugofs.Os, nil)
+                       }
+                       return herrors.NewFileError(filename, err).UpdateContent(fb.from, nil)
+
                }
        }