Create a struct with all of Hugo's config options

Primary motivation is documentation, but it will also hopefully simplify the code.

Also,

* Lower case the default output format names; this is in line with the custom ones (map keys) and how
it's treated all the places. This avoids doing `stringds.EqualFold` everywhere.

Closes #10896
Closes #10620
This commit is contained in:
Bjørn Erik Pedersen
2023-01-04 18:24:36 +01:00
parent 6aededf6b4
commit 241b21b0fd
337 changed files with 13377 additions and 14898 deletions

View File

@@ -19,6 +19,8 @@ import (
"strings"
"sync"
xmaps "golang.org/x/exp/maps"
"github.com/spf13/cast"
"github.com/gohugoio/hugo/common/maps"
@@ -75,11 +77,6 @@ func NewFrom(params maps.Params) Provider {
}
}
// NewWithTestDefaults is used in tests only.
func NewWithTestDefaults() Provider {
return SetBaseTestDefaults(New())
}
// defaultConfigProvider is a Provider backed by a map where all keys are lower case.
// All methods are thread safe.
type defaultConfigProvider struct {
@@ -160,9 +157,9 @@ func (c *defaultConfigProvider) Set(k string, v any) {
k = strings.ToLower(k)
if k == "" {
if p, ok := maps.ToParamsAndPrepare(v); ok {
if p, err := maps.ToParamsAndPrepare(v); err == nil {
// Set the values directly in root.
c.root.Set(p)
maps.SetParams(c.root, p)
} else {
c.root[k] = v
}
@@ -184,7 +181,7 @@ func (c *defaultConfigProvider) Set(k string, v any) {
if existing, found := m[key]; found {
if p1, ok := existing.(maps.Params); ok {
if p2, ok := v.(maps.Params); ok {
p1.Set(p2)
maps.SetParams(p1, p2)
return
}
}
@@ -208,12 +205,6 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
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 {
@@ -222,7 +213,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
return
}
if p, ok := maps.ToParamsAndPrepare(v); ok {
if p, err := maps.ToParamsAndPrepare(v); err == nil {
// As there may be keys in p not in root, we need to handle
// those as a special case.
var keysToDelete []string
@@ -230,49 +221,14 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
if pp, ok := vv.(maps.Params); ok {
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)
maps.MergeParamsWithStrategy("", ppp, pp)
} else {
// We need to use the default merge strategy for
// this key.
np := make(maps.Params)
strategy := c.determineMergeStrategy(KeyParams{Key: "", Params: c.root}, KeyParams{Key: kk, Params: np})
np.SetDefaultMergeStrategy(strategy)
np.Merge(pp)
strategy := c.determineMergeStrategy(maps.KeyParams{Key: "", Params: c.root}, maps.KeyParams{Key: kk, Params: np})
np.SetMergeStrategy(strategy)
maps.MergeParamsWithStrategy("", np, pp)
c.root[kk] = np
if np.IsZero() {
// Just keep it until merge is done.
@@ -282,7 +238,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
}
}
// Merge the rest.
c.root.MergeRoot(p)
maps.MergeParams(c.root, p)
for _, k := range keysToDelete {
delete(c.root, k)
}
@@ -307,7 +263,7 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
if existing, found := m[key]; found {
if p1, ok := existing.(maps.Params); ok {
if p2, ok := v.(maps.Params); ok {
p1.Merge(p2)
maps.MergeParamsWithStrategy("", p1, p2)
}
}
} else {
@@ -315,9 +271,15 @@ func (c *defaultConfigProvider) Merge(k string, v any) {
}
}
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...KeyParams) bool) {
var walk func(params ...KeyParams)
walk = func(params ...KeyParams) {
func (c *defaultConfigProvider) Keys() []string {
c.mu.RLock()
defer c.mu.RUnlock()
return 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) {
if walkFn(params...) {
return
}
@@ -325,17 +287,17 @@ func (c *defaultConfigProvider) WalkParams(walkFn func(params ...KeyParams) bool
i := len(params)
for k, v := range p1.Params {
if p2, ok := v.(maps.Params); ok {
paramsplus1 := make([]KeyParams, i+1)
paramsplus1 := make([]maps.KeyParams, i+1)
copy(paramsplus1, params)
paramsplus1[i] = KeyParams{Key: k, Params: p2}
paramsplus1[i] = maps.KeyParams{Key: k, Params: p2}
walk(paramsplus1...)
}
}
}
walk(KeyParams{Key: "", Params: c.root})
walk(maps.KeyParams{Key: "", Params: c.root})
}
func (c *defaultConfigProvider) determineMergeStrategy(params ...KeyParams) maps.ParamsMergeStrategy {
func (c *defaultConfigProvider) determineMergeStrategy(params ...maps.KeyParams) maps.ParamsMergeStrategy {
if len(params) == 0 {
return maps.ParamsMergeStrategyNone
}
@@ -391,13 +353,8 @@ func (c *defaultConfigProvider) determineMergeStrategy(params ...KeyParams) maps
return strategy
}
type KeyParams struct {
Key string
Params maps.Params
}
func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
c.WalkParams(func(params ...KeyParams) bool {
c.WalkParams(func(params ...maps.KeyParams) bool {
if len(params) == 0 {
return false
}
@@ -409,7 +366,7 @@ func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
}
strategy := c.determineMergeStrategy(params...)
if strategy != "" {
p.SetDefaultMergeStrategy(strategy)
p.SetMergeStrategy(strategy)
}
return false
})