hugo

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

git clone git://git.shimmy1996.com/hugo.git
commit 093dacab29a3c6fc363408453d0bc3b1fc159ad5
parent 4a9d408fe0bbf4c563546e35d2be7ade4e920c4c
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Tue, 22 Jun 2021 18:17:49 +0200

Fix language menu config regression

Fixes #8672

Diffstat:
Mconfig/defaultConfigProvider.go | 46++++++++++++++++++++++++++++++++++++++++++++--
Mhugolib/config.go | 14--------------
Mhugolib/config_test.go | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mhugolib/language_test.go | 25+++++++++++++++++++++++++
4 files changed, 135 insertions(+), 20 deletions(-)
diff --git a/config/defaultConfigProvider.go b/config/defaultConfigProvider.go
@@ -197,6 +197,12 @@ func (c *defaultConfigProvider) Merge(k string, v interface{}) {
 	defer c.mu.Unlock()
 	k = strings.ToLower(k)
 
+	const (
+		languagesKey = "languages"
+		paramsKey    = "params"
+		menusKey     = "menus"
+	)
+
 	if k == "" {
 		rs, f := c.root.GetMergeStrategy()
 		if f && rs == maps.ParamsMergeStrategyNone {
@@ -210,8 +216,44 @@ func (c *defaultConfigProvider) Merge(k string, v interface{}) {
 			// those as a special case.
 			for kk, vv := range p {
 				if pp, ok := vv.(maps.Params); ok {
-					if ppp, ok := c.root[kk]; ok {
-						ppp.(maps.Params).Merge(pp)
+					if pppi, ok := c.root[kk]; ok {
+						ppp := pppi.(maps.Params)
+						if kk == languagesKey {
+							// Languages is currently a special case.
+							// We may have languages with menus or params in the
+							// right map that is not present in the left map.
+							// With the default merge strategy those items will not
+							// be passed over.
+							var hasParams, hasMenus bool
+							for _, rv := range pp {
+								if lkp, ok := rv.(maps.Params); ok {
+									_, hasMenus = lkp[menusKey]
+									_, hasParams = lkp[paramsKey]
+								}
+							}
+
+							if hasMenus || hasParams {
+								for _, lv := range ppp {
+									if lkp, ok := lv.(maps.Params); ok {
+										if hasMenus {
+											if _, ok := lkp[menusKey]; !ok {
+												p := maps.Params{}
+												p.SetDefaultMergeStrategy(maps.ParamsMergeStrategyShallow)
+												lkp[menusKey] = p
+											}
+										}
+										if hasParams {
+											if _, ok := lkp[paramsKey]; !ok {
+												p := maps.Params{}
+												p.SetDefaultMergeStrategy(maps.ParamsMergeStrategyShallow)
+												lkp[paramsKey] = p
+											}
+										}
+									}
+								}
+							}
+						}
+						ppp.Merge(pp)
 					} else {
 						// We need to use the default merge strategy for
 						// this key.
diff --git a/hugolib/config.go b/hugolib/config.go
@@ -93,20 +93,6 @@ func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provid
 		}
 	}
 
-	// TODO(bep) improve this. This is currently needed to get the merge correctly.
-	if l.cfg.IsSet("languages") {
-		langs := l.cfg.GetParams("languages")
-		for _, lang := range langs {
-			langp := lang.(maps.Params)
-			if _, ok := langp["menus"]; !ok {
-				langp["menus"] = make(maps.Params)
-			}
-			if _, ok := langp["params"]; !ok {
-				langp["params"] = make(maps.Params)
-			}
-		}
-
-	}
 	l.cfg.SetDefaultMergeStrategy()
 
 	// We create languages based on the settings, so we need to make sure that
diff --git a/hugolib/config_test.go b/hugolib/config_test.go
@@ -76,7 +76,7 @@ func TestLoadMultiConfig(t *testing.T) {
 	c.Assert(cfg.GetString("DontChange"), qt.Equals, "same")
 }
 
-func TestLoadConfigFromTheme(t *testing.T) {
+func TestLoadConfigFromThemes(t *testing.T) {
 	t.Parallel()
 
 	c := qt.New(t)
@@ -185,11 +185,15 @@ name = "menu-theme"
 
 `
 
-	buildForStrategy := func(t testing.TB, s string) *sitesBuilder {
-		mainConfig := strings.ReplaceAll(mainConfigTemplate, "MERGE_PARAMS", s)
+	buildForConfig := func(mainConfig, themeConfig string) *sitesBuilder {
 		b := newTestSitesBuilder(t)
 		b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig)
-		return b.CreateSites().Build(BuildCfg{})
+		return b.Build(BuildCfg{})
+	}
+
+	buildForStrategy := func(t testing.TB, s string) *sitesBuilder {
+		mainConfig := strings.ReplaceAll(mainConfigTemplate, "MERGE_PARAMS", s)
+		return buildForConfig(mainConfig, themeConfig)
 	}
 
 	c.Run("Merge default", func(c *qt.C) {
@@ -316,6 +320,64 @@ name = "menu-theme"
 		})
 	})
 
+	c.Run("Merge no params in project", func(c *qt.C) {
+		b := buildForConfig(
+			"baseURL=\"https://example.org\"\ntheme = \"test-theme\"\n",
+			"[params]\np1 = \"p1 theme\"\n",
+		)
+
+		got := b.Cfg.Get("").(maps.Params)
+
+		b.Assert(got["params"], qt.DeepEquals, maps.Params{
+			"p1": "p1 theme",
+		})
+	})
+
+	c.Run("Merge language no menus or params in project", func(c *qt.C) {
+		b := buildForConfig(
+			`
+theme = "test-theme"
+baseURL = "https://example.com/"
+
+[languages]
+[languages.en]
+languageName = "English"
+
+`,
+			`
+[languages]
+[languages.en]
+languageName = "EnglishTheme"
+
+[languages.en.params]
+p1="themep1"
+
+[[languages.en.menus.main]]
+name   = "menu-theme"
+`,
+		)
+
+		got := b.Cfg.Get("").(maps.Params)
+
+		b.Assert(got["languages"], qt.DeepEquals,
+			maps.Params{
+				"en": maps.Params{
+					"languagename": "English",
+					"menus": maps.Params{
+						"main": []map[string]interface{}{
+							{
+								"name": "menu-theme",
+							},
+						},
+					},
+					"params": maps.Params{
+						"p1": "themep1",
+					},
+				},
+			},
+		)
+	})
+
 }
 
 func TestLoadConfigFromThemeDir(t *testing.T) {
diff --git a/hugolib/language_test.go b/hugolib/language_test.go
@@ -54,3 +54,28 @@ weight = 1
 		b.AssertFileContent("public/index.html", "Hello: Hello")
 	})
 }
+
+func TestLanguageBugs(t *testing.T) {
+	c := qt.New(t)
+
+	// Issue #8672
+	c.Run("Config with language, menu in root only", func(c *qt.C) {
+		b := newTestSitesBuilder(c)
+		b.WithConfigFile("toml", `
+theme = "test-theme"
+[[menus.foo]]
+name = "foo-a"
+[languages.en]
+
+`,
+		)
+
+		b.WithThemeConfigFile("toml", `[languages.en]`)
+
+		b.Build(BuildCfg{})
+
+		menus := b.H.Sites[0].Menus()
+		c.Assert(menus, qt.HasLen, 1)
+
+	})
+}