summaryrefslogtreecommitdiffstats
path: root/hugolib
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-10-21 12:20:21 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-10-22 20:46:14 +0200
commitd1661b823af25c50d3bbe5366ea40a3cdd52e237 (patch)
treecd84d18229fb9c294ff1be56d7c0ce92a8f46761 /hugolib
parent7930d2132a3c36c1aaca20f16f56978c84656b0a (diff)
hugolib: Continue the file context/line number errors work
See #5324
Diffstat (limited to 'hugolib')
-rw-r--r--hugolib/hugo_sites.go36
-rw-r--r--hugolib/hugo_sites_build.go75
-rw-r--r--hugolib/hugo_sites_build_errors_test.go87
-rw-r--r--hugolib/page.go53
-rw-r--r--hugolib/page_content.go35
-rw-r--r--hugolib/page_errors.go47
-rw-r--r--hugolib/shortcode.go30
-rw-r--r--hugolib/site.go39
-rw-r--r--hugolib/testhelpers_test.go6
9 files changed, 280 insertions, 128 deletions
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 7f70967d6..a184e8877 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -21,6 +21,7 @@ import (
"strings"
"sync"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/helpers"
@@ -53,6 +54,40 @@ type HugoSites struct {
gitInfo *gitInfo
}
+func (h *HugoSites) 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
+ }
+ }
+
+ // Log the rest, but add a threshold to avoid flooding the log.
+ const errLogThreshold = 5
+
+ for j, err := range errors {
+ if j == i || err == nil {
+ continue
+ }
+
+ if j >= errLogThreshold {
+ break
+ }
+
+ h.Log.ERROR.Println(err)
+ }
+
+ return errors[i]
+}
+
func (h *HugoSites) IsMultihost() bool {
return h != nil && h.multihost
}
@@ -636,6 +671,7 @@ func handleShortcodes(p *PageWithoutContent, rawContentCopy []byte) ([]byte, err
err := p.shortcodeState.executeShortcodesForDelta(p)
if err != nil {
+
return rawContentCopy, err
}
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index 13fbfd57e..4c275f55b 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -26,13 +26,29 @@ import (
// Build builds all sites. If filesystem events are provided,
// this is considered to be a potential partial rebuild.
func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
+ errCollector := h.StartErrorCollector()
+ errs := make(chan error)
+
+ go func(from, to chan error) {
+ var errors []error
+ i := 0
+ for e := range from {
+ i++
+ if i > 50 {
+ break
+ }
+ errors = append(errors, e)
+ }
+ to <- h.pickOneAndLogTheRest(errors)
+
+ close(to)
+
+ }(errCollector, errs)
if h.Metrics != nil {
h.Metrics.Reset()
}
- //t0 := time.Now()
-
// Need a pointer as this may be modified.
conf := &config
@@ -41,33 +57,46 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
conf.whatChanged = &whatChanged{source: true, other: true}
}
+ var prepareErr error
+
if !config.PartialReRender {
- for _, s := range h.Sites {
- s.Deps.BuildStartListeners.Notify()
- }
+ prepare := func() error {
+ for _, s := range h.Sites {
+ s.Deps.BuildStartListeners.Notify()
+ }
+
+ if len(events) > 0 {
+ // Rebuild
+ if err := h.initRebuild(conf); err != nil {
+ return err
+ }
+ } else {
+ if err := h.init(conf); err != nil {
+ return err
+ }
+ }
- if len(events) > 0 {
- // Rebuild
- if err := h.initRebuild(conf); err != nil {
+ if err := h.process(conf, events...); err != nil {
return err
}
- } else {
- if err := h.init(conf); err != nil {
+
+ if err := h.assemble(conf); err != nil {
return err
}
+ return nil
}
- if err := h.process(conf, events...); err != nil {
- return err
+ prepareErr = prepare()
+ if prepareErr != nil {
+ h.SendError(prepareErr)
}
- if err := h.assemble(conf); err != nil {
- return err
- }
}
- if err := h.render(conf); err != nil {
- return err
+ if prepareErr == nil {
+ if err := h.render(conf); err != nil {
+ h.SendError(err)
+ }
}
if h.Metrics != nil {
@@ -79,6 +108,18 @@ func (h *HugoSites) Build(config BuildCfg, events ...fsnotify.Event) error {
h.Log.FEEDBACK.Println()
}
+ select {
+ // Make sure the channel always gets something.
+ case errCollector <- nil:
+ default:
+ }
+ close(errCollector)
+
+ err := <-errs
+ if err != nil {
+ return err
+ }
+
errorCount := h.Log.ErrorCounter.Count()
if errorCount > 0 {
return fmt.Errorf("logged %d error(s)", errorCount)
diff --git a/hugolib/hugo_sites_build_errors_test.go b/hugolib/hugo_sites_build_errors_test.go
index 6b44bea88..2e8eb99ea 100644
--- a/hugolib/hugo_sites_build_errors_test.go
+++ b/hugolib/hugo_sites_build_errors_test.go
@@ -2,6 +2,7 @@ package hugolib
import (
"fmt"
+ "path/filepath"
"strings"
"testing"
@@ -17,13 +18,20 @@ type testSiteBuildErrorAsserter struct {
func (t testSiteBuildErrorAsserter) getFileError(err error) *herrors.ErrorWithFileContext {
t.assert.NotNil(err, t.name)
ferr := herrors.UnwrapErrorWithFileContext(err)
- t.assert.NotNil(ferr, fmt.Sprintf("[%s] got %T: %+v", t.name, err, err))
+ t.assert.NotNil(ferr, fmt.Sprintf("[%s] got %T: %+v\n%s", t.name, err, err, trace()))
return ferr
}
func (t testSiteBuildErrorAsserter) assertLineNumber(lineNumber int, err error) {
fe := t.getFileError(err)
- t.assert.Equal(lineNumber, fe.LineNumber, fmt.Sprintf("[%s] got => %s", t.name, fe))
+ t.assert.Equal(lineNumber, fe.LineNumber, fmt.Sprintf("[%s] got => %s\n%s", t.name, fe, trace()))
+}
+
+func (t testSiteBuildErrorAsserter) assertErrorMessage(e1, e2 string) {
+ // The error message will contain filenames with OS slashes. Normalize before compare.
+ e1, e2 = filepath.ToSlash(e1), filepath.ToSlash(e2)
+ t.assert.Equal(e1, e2, trace())
+
}
func TestSiteBuildErrors(t *testing.T) {
@@ -32,6 +40,7 @@ func TestSiteBuildErrors(t *testing.T) {
const (
yamlcontent = "yamlcontent"
+ tomlcontent = "tomlcontent"
shortcode = "shortcode"
base = "base"
single = "single"
@@ -55,7 +64,7 @@ func TestSiteBuildErrors(t *testing.T) {
return strings.Replace(content, ".Title }}", ".Title }", 1)
},
assertCreateError: func(a testSiteBuildErrorAsserter, err error) {
- a.assertLineNumber(2, err)
+ a.assertLineNumber(4, err)
},
},
{
@@ -65,7 +74,7 @@ func TestSiteBuildErrors(t *testing.T) {
return strings.Replace(content, ".Title", ".Titles", 1)
},
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
- a.assertLineNumber(2, err)
+ a.assertLineNumber(4, err)
},
},
{
@@ -75,7 +84,12 @@ func TestSiteBuildErrors(t *testing.T) {
return strings.Replace(content, ".Title }}", ".Title }", 1)
},
assertCreateError: func(a testSiteBuildErrorAsserter, err error) {
- a.assertLineNumber(3, err)
+ fe := a.getFileError(err)
+ assert.Equal(5, fe.LineNumber)
+ assert.Equal(1, fe.ColumnNumber)
+ assert.Equal("go-html-template", fe.ChromaLexer)
+ a.assertErrorMessage("\"layouts/_default/single.html:5:1\": parse failed: template: _default/single.html:5: unexpected \"}\" in operand", fe.Error())
+
},
},
{
@@ -85,7 +99,12 @@ func TestSiteBuildErrors(t *testing.T) {
return strings.Replace(content, ".Title", ".Titles", 1)
},
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
- a.assertLineNumber(3, err)
+ fe := a.getFileError(err)
+ assert.Equal(5, fe.LineNumber)
+ assert.Equal(14, fe.ColumnNumber)
+ assert.Equal("md", fe.ChromaLexer)
+ a.assertErrorMessage("asdfadf", fe.Error())
+
},
},
{
@@ -95,7 +114,7 @@ func TestSiteBuildErrors(t *testing.T) {
return strings.Replace(content, ".Title }}", ".Title }", 1)
},
assertCreateError: func(a testSiteBuildErrorAsserter, err error) {
- a.assertLineNumber(2, err)
+ a.assertLineNumber(4, err)
},
},
{
@@ -105,10 +124,47 @@ func TestSiteBuildErrors(t *testing.T) {
return strings.Replace(content, ".Title", ".Titles", 1)
},
assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
- a.assertLineNumber(25, err)
+ a.assertLineNumber(4, err)
},
},
+ {
+ name: "Shortode does not exist",
+ fileType: yamlcontent,
+ fileFixer: func(content string) string {
+ return strings.Replace(content, "{{< sc >}}", "{{< nono >}}", 1)
+ },
+ assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
+ fe := a.getFileError(err)
+ assert.Equal(7, fe.LineNumber)
+ assert.Equal(14, fe.ColumnNumber)
+ assert.Equal("md", fe.ChromaLexer)
+ a.assertErrorMessage("\"content/myyaml.md:7:14\": failed to extract shortcode: template for shortcode \"nono\" not found", fe.Error())
+ },
+ },
+ {
+ name: "Invalid YAML front matter",
+ fileType: yamlcontent,
+ fileFixer: func(content string) string {
+ // TODO(bep) 2errors YAML line numbers seems to be off by one for > 1 line.
+ return strings.Replace(content, "title:", "title", 1)
+ },
+ assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
+ a.assertLineNumber(2, err)
+ },
+ },
+ {
+ name: "Invalid TOML front matter",
+ fileType: tomlcontent,
+ fileFixer: func(content string) string {
+ return strings.Replace(content, "description = ", "description &", 1)
+ },
+ assertBuildError: func(a testSiteBuildErrorAsserter, err error) {
+ fe := a.getFileError(err)
+ assert.Equal(6, fe.LineNumber)
+ assert.Equal("toml", fe.ErrorContext.ChromaLexer)
+ },
+ },
{
name: "Panic in template Execute",
fileType: single,
@@ -166,7 +222,7 @@ title: "The YAML"
Some content.
-{{< sc >}}
+ {{< sc >}}
Some more text.
@@ -174,6 +230,19 @@ The end.
`))
+ b.WithContent("mytoml.md", f(tomlcontent, `+++
+title = "The TOML"
+p1 = "v"
+p2 = "v"
+p3 = "v"
+description = "Descriptioon"
++++
+
+Some content.
+
+
+`))
+
createErr := b.CreateSitesE()
if test.assertCreateError != nil {
test.assertCreateError(errorAsserter, createErr)
diff --git a/hugolib/page.go b/hugolib/page.go
index 74005e5a8..df6f88b01 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -20,11 +20,10 @@ import (
"fmt"
"reflect"
+ "github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/media"
_errors "github.com/pkg/errors"
- "github.com/gohugoio/hugo/common/maps"
-
"github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/related"
@@ -304,7 +303,7 @@ func (p *Page) initContent() {
if len(p.summary) == 0 {
if err = p.setAutoSummary(); err != nil {
- err = _errors.Wrapf(err, "Failed to set user auto summary for page %q:", p.pathOrTitle())
+ err = p.errorf(err, "failed to set auto summary")
}
}
c <- err
@@ -315,11 +314,11 @@ func (p *Page) initContent() {
p.s.Log.WARN.Printf("WARNING: Timed out creating content for page %q (.Content will be empty). This is most likely a circular shortcode content loop that should be fixed. If this is just a shortcode calling a slow remote service, try to set \"timeout=20000\" (or higher, value is in milliseconds) in config.toml.\n", p.pathOrTitle())
case err := <-c:
if err != nil {
- // TODO(bep) 2errors needs to be transported to the caller.
- p.s.Log.ERROR.Println(err)
+ p.s.SendError(err)
}
}
})
+
}
// This is sent to the shortcodes for this page. Not doing that will create an infinite regress. So,
@@ -560,11 +559,6 @@ func (ps Pages) findPagePos(page *Page) int {
return -1
}
-func (p *Page) createWorkContentCopy() {
- p.workContent = make([]byte, len(p.rawContent))
- copy(p.workContent, p.rawContent)
-}
-
func (p *Page) Plain() string {
p.initContent()
p.initPlain(true)
@@ -697,12 +691,6 @@ func (p *Page) UniqueID() string {
return p.File.UniqueID()
}
-// for logging
-// TODO(bep) 2errors remove
-func (p *Page) lineNumRawContentStart() int {
- return bytes.Count(p.frontmatter, []byte("\n")) + 1
-}
-
// Returns the page as summary and main.
func (p *Page) setUserDefinedSummary(rawContentCopy []byte) (*summaryContent, error) {
@@ -936,31 +924,18 @@ func (s *Site) NewPage(name string) (*Page, error) {
return p, nil
}
-func (p *Page) errorf(err error, format string, a ...interface{}) error {
- args := append([]interface{}{p.Lang(), p.pathOrTitle()}, a...)
- format = "[%s] Page %q: " + format
- if err == nil {
- return fmt.Errorf(format, args...)
- }
- return _errors.Wrapf(err, format, args...)
-}
-
func (p *Page) ReadFrom(buf io.Reader) (int64, error) {
// Parse for metadata & body
if err := p.parse(buf); err != nil {
- return 0, p.errorf(err, "parse failed")
+ return 0, p.errWithFileContext(err)
}
- // Work on a copy of the raw content from now on.
- // TODO(bep) 2errors
- //p.createWorkContentCopy()
-
if err := p.mapContent(); err != nil {
- return 0, err
+ return 0, p.errWithFileContext(err)
}
- return int64(len(p.rawContent)), nil
+ return int64(len(p.source.parsed.Input())), nil
}
func (p *Page) WordCount() int {
@@ -1169,7 +1144,7 @@ func (p *Page) initMainOutputFormat() error {
pageOutput, err := newPageOutput(p, false, false, outFormat)
if err != nil {
- return _errors.Wrapf(err, "Failed to create output page for type %q for page %q:", outFormat.Name, p.pathOrTitle())
+ return p.errorf(err, "failed to create output page for type %q", outFormat.Name)
}
p.mainPageOutput = pageOutput
@@ -1485,7 +1460,7 @@ func (p *Page) updateMetaData(frontmatter map[string]interface{}) error {
if isCJKLanguage != nil {
p.isCJKLanguage = *isCJKLanguage
} else if p.s.Cfg.GetBool("hasCJKLanguage") {
- if cjk.Match(p.rawContent) {
+ if cjk.Match(p.source.parsed.Input()) {
p.isCJKLanguage = true
} else {
p.isCJKLanguage = false
@@ -1711,7 +1686,8 @@ func (p *Page) shouldRenderTo(f output.Format) bool {
}
func (p *Page) RawContent() string {
- return string(p.rawContent)
+ // TODO(bep) 2errors
+ return string(p.source.parsed.Input())
}
func (p *Page) FullFilePath() string {
@@ -2145,12 +2121,7 @@ func (p *Page) setValuesForKind(s *Site) {
// Used in error logs.
func (p *Page) pathOrTitle() string {
if p.Filename() != "" {
- // Make a path relative to the working dir if possible.
- filename := strings.TrimPrefix(p.Filename(), p.s.WorkingDir)
- if filename != p.Filename() {
- filename = strings.TrimPrefix(filename, helpers.FilePathSeparator)
- }
- return filename
+ return p.Filename()
}
return p.title
}
diff --git a/hugolib/page_content.go b/hugolib/page_content.go
index 39abd0981..8c20db761 100644
--- a/hugolib/page_content.go
+++ b/hugolib/page_content.go
@@ -14,11 +14,14 @@
package hugolib
import (
- "fmt"
+ "bytes"
"io"
+ errors "github.com/pkg/errors"
+
bp "github.com/gohugoio/hugo/bufferpool"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/parser/metadecoders"
"github.com/gohugoio/hugo/parser/pageparser"
)
@@ -31,11 +34,6 @@ var (
type pageContent struct {
renderable bool
- frontmatter []byte
-
- // rawContent is the raw content read from the content file.
- rawContent []byte
-
// workContent is a copy of rawContent that may be mutated during site build.
workContent []byte
@@ -66,6 +64,10 @@ func (p *Page) mapContent() error {
iter := p.source.parsed.Iterator()
+ fail := func(err error, i pageparser.Item) error {
+ return parseError(err, iter.Input(), i.Pos)
+ }
+
// the parser is guaranteed to return items in proper order or fail, so …
// … it's safe to keep some "global" state
var currShortcode shortcode
@@ -87,7 +89,7 @@ Loop:
f := metadecoders.FormatFromFrontMatterType(it.Type)
m, err := metadecoders.UnmarshalToMap(it.Val, f)
if err != nil {
- return err
+ return herrors.ToFileErrorWithOffset(string(f), err, iter.LineNumber()-1)
}
if err := p.updateMetaData(m); err != nil {
return err
@@ -125,7 +127,7 @@ Loop:
}
if err != nil {
- return err
+ return fail(errors.Wrap(err, "failed to extract shortcode"), it)
}
if currShortcode.params == nil {
@@ -139,10 +141,10 @@ Loop:
case it.IsEOF():
break Loop
case it.IsError():
- err := fmt.Errorf("%s:shortcode:%d: %s",
- p.pathOrTitle(), iter.LineNumber(), it)
+ err := fail(errors.WithStack(errors.New(it.ValStr())), it)
currShortcode.err = err
return err
+
default:
result.Write(it.Val)
}
@@ -180,3 +182,16 @@ func (p *Page) parse(reader io.Reader) error {
return nil
}
+
+func parseError(err error, input []byte, pos int) error {
+ if herrors.UnwrapFileError(err) != nil {
+ // Use the most specific location.
+ return err
+ }
+ lf := []byte("\n")
+ input = input[:pos]
+ lineNumber := bytes.Count(input, lf) + 1
+ endOfLastLine := bytes.LastIndex(input, lf)
+ return herrors.NewFileError("md", lineNumber, pos-endOfLastLine, err)
+
+}
diff --git a/hugolib/page_errors.go b/hugolib/page_errors.go
new file mode 100644
index 000000000..42e2a8835
--- /dev/null
+++ b/hugolib/page_errors.go
@@ -0,0 +1,47 @@
+// Copyright 2018 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
+// 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
+// limitations under the License.
+
+package hugolib
+
+import (
+ "fmt"
+
+ "github.com/gohugoio/hugo/common/herrors"
+ errors "github.com/pkg/errors"
+)
+
+func (p *Page) errorf(err error, format string, a ...interface{}) error {
+ if herrors.UnwrapErrorWithFileContext(err) != nil {
+ // More isn't always better.
+ return err
+ }
+ args := append([]interface{}{p.Lang(), p.pathOrTitle()}, a...)
+ format = "[%s] page %q: " + format
+ if err == nil {
+ errors.Errorf(format, args...)
+ return fmt.Errorf(format, args...)
+ }
+ return errors.Wrapf(err, format, args...)
+}
+
+func (p *Page) errWithFileContext(err error) error {
+
+ err, _ = herrors.WithFileContextForFile(
+ err,
+ p.Filename(),
+ p.Filename(),
+ p.s.SourceSpec.Fs.Source,
+ herrors.SimpleLineMatcher)
+
+ return err
+}
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
index 749730236..024a919ed 100644
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -18,7 +18,9 @@ import (
"errors"
"fmt"
"html/template"
+
"reflect"
+
"regexp"
"sort"
@@ -139,6 +141,7 @@ type shortcode struct {
ordinal int
err error
doMarkup bool
+ pos int // the position in bytes in the source file
}
func (sc shortcode) String() string {
@@ -458,7 +461,13 @@ func (s *shortcodeHandler) executeShortcodesForDelta(p *PageWithoutContent) erro
render := s.contentShortcodesDelta.getShortcodeRenderer(k)
renderedShortcode, err := render()
if err != nil {
- return _errors.Wrapf(err, "Failed to execute shortcode in page %q:", p.Path())
+ sc := s.shortcodes.getShortcode(k.(scKey).ShortcodePlaceholder)
+ if sc != nil {
+ err = p.errWithFileContext(parseError(_errors.Wrapf(err, "failed to render shortcode %q", sc.name), p.source.parsed.Input(), sc.pos))
+ }
+
+ p.s.SendError(err)
+ continue
}
s.renderedShortcodes[k.(scKey).ShortcodePlaceholder] = renderedShortcode
@@ -495,15 +504,8 @@ func (s *shortcodeHandler) extractShortcode(ordinal int, pt *pageparser.Iterator
var cnt = 0
var nestedOrdinal = 0
- // TODO(bep) 2errors revisit after https://github.com/gohugoio/hugo/issues/5324
- msgf := func(i pageparser.Item, format string, args ...interface{}) string {
- format = format + ":%d:"
- // TODO(bep) 2errors
- c1 := 32 // strings.Count(pt.lexer.input[:i.pos], "\n") + 1
- c2 := bytes.Count(p.frontmatter, []byte{'\n'})
- args = append(args, c1+c2)
- return fmt.Sprintf(format, args...)
-
+ fail := func(err error, i pageparser.Item) error {
+ return parseError(err, pt.Input(), i.Pos)
}
Loop:
@@ -511,6 +513,7 @@ Loop:
currItem := pt.Next()
switch {
case currItem.IsLeftShortcodeDelim():
+ sc.pos = currItem.Pos
next := pt.Peek()
if next.IsShortcodeClose() {
continue
@@ -550,7 +553,8 @@ Loop:
// return that error, more specific
continue
}
- return sc, errors.New(msgf(next, "shortcode %q has no .Inner, yet a closing tag was provided", next.Val))
+
+ return sc, fail(_errors.Errorf("shortcode %q has no .Inner, yet a closing tag was provided", next.Val), next)
}
if next.IsRightShortcodeDelim() {
// self-closing
@@ -568,13 +572,13 @@ Loop:
// if more than one. It is "all inner or no inner".
tmpl := getShortcodeTemplateForTemplateKey(scKey{}, sc.name, p.s.Tmpl)
if tmpl == nil {
- return sc, errors.New(msgf(currItem, "unable to locate template for shortcode %q", sc.name))
+ return sc, fail(_errors.Errorf("template for shortcode %q not found", sc.name), currItem)
}
var err error
isInner, err = isInnerShortcode(tmpl.(tpl.TemplateExecutor))
if err != nil {
- return sc, _errors.Wrap(err, msgf(currItem, "failed to handle template for shortcode %q", sc.name))
+ return sc, fail(_errors.Wrapf(err, "failed to handle template for shortcode %q", sc.name), currItem)
}
case currItem.IsShortcodeParam():
diff --git a/hugolib/site.go b/hugolib/site.go
index 8358cf610..78a0070ee 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -30,7 +30,6 @@ import (
_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"
@@ -1552,7 +1551,7 @@ func (s *Site) preparePages() error {
}
}
- return s.pickOneAndLogTheRest(errors)
+ return s.owner.pickOneAndLogTheRest(errors)
}
func (s *Site) errorCollator(results <-chan error, errs chan<- error) {
@@ -1561,45 +1560,11 @@ func (s *Site) errorCollator(results <-chan error, errs chan<- error) {
errors = append(errors, e)
}
- errs <- s.pickOneAndLogTheRest(errors)
+ errs <- s.owner.pickOneAndLogTheRest(errors)
close(errs)
}
-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
- }
- }
-
- // 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)
- }
-
- return errors[i]
-}
-
func (s *Site) appendThemeTemplates(in []string) []string {
if !s.PathSpec.ThemeSet() {
return in
diff --git a/hugolib/testhelpers_test.go b/hugolib/testhelpers_test.go
index 70c9263b3..d37d83ed3 100644
--- a/hugolib/testhelpers_test.go
+++ b/hugolib/testhelpers_test.go
@@ -465,12 +465,16 @@ func (s *sitesBuilder) Fatalf(format string, args ...interface{}) {
}
func Fatalf(t testing.TB, format string, args ...interface{}) {
- trace := strings.Join(assert.CallerInfo(), "\n\r\t\t\t")
+ trace := trace()
format = format + "\n%s"
args = append(args, trace)
t.Fatalf(format, args...)
}
+func trace() string {
+ return strings.Join(assert.CallerInfo(), "\n\r\t\t\t")
+}
+
func (s *sitesBuilder) AssertFileContent(filename string, matches ...string) {
content := readDestination(s.T, s.Fs, filename)
for _, match := range matches {