summaryrefslogtreecommitdiffstats
path: root/hugolib/site.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-10-03 14:58:09 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-10-16 22:10:56 +0200
commit35fbfb19a173b01bc881f2bbc5d104136633a7ec (patch)
tree636d0d51fa262dc808eb3c5cc9cf92ad977a0c6a /hugolib/site.go
parent3a3089121b852332b5744d1f566959c8cf93cef4 (diff)
commands: Show server error info in browser
The main item in this commit is showing of errors with a file context when running `hugo server`. This can be turned off: `hugo server --disableBrowserError` (can also be set in `config.toml`). But to get there, the error handling in Hugo needed a revision. There are some items left TODO for commits soon to follow, most notable errors in content and config files. Fixes #5284 Fixes #5290 See #5325 See #5324
Diffstat (limited to 'hugolib/site.go')
-rw-r--r--hugolib/site.go105
1 files changed, 51 insertions, 54 deletions
diff --git a/hugolib/site.go b/hugolib/site.go
index 1196496d3..687c6338c 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -15,7 +15,6 @@ package hugolib
import (
"context"
- "errors"
"fmt"
"html/template"
"io"
@@ -29,6 +28,9 @@ import (
"strings"
"time"
+ _errors "github.com/pkg/errors"
+
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/publisher"
"github.com/gohugoio/hugo/resource"
@@ -754,8 +756,6 @@ func (s *Site) processPartial(events []fsnotify.Event) (whatChanged, error) {
return whatChanged{}, err
}
- s.TemplateHandler().PrintErrors()
-
for i := 1; i < len(sites); i++ {
site := sites[i]
var err error
@@ -861,7 +861,7 @@ func (s *Site) handleDataFile(r source.ReadableFile) error {
f, err := r.Open()
if err != nil {
- return fmt.Errorf("Failed to open data file %q: %s", r.LogicalName(), err)
+ return _errors.Wrapf(err, "Failed to open data file %q:", r.LogicalName())
}
defer f.Close()
@@ -942,7 +942,7 @@ func (s *Site) handleDataFile(r source.ReadableFile) error {
func (s *Site) readData(f source.ReadableFile) (interface{}, error) {
file, err := f.Open()
if err != nil {
- return nil, fmt.Errorf("readData: failed to open data file: %s", err)
+ return nil, _errors.Wrap(err, "readData: failed to open data file")
}
defer file.Close()
content := helpers.ReaderToBytes(file)
@@ -1558,26 +1558,52 @@ func (s *Site) preparePages() error {
}
}
- if len(errors) != 0 {
- return fmt.Errorf("Prepare pages failed: %.100q…", errors)
+ return s.pickOneAndLogTheRest(errors)
+}
+
+func (s *Site) errorCollator(results <-chan error, errs chan<- error) {
+ var errors []error
+ for e := range results {
+ errors = append(errors, e)
}
- return nil
+ errs <- s.pickOneAndLogTheRest(errors)
+
+ close(errs)
}
-func errorCollator(results <-chan error, errs chan<- error) {
- errMsgs := []string{}
- for err := range results {
- if err != nil {
- errMsgs = append(errMsgs, err.Error())
+func (s *Site) pickOneAndLogTheRest(errors []error) error {
+ if len(errors) == 0 {
+ return nil
+ }
+
+ var i int
+
+ 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 {
+ i = j
+ break
}
}
- if len(errMsgs) == 0 {
- errs <- nil
- } else {
- errs <- errors.New(strings.Join(errMsgs, "\n"))
+
+ // Log the rest, but add a threshold to avoid flooding the log.
+ const errLogThreshold = 5
+
+ for j, err := range errors {
+ if j == i {
+ continue
+ }
+
+ if j >= errLogThreshold {
+ break
+ }
+
+ s.Log.ERROR.Println(err)
}
- close(errs)
+
+ return errors[i]
}
func (s *Site) appendThemeTemplates(in []string) []string {
@@ -1650,8 +1676,7 @@ func (s *Site) renderAndWriteXML(statCounter *uint64, name string, targetPath st
renderBuffer.WriteString("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n")
if err := s.renderForLayouts(name, d, renderBuffer, layouts...); err != nil {
- helpers.DistinctWarnLog.Println(err)
- return nil
+ return err
}
var path string
@@ -1684,8 +1709,8 @@ func (s *Site) renderAndWritePage(statCounter *uint64, name string, targetPath s
defer bp.PutBuffer(renderBuffer)
if err := s.renderForLayouts(p.Kind, p, renderBuffer, layouts...); err != nil {
- helpers.DistinctWarnLog.Println(err)
- return nil
+
+ return err
}
if renderBuffer.Len() == 0 {
@@ -1735,46 +1760,18 @@ func (s *Site) renderAndWritePage(statCounter *uint64, name string, targetPath s
func (s *Site) renderForLayouts(name string, d interface{}, w io.Writer, layouts ...string) (err error) {
var templ tpl.Template
- defer func() {
- if r := recover(); r != nil {
- templName := ""
- if templ != nil {
- templName = templ.Name()
- }
- s.DistinctErrorLog.Printf("Failed to render %q: %s", templName, r)
- s.DistinctErrorLog.Printf("Stack Trace:\n%s", stackTrace(1200))
-
- // TOD(bep) we really need to fix this. Also see below.
- if !s.running() && !testMode {
- os.Exit(-1)
- }
- }
- }()
-
templ = s.findFirstTemplate(layouts...)
if templ == nil {
- return fmt.Errorf("[%s] Unable to locate layout for %q: %s\n", s.Language.Lang, name, layouts)
+ s.Log.WARN.Printf("[%s] Unable to locate layout for %q: %s\n", s.Language.Lang, name, layouts)
+ return nil
}
if err = templ.Execute(w, d); err != nil {
- // Behavior here should be dependent on if running in server or watch mode.
if p, ok := d.(*PageOutput); ok {
- if p.File != nil {
- s.DistinctErrorLog.Printf("Error while rendering %q in %q: %s", name, p.File.Dir(), err)
- } else {
- s.DistinctErrorLog.Printf("Error while rendering %q: %s", name, err)
- }
- } else {
- s.DistinctErrorLog.Printf("Error while rendering %q: %s", name, err)
- }
- if !s.running() && !testMode {
- // TODO(bep) check if this can be propagated
- os.Exit(-1)
- } else if testMode {
- return
+ return p.errorf(err, "render of %q failed", name)
}
+ return _errors.Wrapf(err, "render of %q failed", name)
}
-
return
}