Skip to content

Commit f2946da

Browse files
committed
Improve error messages, esp. when the server is running
* Add file context to minifier errors when publishing * Misc fixes (see issues) * Allow custom server error template in layouts/server/error.html To get to this, this commit also cleans up and simplifies the code surrounding errors and files. This also removes the usage of `github.com/pkg/errors`, mostly because of pkg/errors#223 -- but also because most of this is now built-in to Go. Fixes gohugoio#9852 Fixes gohugoio#9857 Fixes gohugoio#9863
1 parent 6eea32b commit f2946da

File tree

109 files changed

+858
-777
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+858
-777
lines changed

cache/filecache/filecache_config.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package filecache
1515

1616
import (
17+
"fmt"
1718
"path"
1819
"path/filepath"
1920
"strings"
@@ -25,8 +26,9 @@ import (
2526

2627
"github.com/gohugoio/hugo/helpers"
2728

29+
"errors"
30+
2831
"github.com/mitchellh/mapstructure"
29-
"github.com/pkg/errors"
3032
"github.com/spf13/afero"
3133
)
3234

@@ -153,7 +155,7 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
153155
}
154156

155157
if err := decoder.Decode(v); err != nil {
156-
return nil, errors.Wrap(err, "failed to decode filecache config")
158+
return nil, fmt.Errorf("failed to decode filecache config: %w", err)
157159
}
158160

159161
if cc.Dir == "" {
@@ -162,7 +164,7 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
162164

163165
name := strings.ToLower(k)
164166
if !valid[name] {
165-
return nil, errors.Errorf("%q is not a valid cache name", name)
167+
return nil, fmt.Errorf("%q is not a valid cache name", name)
166168
}
167169

168170
c[name] = cc
@@ -197,12 +199,12 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
197199

198200
if !v.isResourceDir {
199201
if isOsFs && !filepath.IsAbs(v.Dir) {
200-
return c, errors.Errorf("%q must resolve to an absolute directory", v.Dir)
202+
return c, fmt.Errorf("%q must resolve to an absolute directory", v.Dir)
201203
}
202204

203205
// Avoid cache in root, e.g. / (Unix) or c:\ (Windows)
204206
if len(strings.TrimPrefix(v.Dir, filepath.VolumeName(v.Dir))) == 1 {
205-
return c, errors.Errorf("%q is a root folder and not allowed as cache dir", v.Dir)
207+
return c, fmt.Errorf("%q is a root folder and not allowed as cache dir", v.Dir)
206208
}
207209
}
208210

@@ -242,5 +244,5 @@ func resolveDirPlaceholder(fs afero.Fs, cfg config.Provider, placeholder string)
242244
return filepath.Base(workingDir), false, nil
243245
}
244246

245-
return "", false, errors.Errorf("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)", placeholder)
247+
return "", false, fmt.Errorf("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)", placeholder)
246248
}

cache/filecache/filecache_pruner.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
package filecache
1515

1616
import (
17+
"fmt"
1718
"io"
1819
"os"
1920

2021
"github.com/gohugoio/hugo/hugofs"
2122

22-
"github.com/pkg/errors"
2323
"github.com/spf13/afero"
2424
)
2525

@@ -39,7 +39,7 @@ func (c Caches) Prune() (int, error) {
3939
if os.IsNotExist(err) {
4040
continue
4141
}
42-
return counter, errors.Wrapf(err, "failed to prune cache %q", k)
42+
return counter, fmt.Errorf("failed to prune cache %q: %w", k, err)
4343
}
4444

4545
}

commands/commandeer.go

+4-13
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
package commands
1515

