From ed7b3e261909fe425ef64216f12806840c45b205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Mon, 22 Oct 2018 20:20:48 +0200 Subject: [PATCH] commands, hugolib: Get file context in "config parse failed" errors Fixes #5325 --- commands/hugo.go | 3 ++- go.mod | 1 - go.sum | 3 --- hugolib/config.go | 18 +++++++++++++++--- hugolib/hugo_sites_build_errors_test.go | 15 ++++++++++----- hugolib/page_bundler_test.go | 2 +- hugolib/page_test.go | 2 +- hugolib/shortcode_test.go | 12 ++++++------ 8 files changed, 35 insertions(+), 21 deletions(-) diff --git a/commands/hugo.go b/commands/hugo.go index acc48539d25..1cfbdcf7c1f 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -662,9 +662,10 @@ func (c *commandeer) fullRebuild() { c.commandeerHugoState = &commandeerHugoState{} err := c.loadConfig(true, true) if err != nil { - c.logger.ERROR.Println("Failed to reload config:", err) // Set the processing on pause until the state is recovered. c.paused = true + c.handleBuildErr(err, "Failed to reload config") + } else { c.paused = false } diff --git a/go.mod b/go.mod index b931009767e..8060a887633 100644 --- a/go.mod +++ b/go.mod @@ -63,7 +63,6 @@ require ( golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect golang.org/x/text v0.3.0 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 gopkg.in/yaml.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index 806cdc98a98..23e14989e7d 100644 --- a/go.sum +++ b/go.sum @@ -65,7 +65,6 @@ github.com/magefile/mage v1.4.0 h1:RI7B1CgnPAuu2O9lWszwya61RLmfL0KCdo+QyyI/Bhk= github.com/magefile/mage v1.4.0/go.mod h1:IUDi13rsHje59lecXokTfGX0QIzO45uVPlXnJYsXepA= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/markbates/inflect v0.0.0-20171215194931-a12c3aec81a6 h1:LZhVjIISSbj8qLf2qDPP0D8z0uvOWAW5C85ly5mJW6c= github.com/markbates/inflect v0.0.0-20171215194931-a12c3aec81a6/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -146,7 +145,5 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/hugolib/config.go b/hugolib/config.go index b21981304fa..32fa2dfca71 100644 --- a/hugolib/config.go +++ b/hugolib/config.go @@ -16,10 +16,11 @@ package hugolib import ( "errors" "fmt" - "io" "strings" + "github.com/gohugoio/hugo/common/herrors" + "github.com/gohugoio/hugo/hugolib/paths" _errors "github.com/pkg/errors" @@ -106,12 +107,23 @@ func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provid v.SetConfigFile(configFilenames[0]) v.AddConfigPath(d.Path) + applyFileContext := func(filename string, err error) error { + err, _ = herrors.WithFileContextForFile( + err, + filename, + filename, + fs, + herrors.SimpleLineMatcher) + + return err + } + var configFileErr error err := v.ReadInConfig() if err != nil { if _, ok := err.(viper.ConfigParseError); ok { - return nil, configFiles, err + return nil, configFiles, applyFileContext(v.ConfigFileUsed(), err) } configFileErr = ErrNoConfigFile } @@ -129,7 +141,7 @@ func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provid return nil, configFiles, fmt.Errorf("Unable to open Config file.\n (%s)\n", err) } if err = v.MergeConfig(r); err != nil { - return nil, configFiles, fmt.Errorf("Unable to parse/merge Config file (%s).\n (%s)\n", configFile, err) + return nil, configFiles, applyFileContext(configFile, err) } configFiles = append(configFiles, configFile) } diff --git a/hugolib/hugo_sites_build_errors_test.go b/hugolib/hugo_sites_build_errors_test.go index 2e8eb99eae3..f290022e041 100644 --- a/hugolib/hugo_sites_build_errors_test.go +++ b/hugolib/hugo_sites_build_errors_test.go @@ -30,7 +30,7 @@ func (t testSiteBuildErrorAsserter) assertLineNumber(lineNumber int, err error) 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()) + t.assert.Contains(e2, e1, trace()) } @@ -102,8 +102,8 @@ func TestSiteBuildErrors(t *testing.T) { fe := a.getFileError(err) assert.Equal(5, fe.LineNumber) assert.Equal(14, fe.ColumnNumber) - assert.Equal("md", fe.ChromaLexer) - a.assertErrorMessage("asdfadf", fe.Error()) + assert.Equal("go-html-template", fe.ChromaLexer) + a.assertErrorMessage("\"layouts/_default/single.html:5:14\": execute of template failed", fe.Error()) }, }, @@ -124,7 +124,12 @@ func TestSiteBuildErrors(t *testing.T) { return strings.Replace(content, ".Title", ".Titles", 1) }, assertBuildError: func(a testSiteBuildErrorAsserter, err error) { - a.assertLineNumber(4, err) + fe := a.getFileError(err) + assert.Equal(7, fe.LineNumber) + assert.Equal("md", fe.ChromaLexer) + // 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()) }, }, { @@ -173,7 +178,7 @@ func TestSiteBuildErrors(t *testing.T) { }, assertBuildError: func(a testSiteBuildErrorAsserter, err error) { assert.Error(err) - assert.Contains(err.Error(), "single.html") + assert.Contains(err.Error(), `"content/mytoml.md": render of "page" failed: execute of template failed: panic in Execute`) }, }, } diff --git a/hugolib/page_bundler_test.go b/hugolib/page_bundler_test.go index 39de49663eb..1eb5aacdd52 100644 --- a/hugolib/page_bundler_test.go +++ b/hugolib/page_bundler_test.go @@ -132,7 +132,7 @@ func TestPageBundlerSiteRegular(t *testing.T) { assert.Len(pageResources, 2) firstPage := pageResources[0].(*Page) secondPage := pageResources[1].(*Page) - assert.Equal(filepath.FromSlash("base/b/my-bundle/1.md"), firstPage.pathOrTitle(), secondPage.pathOrTitle()) + assert.Equal(filepath.FromSlash("/work/base/b/my-bundle/1.md"), firstPage.pathOrTitle(), secondPage.pathOrTitle()) assert.Contains(firstPage.content(), "TheContent") assert.Equal(6, len(leafBundle1.Resources)) diff --git a/hugolib/page_test.go b/hugolib/page_test.go index 7359140fcf7..ced7e78d882 100644 --- a/hugolib/page_test.go +++ b/hugolib/page_test.go @@ -1145,7 +1145,7 @@ func TestDegenerateInvalidFrontMatterShortDelim(t *testing.T) { r string err string }{ - {invalidFrontmatterShortDelimEnding, ":2: EOF looking for end YAML front matter delimiter"}, + {invalidFrontmatterShortDelimEnding, "EOF looking for end YAML front matter delimiter"}, } for _, test := range tests { s := newTestSite(t) diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go index 6e250ed21fb..0d397f9eeee 100644 --- a/hugolib/shortcode_test.go +++ b/hugolib/shortcode_test.go @@ -368,11 +368,11 @@ func TestExtractShortcodes(t *testing.T) { expectErrorMsg string }{ {"text", "Some text.", "map[]", "Some text.", ""}, - {"invalid right delim", "{{< tag }}", "", false, ":5:.*unrecognized character.*}"}, - {"invalid close", "\n{{< /tag >}}", "", false, ":6:.*got closing shortcode, but none is open"}, - {"invalid close2", "\n\n{{< tag >}}{{< /anotherTag >}}", "", false, ":7: closing tag for shortcode 'anotherTag' does not match start tag"}, - {"unterminated quote 1", `{{< figure src="im caption="S" >}}`, "", false, ":5:.got pos.*"}, - {"unterminated quote 1", `{{< figure src="im" caption="S >}}`, "", false, ":5:.*unterm.*}"}, + {"invalid right delim", "{{< tag }}", "", false, "unrecognized character"}, + {"invalid close", "\n{{< /tag >}}", "", false, "got closing shortcode, but none is open"}, + {"invalid close2", "\n\n{{< tag >}}{{< /anotherTag >}}", "", false, "closing tag for shortcode 'anotherTag' does not match start tag"}, + {"unterminated quote 1", `{{< figure src="im caption="S" >}}`, "", false, "got pos"}, + {"unterminated quote 1", `{{< figure src="im" caption="S >}}`, "", false, "unterm"}, {"one shortcode, no markup", "{{< tag >}}", "", testScPlaceholderRegexp, ""}, {"one shortcode, markup", "{{% tag %}}", "", testScPlaceholderRegexp, ""}, {"one pos param", "{{% tag param1 %}}", `tag([\"param1\"], true){[]}"]`, testScPlaceholderRegexp, ""}, @@ -430,7 +430,7 @@ func TestExtractShortcodes(t *testing.T) { if err == nil { t.Fatalf("[%d] %s: ExtractShortcodes didn't return an expected error", i, this.name) } else { - r, _ := regexp.Compile(this.expectErrorMsg) + r := regexp.MustCompile(this.expectErrorMsg) if !r.MatchString(err.Error()) { t.Fatalf("[%d] %s: ExtractShortcodes didn't return an expected error message, got\n%s but expected\n%s", i, this.name, err.Error(), this.expectErrorMsg)