hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit e3dc5240f01fd5ec67643e40f27c026d707da110
parent 268065cb2d8339392766a23703beaf7cc49d6b5c
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Fri, 30 Jul 2021 10:56:45 +0200

Improve handling of <nil> Params

Fixes #8825

Diffstat:
Mcommon/maps/maps.go | 6++++++
Mcommon/maps/maps_test.go | 10++++++++++
Mhugolib/menu_test.go | 19+++++++++++++++++++
Mhugolib/site.go | 18+++++++++++++-----
Mnavigation/menu.go | 20+++++++++++++++++---
Mnavigation/pagemenus.go | 12+++++++++---
6 files changed, 74 insertions(+), 11 deletions(-)
diff --git a/common/maps/maps.go b/common/maps/maps.go
@@ -17,6 +17,8 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/gohugoio/hugo/common/types"
+
 	"github.com/gobwas/glob"
 	"github.com/spf13/cast"
 )
@@ -39,8 +41,12 @@ func ToStringMapE(in interface{}) (map[string]interface{}, error) {
 }
 
 // ToParamsAndPrepare converts in to Params and prepares it for use.
+// If in is nil, an empty map is returned.
 // See PrepareParams.
 func ToParamsAndPrepare(in interface{}) (Params, bool) {
+	if types.IsNil(in) {
+		return Params{}, true
+	}
 	m, err := ToStringMapE(in)
 	if err != nil {
 		return nil, false
diff --git a/common/maps/maps_test.go b/common/maps/maps_test.go
@@ -114,6 +114,16 @@ func TestToSliceStringMap(t *testing.T) {
 	}
 }
 
+func TestToParamsAndPrepare(t *testing.T) {
+	c := qt.New(t)
+	_, ok := ToParamsAndPrepare(map[string]interface{}{"A": "av"})
+	c.Assert(ok, qt.IsTrue)
+
+	params, ok := ToParamsAndPrepare(nil)
+	c.Assert(ok, qt.IsTrue)
+	c.Assert(params, qt.DeepEquals, Params{})
+}
+
 func TestRenameKeys(t *testing.T) {
 	c := qt.New(t)
 
diff --git a/hugolib/menu_test.go b/hugolib/menu_test.go
@@ -350,6 +350,25 @@ menu:
 	b.AssertFileContent("public/index.html", "A|Children:C|B|")
 }
 
+// Issue #8825
+func TestMenuParamsEmptyYaml(t *testing.T) {
+	b := newTestSitesBuilder(t).WithConfigFile("yaml", `
+
+`)
+
+	b.WithTemplates("index.html", `{{ site.Menus }}`)
+
+	b.WithContent("p1.md", `---
+menus:
+  main: 
+    identity: journal
+    weight: 2
+    params:
+---	
+`)
+	b.Build(BuildCfg{})
+}
+
 func TestMenuParams(t *testing.T) {
 	b := newTestSitesBuilder(t).WithConfigFile("toml", `
 [[menus.main]]
diff --git a/hugolib/site.go b/hugolib/site.go
@@ -1400,17 +1400,25 @@ func (s *Site) getMenusFromConfig() navigation.Menus {
 				s.Log.Errorf("unable to process menus in site config\n")
 				s.Log.Errorln(err)
 			} else {
+				handleErr := func(err error) {
+					if err == nil {
+						return
+					}
+					s.Log.Errorf("unable to process menus in site config\n")
+					s.Log.Errorln(err)
+
+				}
+
 				for _, entry := range m {
 					s.Log.Debugf("found menu: %q, in site config\n", name)
 
 					menuEntry := navigation.MenuEntry{Menu: name}
 					ime, err := maps.ToStringMapE(entry)
-					if err != nil {
-						s.Log.Errorf("unable to process menus in site config\n")
-						s.Log.Errorln(err)
-					}
+					handleErr(err)
+
+					err = menuEntry.MarshallMap(ime)
+					handleErr(err)
 
-					menuEntry.MarshallMap(ime)
 					// TODO(bep) clean up all of this
 					menuEntry.ConfiguredURL = s.Info.createNodeMenuEntryURL(menuEntry.ConfiguredURL)
 
diff --git a/navigation/menu.go b/navigation/menu.go
@@ -14,10 +14,13 @@
 package navigation
 
 import (
+	"fmt"
 	"html/template"
 	"sort"
 	"strings"
 
+	"github.com/pkg/errors"
+
 	"github.com/gohugoio/hugo/common/maps"
 	"github.com/gohugoio/hugo/common/types"
 	"github.com/gohugoio/hugo/compare"
@@ -65,6 +68,7 @@ func (m *MenuEntry) URL() string {
 type Page interface {
 	LinkTitle() string
 	RelPermalink() string
+	Path() string
 	Section() string
 	Weight() int
 	IsPage() bool
@@ -127,7 +131,8 @@ func (m *MenuEntry) isSamePage(p Page) bool {
 	return false
 }
 
-func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
+func (m *MenuEntry) MarshallMap(ime map[string]interface{}) error {
+	var err error
 	for k, v := range ime {
 		loki := strings.ToLower(k)
 		switch loki {
@@ -150,10 +155,19 @@ func (m *MenuEntry) MarshallMap(ime map[string]interface{}) {
 		case "parent":
 			m.Parent = cast.ToString(v)
 		case "params":
-			m.Params = maps.MustToParamsAndPrepare(v)
-
+			var ok bool
+			m.Params, ok = maps.ToParamsAndPrepare(v)
+			if !ok {
+				err = fmt.Errorf("cannot convert %T to Params", v)
+			}
 		}
 	}
+
+	if err != nil {
+		return errors.Wrapf(err, "failed to marshal menu entry %q", m.KeyName())
+	}
+
+	return nil
 }
 
 func (m Menu) Add(me *MenuEntry) Menu {
diff --git a/navigation/pagemenus.go b/navigation/pagemenus.go
@@ -75,10 +75,14 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
 		return pm, nil
 	}
 
+	var wrapErr = func(err error) error {
+		return errors.Wrapf(err, "unable to process menus for page %q", p.Path())
+	}
+
 	// Could be a structured menu entry
 	menus, err := maps.ToStringMapE(ms)
 	if err != nil {
-		return pm, errors.Wrapf(err, "unable to process menus for %q", p.LinkTitle())
+		return pm, wrapErr(err)
 	}
 
 	for name, menu := range menus {
@@ -86,10 +90,12 @@ func PageMenusFromPage(p Page) (PageMenus, error) {
 		if menu != nil {
 			ime, err := maps.ToStringMapE(menu)
 			if err != nil {
-				return pm, errors.Wrapf(err, "unable to process menus for %q", p.LinkTitle())
+				return pm, wrapErr(err)
 			}
 
-			menuEntry.MarshallMap(ime)
+			if err = menuEntry.MarshallMap(ime); err != nil {
+				return pm, wrapErr(err)
+			}
 		}
 		pm[name] = &menuEntry
 	}