mirror of
https://github.com/gohugoio/hugo.git
synced 2025-12-13 20:36:04 +01:00
@@ -14,7 +14,9 @@
|
||||
package maps
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
xmaps "maps"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
@@ -101,7 +103,6 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
|
||||
noUpdate = noUpdate || (ps != "" && ps == ParamsMergeStrategyShallow)
|
||||
|
||||
for k, v := range pp {
|
||||
|
||||
if k == MergeStrategyKey {
|
||||
continue
|
||||
}
|
||||
@@ -115,6 +116,9 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
|
||||
}
|
||||
}
|
||||
} else if !noUpdate {
|
||||
if vvv, ok := v.(Params); ok {
|
||||
v = xmaps.Clone(vvv)
|
||||
}
|
||||
p[k] = v
|
||||
}
|
||||
|
||||
@@ -266,9 +270,17 @@ func CleanConfigStringMapString(m map[string]string) map[string]string {
|
||||
// CleanConfigStringMap is the same as CleanConfigStringMapString but for
|
||||
// map[string]any.
|
||||
func CleanConfigStringMap(m map[string]any) map[string]any {
|
||||
return doCleanConfigStringMap(m, 0)
|
||||
}
|
||||
|
||||
func doCleanConfigStringMap(m map[string]any, depth int) map[string]any {
|
||||
if len(m) == 0 {
|
||||
return m
|
||||
}
|
||||
const maxDepth = 1000
|
||||
if depth > maxDepth {
|
||||
panic(errors.New("max depth exceeded"))
|
||||
}
|
||||
if _, found := m[MergeStrategyKey]; !found {
|
||||
return m
|
||||
}
|
||||
@@ -280,9 +292,9 @@ func CleanConfigStringMap(m map[string]any) map[string]any {
|
||||
}
|
||||
switch v2 := v.(type) {
|
||||
case map[string]any:
|
||||
m2[k] = CleanConfigStringMap(v2)
|
||||
m2[k] = doCleanConfigStringMap(v2, depth+1)
|
||||
case Params:
|
||||
var p Params = CleanConfigStringMap(v2)
|
||||
var p Params = doCleanConfigStringMap(v2, depth+1)
|
||||
m2[k] = p
|
||||
case map[string]string:
|
||||
m2[k] = CleanConfigStringMapString(v2)
|
||||
|
||||
@@ -56,7 +56,7 @@ import (
|
||||
"github.com/gohugoio/hugo/resources/page/pagemeta"
|
||||
"github.com/spf13/afero"
|
||||
|
||||
xmaps "golang.org/x/exp/maps"
|
||||
xmaps "maps"
|
||||
)
|
||||
|
||||
// InternalConfig is the internal configuration for Hugo, not read from any user provided config file.
|
||||
@@ -1054,6 +1054,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
mergedConfig := config.New()
|
||||
var differentRootKeys []string
|
||||
switch x := v.(type) {
|
||||
case nil:
|
||||
case maps.Params:
|
||||
_, found := x["params"]
|
||||
if !found {
|
||||
@@ -1129,6 +1130,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
|
||||
|
||||
langConfigMap[k] = clone
|
||||
case maps.ParamsMergeStrategy:
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type in languages config: %T", v))
|
||||
|
||||
|
||||
@@ -40,7 +40,13 @@ import (
|
||||
//lint:ignore ST1005 end user message.
|
||||
var ErrNoConfigFile = errors.New("Unable to locate config file or config directory. Perhaps you need to create a new site.\n Run `hugo help new` for details.\n")
|
||||
|
||||
func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
|
||||
func LoadConfig(d ConfigSourceDescriptor) (configs *Configs, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("failed to load config: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
if len(d.Environ) == 0 && !hugo.IsRunningAsTest() {
|
||||
d.Environ = os.Environ()
|
||||
}
|
||||
@@ -59,7 +65,7 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
|
||||
return nil, fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
configs, err := fromLoadConfigResult(d.Fs, d.Logger, res)
|
||||
configs, err = fromLoadConfigResult(d.Fs, d.Logger, res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create config from result: %w", err)
|
||||
}
|
||||
@@ -93,7 +99,7 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
|
||||
|
||||
loggers.SetGlobalLogger(d.Logger)
|
||||
|
||||
return configs, nil
|
||||
return
|
||||
}
|
||||
|
||||
// ConfigSourceDescriptor describes where to find the config (e.g. config.toml etc.).
|
||||
@@ -538,11 +544,12 @@ func (l configLoader) loadConfig(configName string) (string, error) {
|
||||
return filename, nil
|
||||
}
|
||||
|
||||
func (l configLoader) deleteMergeStrategies() {
|
||||
func (l configLoader) deleteMergeStrategies() (err error) {
|
||||
l.cfg.WalkParams(func(params ...maps.KeyParams) bool {
|
||||
params[len(params)-1].Params.DeleteMergeStrategy()
|
||||
return false
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (l configLoader) wrapFileError(err error, filename string) error {
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
xmaps "golang.org/x/exp/maps"
|
||||
xmaps "maps"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
|
||||
@@ -237,12 +239,16 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
|
||||
func (c *defaultConfigProvider) Keys() []string {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return xmaps.Keys(c.root)
|
||||
return slices.Collect(xmaps.Keys(c.root))
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...maps.KeyParams) bool) {
|
||||
var walk func(params ...maps.KeyParams)
|
||||
walk = func(params ...maps.KeyParams) {
|
||||
maxDepth := 1000
|
||||
var walk func(depth int, params ...maps.KeyParams)
|
||||
walk = func(depth int, params ...maps.KeyParams) {
|
||||
if depth > maxDepth {
|
||||
panic(errors.New("max depth exceeded"))
|
||||
}
|
||||
if walkFn(params...) {
|
||||
return
|
||||
}
|
||||
@@ -253,11 +259,11 @@ func (c *defaultConfigProvider) WalkParams(walkFn func(params ...maps.KeyParams)
|
||||
paramsplus1 := make([]maps.KeyParams, i+1)
|
||||
copy(paramsplus1, params)
|
||||
paramsplus1[i] = maps.KeyParams{Key: k, Params: p2}
|
||||
walk(paramsplus1...)
|
||||
walk(depth+1, paramsplus1...)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(maps.KeyParams{Key: "", Params: c.root})
|
||||
walk(0, maps.KeyParams{Key: "", Params: c.root})
|
||||
}
|
||||
|
||||
func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams) maps.ParamsMergeStrategy {
|
||||
|
||||
1
go.mod
1
go.mod
@@ -75,7 +75,6 @@ require (
|
||||
github.com/yuin/goldmark-emoji v1.0.6
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
gocloud.dev v0.43.0
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b
|
||||
golang.org/x/image v0.32.0
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/net v0.46.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -267,8 +267,6 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018141905-f04b60c79bd1 h1:95D/7I2Vv3N9icWWlayjoxp7rSzjcr6PaGXLw8DZzgY=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018141905-f04b60c79bd1/go.mod h1:m5hu1im5Qc7LDycVLvee6MPobJiRLBYHklypFJR0/aE=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6 h1:pxlAea9eRwuAnt/zKbGqlFO2ZszpIe24YpOVLf+N+4I=
|
||||
github.com/gohugoio/go-i18n/v2 v2.1.3-0.20251018145728-cfcc22d823c6/go.mod h1:m5hu1im5Qc7LDycVLvee6MPobJiRLBYHklypFJR0/aE=
|
||||
github.com/gohugoio/hashstructure v0.6.0 h1:7wMB/2CfXoThFYhdWRGv3u3rUM761Cq29CxUW+NltUg=
|
||||
@@ -594,8 +592,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
|
||||
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
|
||||
@@ -1570,3 +1570,82 @@ title: "P1 us"
|
||||
`
|
||||
Test(t, files)
|
||||
}
|
||||
|
||||
func TestConfigYAMLAnchorsMerge(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.yaml --
|
||||
definitions:
|
||||
params: ¶ms
|
||||
p1: p1alias
|
||||
|
||||
theme: "mytheme"
|
||||
defaultContentLanguage: en
|
||||
defaultContentLanguageInSubdir: true
|
||||
|
||||
params:
|
||||
<<: *params
|
||||
|
||||
languages:
|
||||
en:
|
||||
weight: 1
|
||||
no:
|
||||
weight: 2
|
||||
params:
|
||||
<<: *params
|
||||
p2: p2no
|
||||
sv:
|
||||
weight: 3
|
||||
params: *params
|
||||
|
||||
-- layouts/all.html --
|
||||
Params: {{ site.Params }}|
|
||||
-- themes/mytheme/hugo.yaml --
|
||||
definitions:
|
||||
params: ¶ms
|
||||
p1: p1aliastheme
|
||||
p2: p2aliastheme
|
||||
|
||||
params: *params
|
||||
|
||||
|
||||
`
|
||||
b := Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/en/index.html", "Params: map[p1:p1alias p2:p2aliastheme]|")
|
||||
b.AssertFileContent("public/no/index.html", "Params: map[p1:p1alias p2:p2no]|")
|
||||
b.AssertFileContent("public/sv/index.html", "Params: map[p1:p1alias p2:p2aliastheme]|")
|
||||
}
|
||||
|
||||
func TestConfigYAMLAnchorsCyclicReference(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.yaml --
|
||||
definitions:
|
||||
params: ¶ms
|
||||
p1: p1alias
|
||||
|
||||
params:
|
||||
p3: *params
|
||||
|
||||
languages:
|
||||
en:
|
||||
weight: 1
|
||||
sv:
|
||||
weight: 2
|
||||
params: *params
|
||||
|
||||
-- layouts/all.html --
|
||||
Params: {{ site.Params }}|
|
||||
|
||||
`
|
||||
|
||||
for range 3 {
|
||||
b := Test(t, files)
|
||||
b.AssertFileContent("public/index.html", "Params: map[p3:map[p1:p1alias]]|")
|
||||
b.AssertFileContent("public/sv/index.html", "Params: map[p1:p1alias p3:map[p1:p1alias]]|")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
xmaps "maps"
|
||||
|
||||
"github.com/bep/logg"
|
||||
"github.com/gobuffalo/flect"
|
||||
"github.com/gohugoio/hugo/langs"
|
||||
"github.com/gohugoio/hugo/markup/converter"
|
||||
xmaps "golang.org/x/exp/maps"
|
||||
|
||||
"github.com/gohugoio/hugo/source"
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -48,9 +49,10 @@ import (
|
||||
"github.com/gohugoio/hugo/modules"
|
||||
"github.com/gohugoio/hugo/resources"
|
||||
|
||||
xmaps "maps"
|
||||
|
||||
"github.com/gohugoio/hugo/tpl/tplimpl"
|
||||
"github.com/gohugoio/hugo/tpl/tplimplinit"
|
||||
xmaps "golang.org/x/exp/maps"
|
||||
|
||||
// Loads the template funcs namespaces.
|
||||
|
||||
@@ -999,7 +1001,7 @@ func (w *WhatChanged) Changes() []identity.Identity {
|
||||
if w == nil || w.ids == nil {
|
||||
return nil
|
||||
}
|
||||
return xmaps.Keys(w.ids)
|
||||
return slices.Collect(xmaps.Keys(w.ids))
|
||||
}
|
||||
|
||||
func (w *WhatChanged) Drain() []identity.Identity {
|
||||
|
||||
@@ -16,6 +16,7 @@ package navigation
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
@@ -25,7 +26,6 @@ import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"slices"
|
||||
)
|
||||
|
||||
var smc = newMenuCache()
|
||||
|
||||
@@ -24,7 +24,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
xmaps "golang.org/x/exp/maps"
|
||||
xmaps "maps"
|
||||
|
||||
"github.com/gohugoio/hugo/common/collections"
|
||||
"github.com/gohugoio/hugo/common/maps"
|
||||
|
||||
Reference in New Issue
Block a user