1616
import (
17-
"bytes"
1817
"errors"
1918
"io/ioutil"
2019
"net"
@@ -141,19 +140,11 @@ func (c *commandeer) getErrorWithContext() any {
141140

142141
m := make(map[string]any)
143142

144-
m["Error"] = errors.New(removeErrorPrefixFromLog(c.logger.Errors()))
143+
//xwm["Error"] = errors.New(cleanErrorLog(removeErrorPrefixFromLog(c.logger.Errors())))
144+
m["Error"] = errors.New(cleanErrorLog(removeErrorPrefixFromLog(c.logger.Errors())))
145145
m["Version"] = hugo.BuildVersionString()
146-
147-
fe := herrors.UnwrapErrorWithFileContext(c.buildErr)
148-
if fe != nil {
149-
m["File"] = fe
150-
}
151-
152-
if c.h.verbose {
153-
var b bytes.Buffer
154-
herrors.FprintStackTraceFromErr(&b, c.buildErr)
155-
m["StackTrace"] = b.String()
156-
}
146+
ferrors := herrors.UnwrapFileErrorsWithErrorContext(c.buildErr)
147+
m["Files"] = ferrors
157148

158149
return m
159150
}

commands/convert.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ import (
3131
"github.com/gohugoio/hugo/parser"
3232
"github.com/gohugoio/hugo/parser/metadecoders"
3333

34-
"github.com/pkg/errors"
35-
3634
"github.com/gohugoio/hugo/hugolib"
3735

3836
"github.com/spf13/cobra"
@@ -193,7 +191,7 @@ func (cc *convertCmd) convertAndSavePage(p page.Page, site *hugolib.Site, target
193191

194192
fs := hugofs.Os
195193
if err := helpers.WriteToDisk(newFilename, &newContent, fs); err != nil {
196-
return errors.Wrapf(err, "Failed to save file %q:", newFilename)
194+
return fmt.Errorf("Failed to save file %q:: %w", newFilename, err)
197195
}
198196

199197
return nil

commands/hugo.go

+7-12
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ import (
3939

4040
"github.com/gohugoio/hugo/resources/page"
4141

42-
"github.com/pkg/errors"
43-
44-
"github.com/gohugoio/hugo/common/herrors"
4542
"github.com/gohugoio/hugo/common/hugo"
4643
"github.com/gohugoio/hugo/common/loggers"
4744
"github.com/gohugoio/hugo/common/terminal"
@@ -300,14 +297,14 @@ func (c *commandeer) fullBuild(noBuildLock bool) error {
300297
copyStaticFunc := func() error {
301298
cnt, err := c.copyStatic()
302299
if err != nil {
303-
return errors.Wrap(err, "Error copying static files")
300+
return fmt.Errorf("Error copying static files: %w", err)
304301
}
305302
langCount = cnt
306303
return nil
307304
}
308305
buildSitesFunc := func() error {
309306
if err := c.buildSites(noBuildLock); err != nil {
310-
return errors.Wrap(err, "Error building site")
307+
return fmt.Errorf("Error building site: %w", err)
311308
}
312309
return nil
313310
}
@@ -354,10 +351,10 @@ func (c *commandeer) initCPUProfile() (func(), error) {
354351

355352
f, err := os.Create(c.h.cpuprofile)
356353
if err != nil {
357-
return nil, errors.Wrap(err, "failed to create CPU profile")
354+
return nil, fmt.Errorf("failed to create CPU profile: %w", err)
358355
}
359356
if err := pprof.StartCPUProfile(f); err != nil {
360-
return nil, errors.Wrap(err, "failed to start CPU profile")
357+
return nil, fmt.Errorf("failed to start CPU profile: %w", err)
361358
}
362359
return func() {
363360
pprof.StopCPUProfile()
@@ -388,11 +385,11 @@ func (c *commandeer) initTraceProfile() (func(), error) {
388385

389386
f, err := os.Create(c.h.traceprofile)
390387
if err != nil {
391-
return nil, errors.Wrap(err, "failed to create trace file")
388+
return nil, fmt.Errorf("failed to create trace file: %w", err)
392389
}
393390

394391
if err := trace.Start(f); err != nil {
395-
return nil, errors.Wrap(err, "failed to start trace")
392+
return nil, fmt.Errorf("failed to start trace: %w", err)
396393
}
397394

398395
return func() {
@@ -735,9 +732,7 @@ func (c *commandeer) handleBuildErr(err error, msg string) {
735732

736733
c.logger.Errorln(msg + ":\n")
737734
c.logger.Errorln(helpers.FirstUpper(err.Error()))
738-
if !c.h.quiet && c.h.verbose {
739-
herrors.PrintStackTraceFromErr(err)
740-
}
735+
741736
}
742737

743738
func (c *commandeer) rebuildSites(events []fsnotify.Event) error {

commands/new_site.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ package commands
1616
import (
1717
"bytes"
1818
"errors"
19+
"fmt"
1920
"path/filepath"
2021
"strings"
2122

2223
"github.com/gohugoio/hugo/config"
2324
"github.com/gohugoio/hugo/parser/metadecoders"
2425

25-
_errors "github.com/pkg/errors"
26-
2726
"github.com/gohugoio/hugo/create"
2827
"github.com/gohugoio/hugo/helpers"
2928
"github.com/gohugoio/hugo/hugofs"
@@ -94,7 +93,7 @@ func (n *newSiteCmd) doNewSite(fs *hugofs.Fs, basepath string, force bool) error
9493

9594
for _, dir := range dirs {
9695
if err := fs.Source.MkdirAll(dir, 0777); err != nil {
97-
return _errors.Wrap(err, "Failed to create dir")
96+
return fmt.Errorf("Failed to create dir: %w", err)
9897
}
9998
}
10099

commands/server.go

+21-9
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ import (
3636
"github.com/gohugoio/hugo/common/paths"
3737
"golang.org/x/sync/errgroup"
3838

39-
"github.com/pkg/errors"
40-
4139
"github.com/gohugoio/hugo/livereload"
4240

4341
"github.com/gohugoio/hugo/config"
@@ -366,7 +364,7 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, net.Listener, string
366364
// We're only interested in the path
367365
u, err := url.Parse(baseURL)
368366
if err != nil {
369-
return nil, nil, "", "", errors.Wrap(err, "Invalid baseURL")
367+
return nil, nil, "", "", fmt.Errorf("Invalid baseURL: %w", err)
370368
}
371369

372370
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{
480478
func removeErrorPrefixFromLog(content string) string {
481479
return logErrorRe.ReplaceAllLiteralString(content, "")
482480
}
481+
func cleanErrorLog(content string) string {
482+
content = strings.ReplaceAll(content, "Rebuild failed:\n", "")
483+
content = strings.ReplaceAll(content, "\n", "")
484+
seen := make(map[string]bool)
485+
parts := strings.Split(content, ": ")
486+
keep := make([]string, 0, len(parts))
487+
for _, part := range parts {
488+
if seen[part] {
489+
continue
490+
}
491+
seen[part] = true
492+
keep = append(keep, part)
493+
}
494+
return strings.Join(keep, ": ")
495+
}
483496

484497
func (c *commandeer) serve(s *serverCmd) error {
485498
isMultiHost := c.hugo().IsMultihost()
@@ -500,17 +513,16 @@ func (c *commandeer) serve(s *serverCmd) error {
500513
roots = []string{""}
501514
}
502515

503-
templ, err := c.hugo().TextTmpl().Parse("__default_server_error", buildErrorTemplate)
504-
if err != nil {
505-
return err
506-
}
507-
508516
srv := &fileServer{
509517
baseURLs: baseURLs,
510518
roots: roots,
511519
c: c,
512520
s: s,
513521
errorTemplate: func(ctx any) (io.Reader, error) {
522+
templ, found := c.hugo().Tmpl().Lookup("server/error.html")
523+
if !found {
524+
panic("template server/error.html not found")
525+
}
514526
b := &bytes.Buffer{}
515527
err := c.hugo().Tmpl().Execute(templ, b, ctx)
516528
return b, err
@@ -627,7 +639,7 @@ func (sc *serverCmd) fixURL(cfg config.Provider, s string, port int) (string, er
627639
if strings.Contains(u.Host, ":") {
628640
u.Host, _, err = net.SplitHostPort(u.Host)
629641
if err != nil {
630-
return "", errors.Wrap(err, "Failed to split baseURL hostpost")
642+
return "", fmt.Errorf("Failed to split baseURL hostpost: %w", err)
631643
}
632644
}
633645
u.Host += fmt.Sprintf(":%d", port)

commands/server_errors.go

-61
Original file line numberDiff line numberDiff line change
@@ -22,67 +22,6 @@ import (
2222
"github.com/gohugoio/hugo/transform/livereloadinject"
2323
)
2424

25-
var buildErrorTemplate = `<!doctype html>
26-
<html class="no-js" lang="">
27-
<head>
28-
<meta charset="utf-8">
29-
<title>Hugo Server: Error</title>
30-
<style type="text/css">
31-
body {
32-
font-family: "Muli",avenir, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
33-
font-size: 16px;
34-
background-color: #2f1e2e;
35-
}
36-
main {
37-
margin: auto;
38-
width: 95%;
39-
padding: 1rem;
40-
}
41-
.version {
42-
color: #ccc;
43-
padding: 1rem 0;
44-
}
45-
.stack {
46-
margin-top: 4rem;
47-
}
48-
pre {
49-
white-space: pre-wrap;
50-
white-space: -moz-pre-wrap;
51-
white-space: -pre-wrap;
52-
white-space: -o-pre-wrap;
53-
word-wrap: break-word;
54-
}
55-
.highlight {
56-
overflow-x: auto;
57-
margin-bottom: 1rem;
58-
}
59-
a {
60-
color: #0594cb;
61-
text-decoration: none;
62-
}
63-
a:hover {
64-
color: #ccc;
65-
}
66-
</style>
67-
</head>
68-
<body>
69-
<main>
70-
{{ highlight .Error "apl" "linenos=false,noclasses=true,style=paraiso-dark" }}
71-
{{ with .File }}
72-
{{ $params := printf "noclasses=true,style=paraiso-dark,linenos=table,hl_lines=%d,linenostart=%d" (add .LinesPos 1) (sub .Position.LineNumber .LinesPos) }}
73-
{{ $lexer := .ChromaLexer | default "go-html-template" }}
74-
{{ highlight (delimit .Lines "\n") $lexer $params }}
75-
{{ end }}
76-
{{ with .StackTrace }}
77-
{{ highlight . "apl" "noclasses=true,style=paraiso-dark" }}
78-
{{ end }}
79-
<p class="version">{{ .Version }}</p>
80-
<a href="">Reload Page</a>
81-
</main>
82-
</body>
83-
</html>
84-
`
85-
8625
func injectLiveReloadScript(src io.Reader, baseURL url.URL) string {
8726
var b bytes.Buffer
8827
chain := transform.Chain{livereloadinject.New(baseURL)}

0 commit comments

Comments
 (0)