mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Misc config loading fixes
The main motivation behind this is simplicity and correctnes, but the new small config library is also faster: ``` BenchmarkDefaultConfigProvider/Viper-16 252418 4546 ns/op 2720 B/op 30 allocs/op BenchmarkDefaultConfigProvider/Custom-16 450756 2651 ns/op 1008 B/op 6 allocs/op ``` Fixes #8633 Fixes #8618 Fixes #8630 Updates #8591 Closes #6680 Closes #5192
This commit is contained in:
parent
a886dd53b8
commit
d392893cd7
107 changed files with 2159 additions and 1060 deletions
7
cache/filecache/filecache_config.go
vendored
7
cache/filecache/filecache_config.go
vendored
|
@ -19,6 +19,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
|
@ -123,6 +125,9 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
|
||||||
_, isOsFs := fs.(*afero.OsFs)
|
_, isOsFs := fs.(*afero.OsFs)
|
||||||
|
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
|
if _, ok := v.(maps.Params); !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
cc := defaultCacheConfig
|
cc := defaultCacheConfig
|
||||||
|
|
||||||
dc := &mapstructure.DecoderConfig{
|
dc := &mapstructure.DecoderConfig{
|
||||||
|
@ -137,7 +142,7 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := decoder.Decode(v); err != nil {
|
if err := decoder.Decode(v); err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "failed to decode filecache config")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cc.Dir == "" {
|
if cc.Dir == "" {
|
||||||
|
|
5
cache/filecache/filecache_config_test.go
vendored
5
cache/filecache/filecache_config_test.go
vendored
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeConfig(t *testing.T) {
|
func TestDecodeConfig(t *testing.T) {
|
||||||
|
@ -178,8 +177,8 @@ dir = "/"
|
||||||
c.Assert(err, qt.Not(qt.IsNil))
|
c.Assert(err, qt.Not(qt.IsNil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestConfig() *viper.Viper {
|
func newTestConfig() config.Provider {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("workingDir", filepath.FromSlash("/my/cool/hugoproject"))
|
cfg.Set("workingDir", filepath.FromSlash("/my/cool/hugoproject"))
|
||||||
cfg.Set("contentDir", "content")
|
cfg.Set("contentDir", "content")
|
||||||
cfg.Set("dataDir", "data")
|
cfg.Set("dataDir", "data")
|
||||||
|
|
|
@ -410,7 +410,5 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||||
}
|
}
|
||||||
config.Set("cacheDir", cacheDir)
|
config.Set("cacheDir", cacheDir)
|
||||||
|
|
||||||
cfg.Logger.Infoln("Using config file:", config.ConfigFileUsed())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
@ -29,7 +31,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
@ -166,7 +167,7 @@ func TestFlags(t *testing.T) {
|
||||||
name: "ignoreVendor as bool",
|
name: "ignoreVendor as bool",
|
||||||
args: []string{"server", "--ignoreVendor"},
|
args: []string{"server", "--ignoreVendor"},
|
||||||
check: func(c *qt.C, cmd *serverCmd) {
|
check: func(c *qt.C, cmd *serverCmd) {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cmd.flagsToConfig(cfg)
|
cmd.flagsToConfig(cfg)
|
||||||
c.Assert(cfg.Get("ignoreVendor"), qt.Equals, true)
|
c.Assert(cfg.Get("ignoreVendor"), qt.Equals, true)
|
||||||
},
|
},
|
||||||
|
@ -176,7 +177,7 @@ func TestFlags(t *testing.T) {
|
||||||
name: "ignoreVendorPaths",
|
name: "ignoreVendorPaths",
|
||||||
args: []string{"server", "--ignoreVendorPaths=github.com/**"},
|
args: []string{"server", "--ignoreVendorPaths=github.com/**"},
|
||||||
check: func(c *qt.C, cmd *serverCmd) {
|
check: func(c *qt.C, cmd *serverCmd) {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cmd.flagsToConfig(cfg)
|
cmd.flagsToConfig(cfg)
|
||||||
c.Assert(cfg.Get("ignoreVendorPaths"), qt.Equals, "github.com/**")
|
c.Assert(cfg.Get("ignoreVendorPaths"), qt.Equals, "github.com/**")
|
||||||
},
|
},
|
||||||
|
@ -216,7 +217,7 @@ func TestFlags(t *testing.T) {
|
||||||
c.Assert(sc.serverPort, qt.Equals, 1366)
|
c.Assert(sc.serverPort, qt.Equals, 1366)
|
||||||
c.Assert(sc.environment, qt.Equals, "testing")
|
c.Assert(sc.environment, qt.Equals, "testing")
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
sc.flagsToConfig(cfg)
|
sc.flagsToConfig(cfg)
|
||||||
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
|
c.Assert(cfg.GetString("publishDir"), qt.Equals, "/tmp/mydestination")
|
||||||
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
|
c.Assert(cfg.GetString("contentDir"), qt.Equals, "mycontent")
|
||||||
|
|
|
@ -22,13 +22,14 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/parser"
|
"github.com/gohugoio/hugo/parser"
|
||||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ cmder = (*configCmd)(nil)
|
var _ cmder = (*configCmd)(nil)
|
||||||
|
@ -81,7 +82,7 @@ func (c *configCmd) printConfig(cmd *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
allSettings := cfg.Cfg.(*viper.Viper).AllSettings()
|
allSettings := cfg.Cfg.Get("").(maps.Params)
|
||||||
|
|
||||||
// We need to clean up this, but we store objects in the config that
|
// We need to clean up this, but we store objects in the config that
|
||||||
// isn't really interesting to the end user, so filter these.
|
// isn't really interesting to the end user, so filter these.
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||||
|
|
||||||
_errors "github.com/pkg/errors"
|
_errors "github.com/pkg/errors"
|
||||||
|
@ -29,7 +30,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/parser"
|
"github.com/gohugoio/hugo/parser"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
jww "github.com/spf13/jwalterweatherman"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ cmder = (*newSiteCmd)(nil)
|
var _ cmder = (*newSiteCmd)(nil)
|
||||||
|
@ -123,7 +123,7 @@ func (n *newSiteCmd) newSite(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
forceNew, _ := cmd.Flags().GetBool("force")
|
forceNew, _ := cmd.Flags().GetBool("force")
|
||||||
|
|
||||||
return n.doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
|
return n.doNewSite(hugofs.NewDefault(config.New()), createpath, forceNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
|
func createConfig(fs *hugofs.Fs, inpath string, kind string) (err error) {
|
||||||
|
|
|
@ -22,10 +22,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServer(t *testing.T) {
|
func TestServer(t *testing.T) {
|
||||||
|
@ -101,7 +101,7 @@ func TestFixURL(t *testing.T) {
|
||||||
t.Run(test.TestName, func(t *testing.T) {
|
t.Run(test.TestName, func(t *testing.T) {
|
||||||
b := newCommandsBuilder()
|
b := newCommandsBuilder()
|
||||||
s := b.newServerCmd()
|
s := b.newServerCmd()
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
baseURL := test.CLIBaseURL
|
baseURL := test.CLIBaseURL
|
||||||
v.Set("baseURL", test.CfgBaseURL)
|
v.Set("baseURL", test.CfgBaseURL)
|
||||||
s.serverAppend = test.AppendPort
|
s.serverAppend = test.AppendPort
|
||||||
|
|
|
@ -18,53 +18,65 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
|
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToLower makes all the keys in the given map lower cased and will do so
|
// ToStringMapE converts in to map[string]interface{}.
|
||||||
// recursively.
|
|
||||||
// Notes:
|
|
||||||
// * This will modify the map given.
|
|
||||||
// * Any nested map[interface{}]interface{} will be converted to Params.
|
|
||||||
func ToLower(m Params) {
|
|
||||||
for k, v := range m {
|
|
||||||
var retyped bool
|
|
||||||
switch v.(type) {
|
|
||||||
case map[interface{}]interface{}:
|
|
||||||
var p Params = cast.ToStringMap(v)
|
|
||||||
v = p
|
|
||||||
ToLower(p)
|
|
||||||
retyped = true
|
|
||||||
case map[string]interface{}:
|
|
||||||
var p Params = v.(map[string]interface{})
|
|
||||||
v = p
|
|
||||||
ToLower(p)
|
|
||||||
retyped = true
|
|
||||||
}
|
|
||||||
|
|
||||||
lKey := strings.ToLower(k)
|
|
||||||
if retyped || k != lKey {
|
|
||||||
delete(m, k)
|
|
||||||
m[lKey] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToStringMapE(in interface{}) (map[string]interface{}, error) {
|
func ToStringMapE(in interface{}) (map[string]interface{}, error) {
|
||||||
switch in.(type) {
|
switch vv := in.(type) {
|
||||||
case Params:
|
case Params:
|
||||||
return in.(Params), nil
|
return vv, nil
|
||||||
|
case map[string]string:
|
||||||
|
var m = map[string]interface{}{}
|
||||||
|
for k, v := range vv {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return cast.ToStringMapE(in)
|
return cast.ToStringMapE(in)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToParamsAndPrepare converts in to Params and prepares it for use.
|
||||||
|
// See PrepareParams.
|
||||||
|
func ToParamsAndPrepare(in interface{}) (Params, bool) {
|
||||||
|
m, err := ToStringMapE(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
PrepareParams(m)
|
||||||
|
return m, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToStringMap converts in to map[string]interface{}.
|
||||||
func ToStringMap(in interface{}) map[string]interface{} {
|
func ToStringMap(in interface{}) map[string]interface{} {
|
||||||
m, _ := ToStringMapE(in)
|
m, _ := ToStringMapE(in)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToStringMapStringE converts in to map[string]string.
|
||||||
|
func ToStringMapStringE(in interface{}) (map[string]string, error) {
|
||||||
|
m, err := ToStringMapE(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cast.ToStringMapStringE(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToStringMapString converts in to map[string]string.
|
||||||
|
func ToStringMapString(in interface{}) map[string]string {
|
||||||
|
m, _ := ToStringMapStringE(in)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToStringMapBool converts in to bool.
|
||||||
|
func ToStringMapBool(in interface{}) map[string]bool {
|
||||||
|
m, _ := ToStringMapE(in)
|
||||||
|
return cast.ToStringMapBool(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSliceStringMap converts in to []map[string]interface{}.
|
||||||
func ToSliceStringMap(in interface{}) ([]map[string]interface{}, error) {
|
func ToSliceStringMap(in interface{}) ([]map[string]interface{}, error) {
|
||||||
switch v := in.(type) {
|
switch v := in.(type) {
|
||||||
case []map[string]interface{}:
|
case []map[string]interface{}:
|
||||||
|
@ -127,9 +139,8 @@ func (KeyRenamer) keyPath(k1, k2 string) string {
|
||||||
k1, k2 = strings.ToLower(k1), strings.ToLower(k2)
|
k1, k2 = strings.ToLower(k1), strings.ToLower(k2)
|
||||||
if k1 == "" {
|
if k1 == "" {
|
||||||
return k2
|
return k2
|
||||||
} else {
|
|
||||||
return k1 + "/" + k2
|
|
||||||
}
|
}
|
||||||
|
return k1 + "/" + k2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]interface{}) {
|
func (r KeyRenamer) renamePath(parentKeyPath string, m map[string]interface{}) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ func TestToLower(t *testing.T) {
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
// ToLower modifies input.
|
// ToLower modifies input.
|
||||||
ToLower(test.input)
|
PrepareParams(test.input)
|
||||||
if !reflect.DeepEqual(test.expected, test.input) {
|
if !reflect.DeepEqual(test.expected, test.input) {
|
||||||
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
|
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package maps
|
package maps
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
@ -29,6 +30,95 @@ func (p Params) Get(indices ...string) interface{} {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set overwrites values in p with values in pp for common or new keys.
|
||||||
|
// This is done recursively.
|
||||||
|
func (p Params) Set(pp Params) {
|
||||||
|
for k, v := range pp {
|
||||||
|
vv, found := p[k]
|
||||||
|
if !found {
|
||||||
|
p[k] = v
|
||||||
|
} else {
|
||||||
|
switch vvv := vv.(type) {
|
||||||
|
case Params:
|
||||||
|
if pv, ok := v.(Params); ok {
|
||||||
|
vvv.Set(pv)
|
||||||
|
} else {
|
||||||
|
p[k] = v
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
p[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge transfers values from pp to p for new keys.
|
||||||
|
// This is done recursively.
|
||||||
|
func (p Params) Merge(pp Params) {
|
||||||
|
p.merge("", pp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
|
||||||
|
ns, found := p.GetMergeStrategy()
|
||||||
|
|
||||||
|
var ms = ns
|
||||||
|
if !found && ps != "" {
|
||||||
|
ms = ps
|
||||||
|
}
|
||||||
|
|
||||||
|
noUpdate := ms == ParamsMergeStrategyNone
|
||||||
|
noUpdate = noUpdate || (ps != "" && ps == ParamsMergeStrategyShallow)
|
||||||
|
|
||||||
|
for k, v := range pp {
|
||||||
|
|
||||||
|
if k == mergeStrategyKey {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vv, found := p[k]
|
||||||
|
|
||||||
|
if found {
|
||||||
|
// Key matches, if both sides are Params, we try to merge.
|
||||||
|
if vvv, ok := vv.(Params); ok {
|
||||||
|
if pv, ok := v.(Params); ok {
|
||||||
|
vvv.merge(ms, pv)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if !noUpdate {
|
||||||
|
p[k] = v
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
|
||||||
|
if v, found := p[mergeStrategyKey]; found {
|
||||||
|
if s, ok := v.(ParamsMergeStrategy); ok {
|
||||||
|
return s, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ParamsMergeStrategyShallow, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Params) DeleteMergeStrategy() bool {
|
||||||
|
if _, found := p[mergeStrategyKey]; found {
|
||||||
|
delete(p, mergeStrategyKey)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Params) SetDefaultMergeStrategy(s ParamsMergeStrategy) {
|
||||||
|
switch s {
|
||||||
|
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("invalid merge strategy %q", s))
|
||||||
|
}
|
||||||
|
p[mergeStrategyKey] = s
|
||||||
|
}
|
||||||
|
|
||||||
func getNested(m map[string]interface{}, indices []string) (interface{}, string, map[string]interface{}) {
|
func getNested(m map[string]interface{}, indices []string) (interface{}, string, map[string]interface{}) {
|
||||||
if len(indices) == 0 {
|
if len(indices) == 0 {
|
||||||
return nil, "", nil
|
return nil, "", nil
|
||||||
|
@ -108,3 +198,61 @@ func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interf
|
||||||
|
|
||||||
return nil, "", nil, nil
|
return nil, "", nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParamsMergeStrategy tells what strategy to use in Params.Merge.
|
||||||
|
type ParamsMergeStrategy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Do not merge.
|
||||||
|
ParamsMergeStrategyNone ParamsMergeStrategy = "none"
|
||||||
|
// Only add new keys.
|
||||||
|
ParamsMergeStrategyShallow ParamsMergeStrategy = "shallow"
|
||||||
|
// Add new keys, merge existing.
|
||||||
|
ParamsMergeStrategyDeep ParamsMergeStrategy = "deep"
|
||||||
|
|
||||||
|
mergeStrategyKey = "_merge"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toMergeStrategy(v interface{}) ParamsMergeStrategy {
|
||||||
|
s := ParamsMergeStrategy(cast.ToString(v))
|
||||||
|
switch s {
|
||||||
|
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
|
||||||
|
return s
|
||||||
|
default:
|
||||||
|
return ParamsMergeStrategyDeep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareParams
|
||||||
|
// * makes all the keys in the given map lower cased and will do so
|
||||||
|
// * This will modify the map given.
|
||||||
|
// * Any nested map[interface{}]interface{} will be converted to Params.
|
||||||
|
// * Any _merge value will be converted to proper type and value.
|
||||||
|
func PrepareParams(m Params) {
|
||||||
|
for k, v := range m {
|
||||||
|
var retyped bool
|
||||||
|
lKey := strings.ToLower(k)
|
||||||
|
if lKey == mergeStrategyKey {
|
||||||
|
v = toMergeStrategy(v)
|
||||||
|
retyped = true
|
||||||
|
} else {
|
||||||
|
switch v.(type) {
|
||||||
|
case map[interface{}]interface{}:
|
||||||
|
var p Params = cast.ToStringMap(v)
|
||||||
|
v = p
|
||||||
|
PrepareParams(p)
|
||||||
|
retyped = true
|
||||||
|
case map[string]interface{}:
|
||||||
|
var p Params = v.(map[string]interface{})
|
||||||
|
v = p
|
||||||
|
PrepareParams(p)
|
||||||
|
retyped = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if retyped || k != lKey {
|
||||||
|
delete(m, k)
|
||||||
|
m[lKey] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -69,3 +69,90 @@ func TestGetNestedParamFnNestedNewKey(t *testing.T) {
|
||||||
c.Assert(nestedKey, qt.Equals, "new")
|
c.Assert(nestedKey, qt.Equals, "new")
|
||||||
c.Assert(owner, qt.DeepEquals, nested)
|
c.Assert(owner, qt.DeepEquals, nested)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParamsSetAndMerge(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
createParamsPair := func() (Params, Params) {
|
||||||
|
p1 := Params{"a": "av", "c": "cv", "nested": Params{"al2": "al2v", "cl2": "cl2v"}}
|
||||||
|
p2 := Params{"b": "bv", "a": "abv", "nested": Params{"bl2": "bl2v", "al2": "al2bv"}, mergeStrategyKey: ParamsMergeStrategyDeep}
|
||||||
|
return p1, p2
|
||||||
|
}
|
||||||
|
|
||||||
|
p1, p2 := createParamsPair()
|
||||||
|
|
||||||
|
p1.Set(p2)
|
||||||
|
|
||||||
|
c.Assert(p1, qt.DeepEquals, Params{
|
||||||
|
"a": "abv",
|
||||||
|
"c": "cv",
|
||||||
|
"nested": Params{
|
||||||
|
"al2": "al2bv",
|
||||||
|
"cl2": "cl2v",
|
||||||
|
"bl2": "bl2v",
|
||||||
|
},
|
||||||
|
"b": "bv",
|
||||||
|
mergeStrategyKey: ParamsMergeStrategyDeep,
|
||||||
|
})
|
||||||
|
|
||||||
|
p1, p2 = createParamsPair()
|
||||||
|
|
||||||
|
p1.Merge(p2)
|
||||||
|
|
||||||
|
// Default is to do a shallow merge.
|
||||||
|
c.Assert(p1, qt.DeepEquals, Params{
|
||||||
|
"c": "cv",
|
||||||
|
"nested": Params{
|
||||||
|
"al2": "al2v",
|
||||||
|
"cl2": "cl2v",
|
||||||
|
},
|
||||||
|
"b": "bv",
|
||||||
|
"a": "av",
|
||||||
|
})
|
||||||
|
|
||||||
|
p1, p2 = createParamsPair()
|
||||||
|
p1.SetDefaultMergeStrategy(ParamsMergeStrategyNone)
|
||||||
|
p1.Merge(p2)
|
||||||
|
p1.DeleteMergeStrategy()
|
||||||
|
|
||||||
|
c.Assert(p1, qt.DeepEquals, Params{
|
||||||
|
"a": "av",
|
||||||
|
"c": "cv",
|
||||||
|
"nested": Params{
|
||||||
|
"al2": "al2v",
|
||||||
|
"cl2": "cl2v",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
p1, p2 = createParamsPair()
|
||||||
|
p1.SetDefaultMergeStrategy(ParamsMergeStrategyShallow)
|
||||||
|
p1.Merge(p2)
|
||||||
|
p1.DeleteMergeStrategy()
|
||||||
|
|
||||||
|
c.Assert(p1, qt.DeepEquals, Params{
|
||||||
|
"a": "av",
|
||||||
|
"c": "cv",
|
||||||
|
"nested": Params{
|
||||||
|
"al2": "al2v",
|
||||||
|
"cl2": "cl2v",
|
||||||
|
},
|
||||||
|
"b": "bv",
|
||||||
|
})
|
||||||
|
|
||||||
|
p1, p2 = createParamsPair()
|
||||||
|
p1.SetDefaultMergeStrategy(ParamsMergeStrategyDeep)
|
||||||
|
p1.Merge(p2)
|
||||||
|
p1.DeleteMergeStrategy()
|
||||||
|
|
||||||
|
c.Assert(p1, qt.DeepEquals, Params{
|
||||||
|
"nested": Params{
|
||||||
|
"al2": "al2v",
|
||||||
|
"cl2": "cl2v",
|
||||||
|
"bl2": "bl2v",
|
||||||
|
},
|
||||||
|
"b": "bv",
|
||||||
|
"a": "av",
|
||||||
|
"c": "cv",
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -21,14 +21,12 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := viper.New()
|
v := New()
|
||||||
v.Set("build", map[string]interface{}{
|
v.Set("build", map[string]interface{}{
|
||||||
"useResourceCacheWhen": "always",
|
"useResourceCacheWhen": "always",
|
||||||
})
|
})
|
||||||
|
|
113
config/compositeConfig.go
Normal file
113
config/compositeConfig.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
// Copyright 2021 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCompositeConfig creates a new composite Provider with a read-only base
|
||||||
|
// and a writeable layer.
|
||||||
|
func NewCompositeConfig(base, layer Provider) Provider {
|
||||||
|
return &compositeConfig{
|
||||||
|
base: base,
|
||||||
|
layer: layer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compositeConfig contains a read only config base with
|
||||||
|
// a possibly writeable config layer on top.
|
||||||
|
type compositeConfig struct {
|
||||||
|
base Provider
|
||||||
|
layer Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetBool(key string) bool {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetBool(key)
|
||||||
|
}
|
||||||
|
return c.base.GetBool(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetInt(key string) int {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetInt(key)
|
||||||
|
}
|
||||||
|
return c.base.GetInt(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) Merge(key string, value interface{}) {
|
||||||
|
c.layer.Merge(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetParams(key string) maps.Params {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetParams(key)
|
||||||
|
}
|
||||||
|
return c.base.GetParams(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetStringMap(key string) map[string]interface{} {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetStringMap(key)
|
||||||
|
}
|
||||||
|
return c.base.GetStringMap(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetStringMapString(key string) map[string]string {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetStringMapString(key)
|
||||||
|
}
|
||||||
|
return c.base.GetStringMapString(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetStringSlice(key string) []string {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetStringSlice(key)
|
||||||
|
}
|
||||||
|
return c.base.GetStringSlice(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) Get(key string) interface{} {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.Get(key)
|
||||||
|
}
|
||||||
|
return c.base.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) IsSet(key string) bool {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return c.base.IsSet(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) GetString(key string) string {
|
||||||
|
if c.layer.IsSet(key) {
|
||||||
|
return c.layer.GetString(key)
|
||||||
|
}
|
||||||
|
return c.base.GetString(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) Set(key string, value interface{}) {
|
||||||
|
c.layer.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) WalkParams(walkFn func(params ...KeyParams) bool) {
|
||||||
|
panic("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compositeConfig) SetDefaultMergeStrategy() {
|
||||||
|
panic("not supported")
|
||||||
|
}
|
40
config/compositeConfig_test.go
Normal file
40
config/compositeConfig_test.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2021 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompositeConfig(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
c.Run("Set and get", func(c *qt.C) {
|
||||||
|
base, layer := New(), New()
|
||||||
|
cfg := NewCompositeConfig(base, layer)
|
||||||
|
|
||||||
|
layer.Set("a1", "av")
|
||||||
|
base.Set("b1", "bv")
|
||||||
|
cfg.Set("c1", "cv")
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("a1"), qt.Equals, "av")
|
||||||
|
c.Assert(cfg.Get("b1"), qt.Equals, "bv")
|
||||||
|
c.Assert(cfg.Get("c1"), qt.Equals, "cv")
|
||||||
|
c.Assert(cfg.IsSet("c1"), qt.IsTrue)
|
||||||
|
c.Assert(layer.IsSet("c1"), qt.IsTrue)
|
||||||
|
c.Assert(base.IsSet("c1"), qt.IsFalse)
|
||||||
|
})
|
||||||
|
}
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/parser/metadecoders"
|
"github.com/gohugoio/hugo/parser/metadecoders"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -43,15 +42,11 @@ func IsValidConfigFilename(filename string) bool {
|
||||||
|
|
||||||
// FromConfigString creates a config from the given YAML, JSON or TOML config. This is useful in tests.
|
// FromConfigString creates a config from the given YAML, JSON or TOML config. This is useful in tests.
|
||||||
func FromConfigString(config, configType string) (Provider, error) {
|
func FromConfigString(config, configType string) (Provider, error) {
|
||||||
v := newViper()
|
|
||||||
m, err := readConfig(metadecoders.FormatFromString(configType), []byte(config))
|
m, err := readConfig(metadecoders.FormatFromString(configType), []byte(config))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return NewFrom(m), nil
|
||||||
v.MergeConfigMap(m)
|
|
||||||
|
|
||||||
return v, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromFile loads the configuration from the given filename.
|
// FromFile loads the configuration from the given filename.
|
||||||
|
@ -60,15 +55,7 @@ func FromFile(fs afero.Fs, filename string) (Provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return NewFrom(m), nil
|
||||||
v := newViper()
|
|
||||||
|
|
||||||
err = v.MergeConfigMap(m)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return v, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromFileToMap is the same as FromFile, but it returns the config values
|
// FromFileToMap is the same as FromFile, but it returns the config values
|
||||||
|
@ -116,9 +103,3 @@ func init() {
|
||||||
func RenameKeys(m map[string]interface{}) {
|
func RenameKeys(m map[string]interface{}) {
|
||||||
keyAliases.Rename(m)
|
keyAliases.Rename(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newViper() *viper.Viper {
|
|
||||||
v := viper.New()
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,11 +23,15 @@ type Provider interface {
|
||||||
GetString(key string) string
|
GetString(key string) string
|
||||||
GetInt(key string) int
|
GetInt(key string) int
|
||||||
GetBool(key string) bool
|
GetBool(key string) bool
|
||||||
|
GetParams(key string) maps.Params
|
||||||
GetStringMap(key string) map[string]interface{}
|
GetStringMap(key string) map[string]interface{}
|
||||||
GetStringMapString(key string) map[string]string
|
GetStringMapString(key string) map[string]string
|
||||||
GetStringSlice(key string) []string
|
GetStringSlice(key string) []string
|
||||||
Get(key string) interface{}
|
Get(key string) interface{}
|
||||||
Set(key string, value interface{})
|
Set(key string, value interface{})
|
||||||
|
Merge(key string, value interface{})
|
||||||
|
SetDefaultMergeStrategy()
|
||||||
|
WalkParams(walkFn func(params ...KeyParams) bool)
|
||||||
IsSet(key string) bool
|
IsSet(key string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetStringSlicePreserveString(t *testing.T) {
|
func TestGetStringSlicePreserveString(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := New()
|
||||||
|
|
||||||
s := "This is a string"
|
s := "This is a string"
|
||||||
sSlice := []string{"This", "is", "a", "slice"}
|
sSlice := []string{"This", "is", "a", "slice"}
|
||||||
|
|
372
config/defaultConfigProvider.go
Normal file
372
config/defaultConfigProvider.go
Normal file
|
@ -0,0 +1,372 @@
|
||||||
|
// Copyright 2021 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
|
||||||
|
// ConfigRootKeysSet contains all of the config map root keys.
|
||||||
|
// TODO(bep) use this for something (docs etc.)
|
||||||
|
ConfigRootKeysSet = map[string]bool{
|
||||||
|
"build": true,
|
||||||
|
"caches": true,
|
||||||
|
"frontmatter": true,
|
||||||
|
"languages": true,
|
||||||
|
"imaging": true,
|
||||||
|
"markup": true,
|
||||||
|
"mediatypes": true,
|
||||||
|
"menus": true,
|
||||||
|
"minify": true,
|
||||||
|
"module": true,
|
||||||
|
"outputformats": true,
|
||||||
|
"params": true,
|
||||||
|
"permalinks": true,
|
||||||
|
"related": true,
|
||||||
|
"sitemap": true,
|
||||||
|
"taxonomies": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigRootKeys is a sorted version of ConfigRootKeysSet.
|
||||||
|
ConfigRootKeys []string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for k := range ConfigRootKeysSet {
|
||||||
|
ConfigRootKeys = append(ConfigRootKeys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(ConfigRootKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a Provider backed by an empty maps.Params.
|
||||||
|
func New() Provider {
|
||||||
|
return &defaultConfigProvider{
|
||||||
|
root: make(maps.Params),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFrom creates a Provider backed by params.
|
||||||
|
func NewFrom(params maps.Params) Provider {
|
||||||
|
maps.PrepareParams(params)
|
||||||
|
return &defaultConfigProvider{
|
||||||
|
root: params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultConfigProvider is a Provider backed by a map where all keys are lower case.
|
||||||
|
// All methods are thread safe.
|
||||||
|
type defaultConfigProvider struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
root maps.Params
|
||||||
|
|
||||||
|
keyCache sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) Get(k string) interface{} {
|
||||||
|
if k == "" {
|
||||||
|
return c.root
|
||||||
|
}
|
||||||
|
c.mu.RLock()
|
||||||
|
key, m := c.getNestedKeyAndMap(strings.ToLower(k), false)
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := m[key]
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetBool(k string) bool {
|
||||||
|
v := c.Get(k)
|
||||||
|
return cast.ToBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetInt(k string) int {
|
||||||
|
v := c.Get(k)
|
||||||
|
return cast.ToInt(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) IsSet(k string) bool {
|
||||||
|
var found bool
|
||||||
|
c.mu.RLock()
|
||||||
|
key, m := c.getNestedKeyAndMap(strings.ToLower(k), false)
|
||||||
|
if m != nil {
|
||||||
|
_, found = m[key]
|
||||||
|
}
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetString(k string) string {
|
||||||
|
v := c.Get(k)
|
||||||
|
return cast.ToString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetParams(k string) maps.Params {
|
||||||
|
v := c.Get(k)
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.(maps.Params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetStringMap(k string) map[string]interface{} {
|
||||||
|
v := c.Get(k)
|
||||||
|
return maps.ToStringMap(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetStringMapString(k string) map[string]string {
|
||||||
|
v := c.Get(k)
|
||||||
|
return maps.ToStringMapString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) GetStringSlice(k string) []string {
|
||||||
|
v := c.Get(k)
|
||||||
|
return cast.ToStringSlice(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) Set(k string, v interface{}) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
|
||||||
|
if k == "" {
|
||||||
|
if p, ok := maps.ToParamsAndPrepare(v); ok {
|
||||||
|
// Set the values directly in root.
|
||||||
|
c.root.Set(p)
|
||||||
|
} else {
|
||||||
|
c.root[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch vv := v.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
var p maps.Params = vv
|
||||||
|
v = p
|
||||||
|
maps.PrepareParams(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, m := c.getNestedKeyAndMap(k, true)
|
||||||
|
|
||||||
|
if existing, found := m[key]; found {
|
||||||
|
if p1, ok := existing.(maps.Params); ok {
|
||||||
|
if p2, ok := v.(maps.Params); ok {
|
||||||
|
p1.Set(p2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m[key] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) Merge(k string, v interface{}) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
|
||||||
|
if k == "" {
|
||||||
|
rs, f := c.root.GetMergeStrategy()
|
||||||
|
if f && rs == maps.ParamsMergeStrategyNone {
|
||||||
|
// The user has set a "no merge" strategy on this,
|
||||||
|
// nothing more to do.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, ok := maps.ToParamsAndPrepare(v); ok {
|
||||||
|
// As there may be keys in p not in root, we need to handle
|
||||||
|
// 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)
|
||||||
|
} 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)
|
||||||
|
if len(np) > 0 {
|
||||||
|
c.root[kk] = np
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Merge the rest.
|
||||||
|
c.root.Merge(p)
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("unsupported type %T received in Merge", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch vv := v.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
var p maps.Params = vv
|
||||||
|
v = p
|
||||||
|
maps.PrepareParams(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, m := c.getNestedKeyAndMap(k, true)
|
||||||
|
|
||||||
|
if existing, found := m[key]; found {
|
||||||
|
if p1, ok := existing.(maps.Params); ok {
|
||||||
|
if p2, ok := v.(maps.Params); ok {
|
||||||
|
p1.Merge(p2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m[key] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...KeyParams) bool) {
|
||||||
|
var walk func(params ...KeyParams)
|
||||||
|
walk = func(params ...KeyParams) {
|
||||||
|
if walkFn(params...) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p1 := params[len(params)-1]
|
||||||
|
i := len(params)
|
||||||
|
for k, v := range p1.Params {
|
||||||
|
if p2, ok := v.(maps.Params); ok {
|
||||||
|
paramsplus1 := make([]KeyParams, i+1)
|
||||||
|
copy(paramsplus1, params)
|
||||||
|
paramsplus1[i] = KeyParams{Key: k, Params: p2}
|
||||||
|
walk(paramsplus1...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walk(KeyParams{Key: "", Params: c.root})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) determineMergeStrategy(params ...KeyParams) maps.ParamsMergeStrategy {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return maps.ParamsMergeStrategyNone
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
strategy maps.ParamsMergeStrategy
|
||||||
|
prevIsRoot bool
|
||||||
|
curr = params[len(params)-1]
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(params) > 1 {
|
||||||
|
prev := params[len(params)-2]
|
||||||
|
prevIsRoot = prev.Key == ""
|
||||||
|
|
||||||
|
// Inherit from parent (but not from the root unless it's set by user).
|
||||||
|
s, found := prev.Params.GetMergeStrategy()
|
||||||
|
if !prevIsRoot && !found {
|
||||||
|
panic("invalid state, merge strategy not set on parent")
|
||||||
|
}
|
||||||
|
if found || !prevIsRoot {
|
||||||
|
strategy = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch curr.Key {
|
||||||
|
case "":
|
||||||
|
// Don't set a merge strategy on the root unless set by user.
|
||||||
|
// This will be handled as a special case.
|
||||||
|
case "params":
|
||||||
|
strategy = maps.ParamsMergeStrategyDeep
|
||||||
|
case "outputformats", "mediatypes":
|
||||||
|
if prevIsRoot {
|
||||||
|
strategy = maps.ParamsMergeStrategyShallow
|
||||||
|
}
|
||||||
|
case "menus":
|
||||||
|
isMenuKey := prevIsRoot
|
||||||
|
if !isMenuKey {
|
||||||
|
// Can also be set below languages.
|
||||||
|
// root > languages > en > menus
|
||||||
|
if len(params) == 4 && params[1].Key == "languages" {
|
||||||
|
isMenuKey = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isMenuKey {
|
||||||
|
strategy = maps.ParamsMergeStrategyShallow
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if strategy == "" {
|
||||||
|
strategy = maps.ParamsMergeStrategyNone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyParams struct {
|
||||||
|
Key string
|
||||||
|
Params maps.Params
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) SetDefaultMergeStrategy() {
|
||||||
|
c.WalkParams(func(params ...KeyParams) bool {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p := params[len(params)-1].Params
|
||||||
|
var found bool
|
||||||
|
if _, found = p.GetMergeStrategy(); found {
|
||||||
|
// Set by user.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
strategy := c.determineMergeStrategy(params...)
|
||||||
|
if strategy != "" {
|
||||||
|
p.SetDefaultMergeStrategy(strategy)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *defaultConfigProvider) getNestedKeyAndMap(key string, create bool) (string, maps.Params) {
|
||||||
|
var parts []string
|
||||||
|
v, ok := c.keyCache.Load(key)
|
||||||
|
if ok {
|
||||||
|
parts = v.([]string)
|
||||||
|
} else {
|
||||||
|
parts = strings.Split(key, ".")
|
||||||
|
c.keyCache.Store(key, parts)
|
||||||
|
}
|
||||||
|
current := c.root
|
||||||
|
for i := 0; i < len(parts)-1; i++ {
|
||||||
|
next, found := current[parts[i]]
|
||||||
|
if !found {
|
||||||
|
if create {
|
||||||
|
next = make(maps.Params)
|
||||||
|
current[parts[i]] = next
|
||||||
|
} else {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = next.(maps.Params)
|
||||||
|
}
|
||||||
|
return parts[len(parts)-1], current
|
||||||
|
}
|
315
config/defaultConfigProvider_test.go
Normal file
315
config/defaultConfigProvider_test.go
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
// Copyright 2021 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/para"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
|
||||||
|
qt "github.com/frankban/quicktest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultConfigProvider(t *testing.T) {
|
||||||
|
c := qt.New(t)
|
||||||
|
|
||||||
|
c.Run("Set and get", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
var k string
|
||||||
|
var v interface{}
|
||||||
|
|
||||||
|
k, v = "foo", "bar"
|
||||||
|
cfg.Set(k, v)
|
||||||
|
c.Assert(cfg.Get(k), qt.Equals, v)
|
||||||
|
c.Assert(cfg.Get(strings.ToUpper(k)), qt.Equals, v)
|
||||||
|
c.Assert(cfg.GetString(k), qt.Equals, v)
|
||||||
|
|
||||||
|
k, v = "foo", 42
|
||||||
|
cfg.Set(k, v)
|
||||||
|
c.Assert(cfg.Get(k), qt.Equals, v)
|
||||||
|
c.Assert(cfg.GetInt(k), qt.Equals, v)
|
||||||
|
|
||||||
|
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||||
|
"foo": 42,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("Set and get map", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
|
||||||
|
cfg.Set("foo", map[string]interface{}{
|
||||||
|
"bar": "baz",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
|
||||||
|
"bar": "baz",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.GetStringMap("foo"), qt.DeepEquals, map[string]interface{}{"bar": string("baz")})
|
||||||
|
c.Assert(cfg.GetStringMapString("foo"), qt.DeepEquals, map[string]string{"bar": string("baz")})
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("Set and get nested", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
|
||||||
|
cfg.Set("a", map[string]interface{}{
|
||||||
|
"B": "bv",
|
||||||
|
})
|
||||||
|
cfg.Set("a.c", "cv")
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||||
|
"b": "bv",
|
||||||
|
"c": "cv",
|
||||||
|
})
|
||||||
|
c.Assert(cfg.Get("a.c"), qt.Equals, "cv")
|
||||||
|
|
||||||
|
cfg.Set("b.a", "av")
|
||||||
|
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
|
||||||
|
"a": "av",
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg.Set("b", map[string]interface{}{
|
||||||
|
"b": "bv",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
|
||||||
|
"a": "av",
|
||||||
|
"b": "bv",
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg = New()
|
||||||
|
|
||||||
|
cfg.Set("a", "av")
|
||||||
|
|
||||||
|
cfg.Set("", map[string]interface{}{
|
||||||
|
"a": "av2",
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||||
|
"a": "av2",
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg = New()
|
||||||
|
|
||||||
|
cfg.Set("a", "av")
|
||||||
|
|
||||||
|
cfg.Set("", map[string]interface{}{
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||||
|
"a": "av",
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg = New()
|
||||||
|
|
||||||
|
cfg.Set("", map[string]interface{}{
|
||||||
|
"foo": map[string]interface{}{
|
||||||
|
"a": "av",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg.Set("", map[string]interface{}{
|
||||||
|
"foo": map[string]interface{}{
|
||||||
|
"b": "bv2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
|
||||||
|
"a": "av",
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("Merge default strategy", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
|
||||||
|
cfg.Set("a", map[string]interface{}{
|
||||||
|
"B": "bv",
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg.Merge("a", map[string]interface{}{
|
||||||
|
"B": "bv2",
|
||||||
|
"c": "cv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||||
|
"b": "bv",
|
||||||
|
"c": "cv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg = New()
|
||||||
|
|
||||||
|
cfg.Set("a", "av")
|
||||||
|
|
||||||
|
cfg.Merge("", map[string]interface{}{
|
||||||
|
"a": "av2",
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
|
||||||
|
"a": "av",
|
||||||
|
"b": "bv2",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("Merge shallow", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
|
||||||
|
cfg.Set("a", map[string]interface{}{
|
||||||
|
"_merge": "shallow",
|
||||||
|
"B": "bv",
|
||||||
|
"c": map[string]interface{}{
|
||||||
|
"b": "bv",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
cfg.Merge("a", map[string]interface{}{
|
||||||
|
"c": map[string]interface{}{
|
||||||
|
"d": "dv2",
|
||||||
|
},
|
||||||
|
"e": "ev2",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
|
||||||
|
"e": "ev2",
|
||||||
|
"_merge": maps.ParamsMergeStrategyShallow,
|
||||||
|
"b": "bv",
|
||||||
|
"c": maps.Params{
|
||||||
|
"b": "bv",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("IsSet", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
|
||||||
|
cfg.Set("a", map[string]interface{}{
|
||||||
|
"B": "bv",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(cfg.IsSet("A"), qt.IsTrue)
|
||||||
|
c.Assert(cfg.IsSet("a.b"), qt.IsTrue)
|
||||||
|
c.Assert(cfg.IsSet("z"), qt.IsFalse)
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("Para", func(c *qt.C) {
|
||||||
|
cfg := New()
|
||||||
|
p := para.New(4)
|
||||||
|
r, _ := p.Start(context.Background())
|
||||||
|
|
||||||
|
setAndGet := func(k string, v int) error {
|
||||||
|
vs := strconv.Itoa(v)
|
||||||
|
cfg.Set(k, v)
|
||||||
|
err := errors.New("get failed")
|
||||||
|
if cfg.Get(k) != v {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cfg.GetInt(k) != v {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cfg.GetString(k) != vs {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !cfg.IsSet(k) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
i := i
|
||||||
|
r.Run(func() error {
|
||||||
|
const v = 42
|
||||||
|
k := fmt.Sprintf("k%d", i)
|
||||||
|
if err := setAndGet(k, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := maps.Params{
|
||||||
|
"new": 42,
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Merge("", m)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Assert(r.Wait(), qt.IsNil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDefaultConfigProvider(b *testing.B) {
|
||||||
|
type cfger interface {
|
||||||
|
Get(key string) interface{}
|
||||||
|
Set(key string, value interface{})
|
||||||
|
IsSet(key string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
newMap := func() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"a": map[string]interface{}{
|
||||||
|
"b": map[string]interface{}{
|
||||||
|
"c": 32,
|
||||||
|
"d": 43,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"b": 62,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runMethods := func(b *testing.B, cfg cfger) {
|
||||||
|
m := newMap()
|
||||||
|
cfg.Set("mymap", m)
|
||||||
|
cfg.Set("num", 32)
|
||||||
|
if !(cfg.IsSet("mymap") && cfg.IsSet("mymap.a") && cfg.IsSet("mymap.a.b") && cfg.IsSet("mymap.a.b.c")) {
|
||||||
|
b.Fatal("IsSet failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Get("num") != 32 {
|
||||||
|
b.Fatal("Get failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Get("mymap.a.b.c") != 32 {
|
||||||
|
b.Fatal("Get failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Run("Viper", func(b *testing.B) {
|
||||||
|
v := viper.New()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
runMethods(b, v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("Custom", func(b *testing.B) {
|
||||||
|
cfg := New()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
runMethods(b, cfg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
45
config/docshelper.go
Normal file
45
config/docshelper.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2021 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
"github.com/gohugoio/hugo/docshelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is is just some helpers used to create some JSON used in the Hugo docs.
|
||||||
|
func init() {
|
||||||
|
docsProvider := func() docshelper.DocProvider {
|
||||||
|
|
||||||
|
cfg := New()
|
||||||
|
for _, configRoot := range ConfigRootKeys {
|
||||||
|
cfg.Set(configRoot, make(maps.Params))
|
||||||
|
}
|
||||||
|
lang := maps.Params{
|
||||||
|
"en": maps.Params{
|
||||||
|
"menus": maps.Params{},
|
||||||
|
"params": maps.Params{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cfg.Set("languages", lang)
|
||||||
|
cfg.SetDefaultMergeStrategy()
|
||||||
|
|
||||||
|
configHelpers := map[string]interface{}{
|
||||||
|
"mergeStrategy": cfg.Get(""),
|
||||||
|
}
|
||||||
|
return docshelper.DocProvider{"config": configHelpers}
|
||||||
|
}
|
||||||
|
|
||||||
|
docshelper.AddDocProviderFunc(docsProvider)
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ import (
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeConfigFromTOML(t *testing.T) {
|
func TestDecodeConfigFromTOML(t *testing.T) {
|
||||||
|
@ -94,7 +93,7 @@ PrivacyENhanced = true
|
||||||
func TestDecodeConfigDefault(t *testing.T) {
|
func TestDecodeConfigDefault(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
pc, err := DecodeConfig(viper.New())
|
pc, err := DecodeConfig(config.New())
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(pc, qt.Not(qt.IsNil))
|
c.Assert(pc, qt.Not(qt.IsNil))
|
||||||
c.Assert(pc.YouTube.PrivacyEnhanced, qt.Equals, false)
|
c.Assert(pc.YouTube.PrivacyEnhanced, qt.Equals, false)
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeConfigFromTOML(t *testing.T) {
|
func TestDecodeConfigFromTOML(t *testing.T) {
|
||||||
|
@ -55,7 +55,7 @@ disableInlineCSS = true
|
||||||
func TestUseSettingsFromRootIfSet(t *testing.T) {
|
func TestUseSettingsFromRootIfSet(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("disqusShortname", "root_short")
|
cfg.Set("disqusShortname", "root_short")
|
||||||
cfg.Set("googleAnalytics", "ga_root")
|
cfg.Set("googleAnalytics", "ga_root")
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugolib"
|
"github.com/gohugoio/hugo/hugolib"
|
||||||
|
@ -30,7 +32,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/create"
|
"github.com/gohugoio/hugo/create"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewContent(t *testing.T) {
|
func TestNewContent(t *testing.T) {
|
||||||
|
@ -245,7 +246,7 @@ func readFileFromFs(t *testing.T, fs afero.Fs, filename string) string {
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestCfg(c *qt.C, mm afero.Fs) (*viper.Viper, *hugofs.Fs) {
|
func newTestCfg(c *qt.C, mm afero.Fs) (config.Provider, *hugofs.Fs) {
|
||||||
cfg := `
|
cfg := `
|
||||||
|
|
||||||
theme = "mytheme"
|
theme = "mytheme"
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeConfigFromTOML(t *testing.T) {
|
func TestDecodeConfigFromTOML(t *testing.T) {
|
||||||
|
@ -164,7 +164,7 @@ Pattern = "[" # invalid regular expression
|
||||||
func TestDecodeConfigDefault(t *testing.T) {
|
func TestDecodeConfigDefault(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
dcfg, err := decodeConfig(viper.New())
|
dcfg, err := decodeConfig(config.New())
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(len(dcfg.Targets), qt.Equals, 0)
|
c.Assert(len(dcfg.Targets), qt.Equals, 0)
|
||||||
c.Assert(len(dcfg.Matchers), qt.Equals, 0)
|
c.Assert(len(dcfg.Matchers), qt.Equals, 0)
|
||||||
|
|
|
@ -7,7 +7,7 @@ footnotereturnlinkcontents = "↩"
|
||||||
languageCode = "en-us"
|
languageCode = "en-us"
|
||||||
title = "Hugo"
|
title = "Hugo"
|
||||||
|
|
||||||
ignoreErrors = ["error-remote-getjson"]
|
ignoreErrors = ["error-remote-getjson", "err-missing-instagram-accesstoken"]
|
||||||
|
|
||||||
|
|
||||||
googleAnalytics = "UA-7131036-4"
|
googleAnalytics = "UA-7131036-4"
|
||||||
|
|
|
@ -80,6 +80,26 @@ Considering the structure above, when running `hugo --environment staging`, Hugo
|
||||||
{{% note %}}
|
{{% note %}}
|
||||||
Default environments are __development__ with `hugo server` and __production__ with `hugo`.
|
Default environments are __development__ with `hugo server` and __production__ with `hugo`.
|
||||||
{{%/ note %}}
|
{{%/ note %}}
|
||||||
|
|
||||||
|
## Merge Configuration from Themes
|
||||||
|
|
||||||
|
{{< new-in "0.84.0" >}} The configuration merge described below was improved in Hugo 0.84.0 and made fully configurable. The big change/improvement was that we now, by default, do deep merging of `params` maps from themes.
|
||||||
|
|
||||||
|
The configuration value for `_merge` can be one of:
|
||||||
|
|
||||||
|
none
|
||||||
|
: No merge.
|
||||||
|
|
||||||
|
shallow
|
||||||
|
: Only add values for new keys.
|
||||||
|
|
||||||
|
shallow
|
||||||
|
: Add values for new keys, merge existing.
|
||||||
|
|
||||||
|
Note that you don't need to be so verbose as in the default setup below; a `_merge` value higher up will be inherited if not set.
|
||||||
|
|
||||||
|
{{< code-toggle config="mergeStrategy" skipHeader=true />}}
|
||||||
|
|
||||||
## All Configuration Settings
|
## All Configuration Settings
|
||||||
|
|
||||||
The following is the full list of Hugo-defined variables with their default
|
The following is the full list of Hugo-defined variables with their default
|
||||||
|
|
|
@ -1587,6 +1587,65 @@
|
||||||
"preserveTOC": false
|
"preserveTOC": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mergeStrategy": {
|
||||||
|
"build": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"caches": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"frontmatter": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"imaging": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"languages": {
|
||||||
|
"_merge": "none",
|
||||||
|
"en": {
|
||||||
|
"_merge": "none",
|
||||||
|
"menus": {
|
||||||
|
"_merge": "shallow"
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"_merge": "deep"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"markup": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"mediatypes": {
|
||||||
|
"_merge": "shallow"
|
||||||
|
},
|
||||||
|
"menus": {
|
||||||
|
"_merge": "shallow"
|
||||||
|
},
|
||||||
|
"minify": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"module": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"outputformats": {
|
||||||
|
"_merge": "shallow"
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"_merge": "deep"
|
||||||
|
},
|
||||||
|
"permalinks": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"related": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"sitemap": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
|
"taxonomies": {
|
||||||
|
"_merge": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
"minify": {
|
"minify": {
|
||||||
"minifyOutput": false,
|
"minifyOutput": false,
|
||||||
"disableHTML": false,
|
"disableHTML": false,
|
||||||
|
|
|
@ -1,34 +1,41 @@
|
||||||
{{ $file := .Get "file" }}
|
{{ $file := .Get "file" }}
|
||||||
{{ $code := "" }}
|
{{ $code := "" }}
|
||||||
{{ with .Get "config" }}
|
{{ with .Get "config" }}
|
||||||
{{ $file = $file | default "config" }}
|
{{ $file = $file | default "config" }}
|
||||||
{{ $sections := (split . ".") }}
|
{{ $sections := (split . ".") }}
|
||||||
{{ $configSection := index $.Site.Data.docs.config $sections }}
|
{{ $configSection := index $.Site.Data.docs.config $sections }}
|
||||||
{{ $code = dict $sections $configSection }}
|
{{ $code = dict $sections $configSection }}
|
||||||
|
{{ if $.Get "skipHeader"}}
|
||||||
|
{{ $code = $configSection }}
|
||||||
|
{{ end }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{ $code = $.Inner }}
|
{{ $code = $.Inner }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ $langs := (slice "yaml" "toml" "json") }}
|
{{ $langs := (slice "yaml" "toml" "json") }}
|
||||||
<div class="code relative" {{ with $file }}id="{{ . | urlize}}"{{ end }}>
|
<div class="code relative" {{ with $file }}id="{{ . | urlize}}"{{ end }}>
|
||||||
<div class="code-nav flex flex-nowrap items-stretch">
|
<div class="code-nav flex flex-nowrap items-stretch">
|
||||||
{{- with $file -}}
|
{{- with $file -}}
|
||||||
<div class="san-serif f6 dib lh-solid pl2 pv2 mr2">{{ . }}.</div>
|
<div class="san-serif f6 dib lh-solid pl2 pv2 mr2">
|
||||||
{{- end -}}
|
{{ . }}.
|
||||||
{{ range $langs }}
|
</div>
|
||||||
<button data-toggle-tab="{{ . }}" class="tab-button {{ cond (eq . "yaml") "active" ""}} ba san-serif f6 dib lh-solid ph2 pv2">{{ . }}</button>
|
{{- end -}}
|
||||||
{{ end }}
|
{{ range $langs }}
|
||||||
</div>
|
<button data-toggle-tab="{{ . }}" class="tab-button {{ cond (eq . "yaml") "active" ""}} ba san-serif f6 dib lh-solid ph2 pv2">
|
||||||
<div class="tab-content">
|
{{ . }}
|
||||||
{{ range $langs }}
|
</button>
|
||||||
<div data-pane="{{ . }}" class="code-copy-content nt3 tab-pane {{ cond (eq . "yaml") "active" ""}}">
|
|
||||||
{{ highlight ($code | transform.Remarshal . | safeHTML) . ""}}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{ if ne ($.Get "copy") "false" }}
|
<div class="tab-content">
|
||||||
<button class="needs-js copy copy-toggle bg-accent-color-dark f6 absolute top-0 right-0 lh-solid hover-bg-primary-color-dark bn white ph3 pv2" title="Copy this code to your clipboard." data-clipboard-action="copy" aria-label="copy button">
|
{{ range $langs }}
|
||||||
</button>
|
<div data-pane="{{ . }}" class="code-copy-content nt3 tab-pane {{ cond (eq . "yaml") "active" ""}}">
|
||||||
{{/* Functionality located within filesaver.js The copy here is located in the css with .copy class so it can be replaced with JS on success */}}
|
{{ highlight ($code | transform.Remarshal . | safeHTML) . ""}}
|
||||||
{{end}}
|
</div>
|
||||||
{{ end }}
|
{{ if ne ($.Get "copy") "false" }}
|
||||||
</div>
|
<button class="needs-js copy copy-toggle bg-accent-color-dark f6 absolute top-0 right-0 lh-solid hover-bg-primary-color-dark bn white ph3 pv2" title="Copy this code to your clipboard." data-clipboard-action="copy" aria-label="copy button"></button>
|
||||||
|
{{/* Functionality located within filesaver.js The copy here is located in the css with .copy class so it can be replaced with JS on success */}}
|
||||||
|
{{end}}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -55,7 +55,7 @@ require (
|
||||||
github.com/spf13/fsync v0.9.0
|
github.com/spf13/fsync v0.9.0
|
||||||
github.com/spf13/jwalterweatherman v1.1.0
|
github.com/spf13/jwalterweatherman v1.1.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.0
|
||||||
github.com/tdewolff/minify/v2 v2.9.16
|
github.com/tdewolff/minify/v2 v2.9.16
|
||||||
github.com/yuin/goldmark v1.3.5
|
github.com/yuin/goldmark v1.3.5
|
||||||
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691
|
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691
|
||||||
|
|
1
go.sum
1
go.sum
|
@ -642,6 +642,7 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
|
|
|
@ -19,12 +19,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ func TestBytesToHTML(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewContentSpec(t *testing.T) {
|
func TestNewContentSpec(t *testing.T) {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg.Set("summaryLength", 32)
|
cfg.Set("summaryLength", 32)
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
func TestResolveMarkup(t *testing.T) {
|
func TestResolveMarkup(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs())
|
spec, err := NewContentSpec(cfg, loggers.NewErrorLogger(), afero.NewMemMapFs())
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMakePath(t *testing.T) {
|
func TestMakePath(t *testing.T) {
|
||||||
|
@ -490,8 +489,6 @@ func TestExists(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAbsPathify(t *testing.T) {
|
func TestAbsPathify(t *testing.T) {
|
||||||
defer viper.Reset()
|
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
inPath, workingDir, expected string
|
inPath, workingDir, expected string
|
||||||
}
|
}
|
||||||
|
@ -511,7 +508,6 @@ func TestAbsPathify(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, d := range data {
|
for i, d := range data {
|
||||||
viper.Reset()
|
|
||||||
// todo see comment in AbsPathify
|
// todo see comment in AbsPathify
|
||||||
ps := newTestDefaultPathSpec("workingDir", d.workingDir)
|
ps := newTestDefaultPathSpec("workingDir", d.workingDir)
|
||||||
|
|
||||||
|
|
|
@ -2,24 +2,24 @@ package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newTestPathSpec(fs *hugofs.Fs, v *viper.Viper) *PathSpec {
|
func newTestPathSpec(fs *hugofs.Fs, v config.Provider) *PathSpec {
|
||||||
l := langs.NewDefaultLanguage(v)
|
l := langs.NewDefaultLanguage(v)
|
||||||
ps, _ := NewPathSpec(fs, l, nil)
|
ps, _ := NewPathSpec(fs, l, nil)
|
||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestDefaultPathSpec(configKeyValues ...interface{}) *PathSpec {
|
func newTestDefaultPathSpec(configKeyValues ...interface{}) *PathSpec {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
cfg := newTestCfgFor(fs)
|
cfg := newTestCfg()
|
||||||
|
|
||||||
for i := 0; i < len(configKeyValues); i += 2 {
|
for i := 0; i < len(configKeyValues); i += 2 {
|
||||||
cfg.Set(configKeyValues[i].(string), configKeyValues[i+1])
|
cfg.Set(configKeyValues[i].(string), configKeyValues[i+1])
|
||||||
|
@ -27,15 +27,8 @@ func newTestDefaultPathSpec(configKeyValues ...interface{}) *PathSpec {
|
||||||
return newTestPathSpec(fs, cfg)
|
return newTestPathSpec(fs, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestCfgFor(fs *hugofs.Fs) *viper.Viper {
|
func newTestCfg() config.Provider {
|
||||||
v := newTestCfg()
|
v := config.New()
|
||||||
v.SetFs(fs.Source)
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestCfg() *viper.Viper {
|
|
||||||
v := viper.New()
|
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
v.Set("dataDir", "data")
|
v.Set("dataDir", "data")
|
||||||
v.Set("i18nDir", "i18n")
|
v.Set("i18nDir", "i18n")
|
||||||
|
@ -56,7 +49,7 @@ func newTestCfg() *viper.Viper {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestContentSpec() *ContentSpec {
|
func newTestContentSpec() *ContentSpec {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
spec, err := NewContentSpec(v, loggers.NewErrorLogger(), afero.NewMemMapFs())
|
spec, err := NewContentSpec(v, loggers.NewErrorLogger(), afero.NewMemMapFs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -16,15 +16,16 @@ package hugofs
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewDefault(t *testing.T) {
|
func TestNewDefault(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
f := NewDefault(v)
|
f := NewDefault(v)
|
||||||
|
|
||||||
c.Assert(f.Source, qt.Not(qt.IsNil))
|
c.Assert(f.Source, qt.Not(qt.IsNil))
|
||||||
|
@ -35,7 +36,7 @@ func TestNewDefault(t *testing.T) {
|
||||||
|
|
||||||
func TestNewMem(t *testing.T) {
|
func TestNewMem(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
f := NewMem(v)
|
f := NewMem(v)
|
||||||
|
|
||||||
c.Assert(f.Source, qt.Not(qt.IsNil))
|
c.Assert(f.Source, qt.Not(qt.IsNil))
|
||||||
|
@ -48,7 +49,7 @@ func TestNewMem(t *testing.T) {
|
||||||
|
|
||||||
func TestWorkingDir(t *testing.T) {
|
func TestWorkingDir(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
v.Set("workingDir", "/a/b/")
|
v.Set("workingDir", "/a/b/")
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
func TestLanguageRootMapping(t *testing.T) {
|
func TestLanguageRootMapping(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
|
|
||||||
fs := NewBaseFileDecorator(afero.NewMemMapFs())
|
fs := NewBaseFileDecorator(afero.NewMemMapFs())
|
||||||
|
|
|
@ -43,34 +43,136 @@ import (
|
||||||
"github.com/gohugoio/hugo/config/services"
|
"github.com/gohugoio/hugo/config/services"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SiteConfig represents the config in .Site.Config.
|
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")
|
||||||
type SiteConfig struct {
|
|
||||||
// This contains all privacy related settings that can be used to
|
|
||||||
// make the YouTube template etc. GDPR compliant.
|
|
||||||
Privacy privacy.Config
|
|
||||||
|
|
||||||
// Services contains config for services such as Google Analytics etc.
|
// LoadConfig loads Hugo configuration into a new Viper and then adds
|
||||||
Services services.Config
|
// a set of defaults.
|
||||||
|
func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provider) error) (config.Provider, []string, error) {
|
||||||
|
|
||||||
|
if d.Environment == "" {
|
||||||
|
d.Environment = hugo.EnvironmentProduction
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(d.Environ) == 0 {
|
||||||
|
d.Environ = os.Environ()
|
||||||
|
}
|
||||||
|
|
||||||
|
var configFiles []string
|
||||||
|
|
||||||
|
l := configLoader{ConfigSourceDescriptor: d, cfg: config.New()}
|
||||||
|
|
||||||
|
if err := l.applyConfigDefaults(); err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range d.configFilenames() {
|
||||||
|
var filename string
|
||||||
|
filename, err := l.loadConfig(name)
|
||||||
|
if err == nil {
|
||||||
|
configFiles = append(configFiles, filename)
|
||||||
|
} else if err != ErrNoConfigFile {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.AbsConfigDir != "" {
|
||||||
|
dirnames, err := l.loadConfigFromConfigDir()
|
||||||
|
if err == nil {
|
||||||
|
configFiles = append(configFiles, dirnames...)
|
||||||
|
} else if err != ErrNoConfigFile {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// all configuration is loaded/set before doing that.
|
||||||
|
for _, d := range doWithConfig {
|
||||||
|
if err := d(l.cfg); err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We made this a Glob pattern in Hugo 0.75, we don't need both.
|
||||||
|
if l.cfg.GetBool("ignoreVendor") {
|
||||||
|
helpers.Deprecated("--ignoreVendor", "--ignoreVendorPaths **", false)
|
||||||
|
l.cfg.Set("ignoreVendorPaths", "**")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some settings are used before we're done collecting all settings,
|
||||||
|
// so apply OS environment both before and after.
|
||||||
|
if err := l.applyOsEnvOverrides(d.Environ); err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
modulesConfig, err := l.loadModulesConfig()
|
||||||
|
if err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to run these after the modules are loaded, but before
|
||||||
|
// they are finalized.
|
||||||
|
collectHook := func(m *modules.ModulesConfig) error {
|
||||||
|
// We don't need the merge strategy configuration anymore,
|
||||||
|
// remove it so it doesn't accidentaly show up in other settings.
|
||||||
|
l.cfg.WalkParams(func(params ...config.KeyParams) bool {
|
||||||
|
params[len(params)-1].Params.DeleteMergeStrategy()
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := l.loadLanguageSettings(nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mods := m.ActiveModules
|
||||||
|
|
||||||
|
// Apply default project mounts.
|
||||||
|
if err := modules.ApplyProjectConfigDefaults(l.cfg, mods[0]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, modulesConfigFiles, err := l.collectModules(modulesConfig, l.cfg, collectHook)
|
||||||
|
if err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
configFiles = append(configFiles, modulesConfigFiles...)
|
||||||
|
|
||||||
|
if err := l.applyOsEnvOverrides(d.Environ); err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = l.applyConfigAliases(); err != nil {
|
||||||
|
return l.cfg, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return l.cfg, configFiles, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSiteConfig(cfg config.Provider) (scfg SiteConfig, err error) {
|
// LoadConfigDefault is a convenience method to load the default "config.toml" config.
|
||||||
privacyConfig, err := privacy.DecodeConfig(cfg)
|
func LoadConfigDefault(fs afero.Fs) (config.Provider, error) {
|
||||||
if err != nil {
|
v, _, err := LoadConfig(ConfigSourceDescriptor{Fs: fs, Filename: "config.toml"})
|
||||||
return
|
return v, err
|
||||||
}
|
|
||||||
|
|
||||||
servicesConfig, err := services.DecodeConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
scfg.Privacy = privacyConfig
|
|
||||||
scfg.Services = servicesConfig
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigSourceDescriptor describes where to find the config (e.g. config.toml etc.).
|
// ConfigSourceDescriptor describes where to find the config (e.g. config.toml etc.).
|
||||||
|
@ -98,13 +200,6 @@ type ConfigSourceDescriptor struct {
|
||||||
Environ []string
|
Environ []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d ConfigSourceDescriptor) configFilenames() []string {
|
|
||||||
if d.Filename == "" {
|
|
||||||
return []string{"config"}
|
|
||||||
}
|
|
||||||
return strings.Split(d.Filename, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d ConfigSourceDescriptor) configFileDir() string {
|
func (d ConfigSourceDescriptor) configFileDir() string {
|
||||||
if d.Path != "" {
|
if d.Path != "" {
|
||||||
return d.Path
|
return d.Path
|
||||||
|
@ -112,178 +207,226 @@ func (d ConfigSourceDescriptor) configFileDir() string {
|
||||||
return d.WorkingDir
|
return d.WorkingDir
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfigDefault is a convenience method to load the default "config.toml" config.
|
func (d ConfigSourceDescriptor) configFilenames() []string {
|
||||||
func LoadConfigDefault(fs afero.Fs) (*viper.Viper, error) {
|
if d.Filename == "" {
|
||||||
v, _, err := LoadConfig(ConfigSourceDescriptor{Fs: fs, Filename: "config.toml"})
|
return []string{"config"}
|
||||||
return v, err
|
}
|
||||||
|
return strings.Split(d.Filename, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
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")
|
// SiteConfig represents the config in .Site.Config.
|
||||||
|
type SiteConfig struct {
|
||||||
|
// This contains all privacy related settings that can be used to
|
||||||
|
// make the YouTube template etc. GDPR compliant.
|
||||||
|
Privacy privacy.Config
|
||||||
|
|
||||||
// LoadConfig loads Hugo configuration into a new Viper and then adds
|
// Services contains config for services such as Google Analytics etc.
|
||||||
// a set of defaults.
|
Services services.Config
|
||||||
func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provider) error) (*viper.Viper, []string, error) {
|
|
||||||
if d.Environment == "" {
|
|
||||||
d.Environment = hugo.EnvironmentProduction
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(d.Environ) == 0 {
|
|
||||||
d.Environ = os.Environ()
|
|
||||||
}
|
|
||||||
|
|
||||||
var configFiles []string
|
|
||||||
|
|
||||||
v := viper.New()
|
|
||||||
l := configLoader{ConfigSourceDescriptor: d}
|
|
||||||
|
|
||||||
for _, name := range d.configFilenames() {
|
|
||||||
var filename string
|
|
||||||
filename, err := l.loadConfig(name, v)
|
|
||||||
if err == nil {
|
|
||||||
configFiles = append(configFiles, filename)
|
|
||||||
} else if err != ErrNoConfigFile {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.AbsConfigDir != "" {
|
|
||||||
dirnames, err := l.loadConfigFromConfigDir(v)
|
|
||||||
if err == nil {
|
|
||||||
configFiles = append(configFiles, dirnames...)
|
|
||||||
} else if err != ErrNoConfigFile {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := loadDefaultSettingsFor(v); err != nil {
|
|
||||||
return v, configFiles, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We create languages based on the settings, so we need to make sure that
|
|
||||||
// all configuration is loaded/set before doing that.
|
|
||||||
for _, d := range doWithConfig {
|
|
||||||
if err := d(v); err != nil {
|
|
||||||
return v, configFiles, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is invoked both after we load the main config and at the end
|
|
||||||
// to support OS env override of config options used in the module collector.
|
|
||||||
applyOsEnvOverrides := func() error {
|
|
||||||
if d.Environ == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const delim = "__env__delim"
|
|
||||||
|
|
||||||
// Extract all that start with the HUGO prefix.
|
|
||||||
// The delimiter is the following rune, usually "_".
|
|
||||||
const hugoEnvPrefix = "HUGO"
|
|
||||||
var hugoEnv []types.KeyValueStr
|
|
||||||
for _, v := range d.Environ {
|
|
||||||
key, val := config.SplitEnvVar(v)
|
|
||||||
if strings.HasPrefix(key, hugoEnvPrefix) {
|
|
||||||
delimiterAndKey := strings.TrimPrefix(key, hugoEnvPrefix)
|
|
||||||
if len(delimiterAndKey) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Allow delimiters to be case sensitive.
|
|
||||||
// It turns out there isn't that many allowed special
|
|
||||||
// chars in environment variables when used in Bash and similar,
|
|
||||||
// so variables on the form HUGOxPARAMSxFOO=bar is one option.
|
|
||||||
key := strings.ReplaceAll(delimiterAndKey[1:], delimiterAndKey[:1], delim)
|
|
||||||
key = strings.ToLower(key)
|
|
||||||
hugoEnv = append(hugoEnv, types.KeyValueStr{
|
|
||||||
Key: key,
|
|
||||||
Value: val,
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, env := range hugoEnv {
|
|
||||||
existing, nestedKey, owner, err := maps.GetNestedParamFn(env.Key, delim, v.Get)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if existing != nil {
|
|
||||||
val, err := metadecoders.Default.UnmarshalStringTo(env.Value, existing)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if owner != nil {
|
|
||||||
owner[nestedKey] = val
|
|
||||||
} else {
|
|
||||||
v.Set(env.Key, val)
|
|
||||||
}
|
|
||||||
} else if nestedKey != "" {
|
|
||||||
owner[nestedKey] = env.Value
|
|
||||||
} else {
|
|
||||||
v.Set(strings.ReplaceAll(env.Key, delim, "."), env.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := applyOsEnvOverrides(); err != nil {
|
|
||||||
return v, configFiles, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// We made this a Glob pattern in Hugo 0.75, we don't need both.
|
|
||||||
if v.GetBool("ignoreVendor") {
|
|
||||||
helpers.Deprecated("--ignoreVendor", "--ignoreVendorPaths **", false)
|
|
||||||
v.Set("ignoreVendorPaths", "**")
|
|
||||||
}
|
|
||||||
|
|
||||||
modulesConfig, err := l.loadModulesConfig(v)
|
|
||||||
if err != nil {
|
|
||||||
return v, configFiles, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to run these after the modules are loaded, but before
|
|
||||||
// they are finalized.
|
|
||||||
collectHook := func(m *modules.ModulesConfig) error {
|
|
||||||
if err := loadLanguageSettings(v, nil); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mods := m.ActiveModules
|
|
||||||
|
|
||||||
// Apply default project mounts.
|
|
||||||
if err := modules.ApplyProjectConfigDefaults(v, mods[0]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, modulesConfigFiles, err := l.collectModules(modulesConfig, v, collectHook)
|
|
||||||
|
|
||||||
if err == nil && len(modulesConfigFiles) > 0 {
|
|
||||||
configFiles = append(configFiles, modulesConfigFiles...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := applyOsEnvOverrides(); err != nil {
|
|
||||||
return v, configFiles, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return v, configFiles, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadLanguageSettings(cfg config.Provider, oldLangs langs.Languages) error {
|
|
||||||
_, err := langs.LoadLanguageSettings(cfg, oldLangs)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type configLoader struct {
|
type configLoader struct {
|
||||||
|
cfg config.Provider
|
||||||
ConfigSourceDescriptor
|
ConfigSourceDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l configLoader) loadConfig(configName string, v *viper.Viper) (string, error) {
|
// Handle some legacy values.
|
||||||
|
func (l configLoader) applyConfigAliases() error {
|
||||||
|
aliases := []types.KeyValueStr{{Key: "taxonomies", Value: "indexes"}}
|
||||||
|
|
||||||
|
for _, alias := range aliases {
|
||||||
|
if l.cfg.IsSet(alias.Key) {
|
||||||
|
vv := l.cfg.Get(alias.Key)
|
||||||
|
l.cfg.Set(alias.Value, vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l configLoader) applyConfigDefaults() error {
|
||||||
|
defaultSettings := maps.Params{
|
||||||
|
"cleanDestinationDir": false,
|
||||||
|
"watch": false,
|
||||||
|
"resourceDir": "resources",
|
||||||
|
"publishDir": "public",
|
||||||
|
"themesDir": "themes",
|
||||||
|
"buildDrafts": false,
|
||||||
|
"buildFuture": false,
|
||||||
|
"buildExpired": false,
|
||||||
|
"environment": hugo.EnvironmentProduction,
|
||||||
|
"uglyURLs": false,
|
||||||
|
"verbose": false,
|
||||||
|
"ignoreCache": false,
|
||||||
|
"canonifyURLs": false,
|
||||||
|
"relativeURLs": false,
|
||||||
|
"removePathAccents": false,
|
||||||
|
"titleCaseStyle": "AP",
|
||||||
|
"taxonomies": map[string]string{"tag": "tags", "category": "categories"},
|
||||||
|
"permalinks": make(map[string]string),
|
||||||
|
"sitemap": config.Sitemap{Priority: -1, Filename: "sitemap.xml"},
|
||||||
|
"disableLiveReload": false,
|
||||||
|
"pluralizeListTitles": true,
|
||||||
|
"forceSyncStatic": false,
|
||||||
|
"footnoteAnchorPrefix": "",
|
||||||
|
"footnoteReturnLinkContents": "",
|
||||||
|
"newContentEditor": "",
|
||||||
|
"paginate": 10,
|
||||||
|
"paginatePath": "page",
|
||||||
|
"summaryLength": 70,
|
||||||
|
"rssLimit": -1,
|
||||||
|
"sectionPagesMenu": "",
|
||||||
|
"disablePathToLower": false,
|
||||||
|
"hasCJKLanguage": false,
|
||||||
|
"enableEmoji": false,
|
||||||
|
"pygmentsCodeFencesGuessSyntax": false,
|
||||||
|
"defaultContentLanguage": "en",
|
||||||
|
"defaultContentLanguageInSubdir": false,
|
||||||
|
"enableMissingTranslationPlaceholders": false,
|
||||||
|
"enableGitInfo": false,
|
||||||
|
"ignoreFiles": make([]string, 0),
|
||||||
|
"disableAliases": false,
|
||||||
|
"debug": false,
|
||||||
|
"disableFastRender": false,
|
||||||
|
"timeout": "30s",
|
||||||
|
"enableInlineShortcodes": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
l.cfg.Merge("", defaultSettings)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l configLoader) applyOsEnvOverrides(environ []string) error {
|
||||||
|
if len(environ) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const delim = "__env__delim"
|
||||||
|
|
||||||
|
// Extract all that start with the HUGO prefix.
|
||||||
|
// The delimiter is the following rune, usually "_".
|
||||||
|
const hugoEnvPrefix = "HUGO"
|
||||||
|
var hugoEnv []types.KeyValueStr
|
||||||
|
for _, v := range environ {
|
||||||
|
key, val := config.SplitEnvVar(v)
|
||||||
|
if strings.HasPrefix(key, hugoEnvPrefix) {
|
||||||
|
delimiterAndKey := strings.TrimPrefix(key, hugoEnvPrefix)
|
||||||
|
if len(delimiterAndKey) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Allow delimiters to be case sensitive.
|
||||||
|
// It turns out there isn't that many allowed special
|
||||||
|
// chars in environment variables when used in Bash and similar,
|
||||||
|
// so variables on the form HUGOxPARAMSxFOO=bar is one option.
|
||||||
|
key := strings.ReplaceAll(delimiterAndKey[1:], delimiterAndKey[:1], delim)
|
||||||
|
key = strings.ToLower(key)
|
||||||
|
hugoEnv = append(hugoEnv, types.KeyValueStr{
|
||||||
|
Key: key,
|
||||||
|
Value: val,
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, env := range hugoEnv {
|
||||||
|
existing, nestedKey, owner, err := maps.GetNestedParamFn(env.Key, delim, l.cfg.Get)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if existing != nil {
|
||||||
|
val, err := metadecoders.Default.UnmarshalStringTo(env.Value, existing)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if owner != nil {
|
||||||
|
owner[nestedKey] = val
|
||||||
|
} else {
|
||||||
|
l.cfg.Set(env.Key, val)
|
||||||
|
}
|
||||||
|
} else if nestedKey != "" {
|
||||||
|
owner[nestedKey] = env.Value
|
||||||
|
} else {
|
||||||
|
// The container does not exist yet.
|
||||||
|
l.cfg.Set(strings.ReplaceAll(env.Key, delim, "."), env.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l configLoader) collectModules(modConfig modules.Config, v1 config.Provider, hookBeforeFinalize func(m *modules.ModulesConfig) error) (modules.Modules, []string, error) {
|
||||||
|
workingDir := l.WorkingDir
|
||||||
|
if workingDir == "" {
|
||||||
|
workingDir = v1.GetString("workingDir")
|
||||||
|
}
|
||||||
|
|
||||||
|
themesDir := paths.AbsPathify(l.WorkingDir, v1.GetString("themesDir"))
|
||||||
|
|
||||||
|
var ignoreVendor glob.Glob
|
||||||
|
if s := v1.GetString("ignoreVendorPaths"); s != "" {
|
||||||
|
ignoreVendor, _ = hglob.GetGlob(hglob.NormalizePath(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
filecacheConfigs, err := filecache.DecodeConfig(l.Fs, v1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v1.Set("filecacheConfigs", filecacheConfigs)
|
||||||
|
|
||||||
|
var configFilenames []string
|
||||||
|
|
||||||
|
hook := func(m *modules.ModulesConfig) error {
|
||||||
|
for _, tc := range m.ActiveModules {
|
||||||
|
if tc.ConfigFilename() != "" {
|
||||||
|
if tc.Watch() {
|
||||||
|
configFilenames = append(configFilenames, tc.ConfigFilename())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge from theme config into v1 based on configured
|
||||||
|
// merge strategy.
|
||||||
|
v1.Merge("", tc.Cfg().Get(""))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hookBeforeFinalize != nil {
|
||||||
|
return hookBeforeFinalize(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
modulesClient := modules.NewClient(modules.ClientConfig{
|
||||||
|
Fs: l.Fs,
|
||||||
|
Logger: l.Logger,
|
||||||
|
HookBeforeFinalize: hook,
|
||||||
|
WorkingDir: workingDir,
|
||||||
|
ThemesDir: themesDir,
|
||||||
|
CacheDir: filecacheConfigs.CacheDirModules(),
|
||||||
|
ModuleConfig: modConfig,
|
||||||
|
IgnoreVendor: ignoreVendor,
|
||||||
|
})
|
||||||
|
|
||||||
|
v1.Set("modulesClient", modulesClient)
|
||||||
|
|
||||||
|
moduleConfig, err := modulesClient.Collect()
|
||||||
|
|
||||||
|
// Avoid recreating these later.
|
||||||
|
v1.Set("allModules", moduleConfig.ActiveModules)
|
||||||
|
|
||||||
|
if moduleConfig.GoModulesFilename != "" {
|
||||||
|
// We want to watch this for changes and trigger rebuild on version
|
||||||
|
// changes etc.
|
||||||
|
configFilenames = append(configFilenames, moduleConfig.GoModulesFilename)
|
||||||
|
}
|
||||||
|
|
||||||
|
return moduleConfig.ActiveModules, configFilenames, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l configLoader) loadConfig(configName string) (string, error) {
|
||||||
baseDir := l.configFileDir()
|
baseDir := l.configFileDir()
|
||||||
var baseFilename string
|
var baseFilename string
|
||||||
if filepath.IsAbs(configName) {
|
if filepath.IsAbs(configName) {
|
||||||
|
@ -318,24 +461,13 @@ func (l configLoader) loadConfig(configName string, v *viper.Viper) (string, err
|
||||||
return "", l.wrapFileError(err, filename)
|
return "", l.wrapFileError(err, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = v.MergeConfigMap(m); err != nil {
|
// Set overwrites keys of the same name, recursively.
|
||||||
return "", l.wrapFileError(err, filename)
|
l.cfg.Set("", m)
|
||||||
}
|
|
||||||
|
|
||||||
return filename, nil
|
return filename, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l configLoader) wrapFileError(err error, filename string) error {
|
func (l configLoader) loadConfigFromConfigDir() ([]string, error) {
|
||||||
err, _ = herrors.WithFileContextForFile(
|
|
||||||
err,
|
|
||||||
filename,
|
|
||||||
filename,
|
|
||||||
l.Fs,
|
|
||||||
herrors.SimpleLineMatcher)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l configLoader) loadConfigFromConfigDir(v *viper.Viper) ([]string, error) {
|
|
||||||
sourceFs := l.Fs
|
sourceFs := l.Fs
|
||||||
configDir := l.AbsConfigDir
|
configDir := l.AbsConfigDir
|
||||||
|
|
||||||
|
@ -421,9 +553,8 @@ func (l configLoader) loadConfigFromConfigDir(v *viper.Viper) ([]string, error)
|
||||||
// Migrate menu => menus etc.
|
// Migrate menu => menus etc.
|
||||||
config.RenameKeys(root)
|
config.RenameKeys(root)
|
||||||
|
|
||||||
if err := v.MergeConfigMap(root); err != nil {
|
// Set will overwrite keys with the same name, recursively.
|
||||||
return l.wrapFileError(err, path)
|
l.cfg.Set("", root)
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -436,8 +567,13 @@ func (l configLoader) loadConfigFromConfigDir(v *viper.Viper) ([]string, error)
|
||||||
return dirnames, nil
|
return dirnames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l configLoader) loadModulesConfig(v1 *viper.Viper) (modules.Config, error) {
|
func (l configLoader) loadLanguageSettings(oldLangs langs.Languages) error {
|
||||||
modConfig, err := modules.DecodeConfig(v1)
|
_, err := langs.LoadLanguageSettings(l.cfg, oldLangs)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l configLoader) loadModulesConfig() (modules.Config, error) {
|
||||||
|
modConfig, err := modules.DecodeConfig(l.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return modules.Config{}, err
|
return modules.Config{}, err
|
||||||
}
|
}
|
||||||
|
@ -445,211 +581,29 @@ func (l configLoader) loadModulesConfig(v1 *viper.Viper) (modules.Config, error)
|
||||||
return modConfig, nil
|
return modConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l configLoader) collectModules(modConfig modules.Config, v1 *viper.Viper, hookBeforeFinalize func(m *modules.ModulesConfig) error) (modules.Modules, []string, error) {
|
func (configLoader) loadSiteConfig(cfg config.Provider) (scfg SiteConfig, err error) {
|
||||||
workingDir := l.WorkingDir
|
privacyConfig, err := privacy.DecodeConfig(cfg)
|
||||||
if workingDir == "" {
|
|
||||||
workingDir = v1.GetString("workingDir")
|
|
||||||
}
|
|
||||||
|
|
||||||
themesDir := paths.AbsPathify(l.WorkingDir, v1.GetString("themesDir"))
|
|
||||||
|
|
||||||
var ignoreVendor glob.Glob
|
|
||||||
if s := v1.GetString("ignoreVendorPaths"); s != "" {
|
|
||||||
ignoreVendor, _ = hglob.GetGlob(hglob.NormalizePath(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
filecacheConfigs, err := filecache.DecodeConfig(l.Fs, v1)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
v1.Set("filecacheConfigs", filecacheConfigs)
|
|
||||||
|
|
||||||
var configFilenames []string
|
|
||||||
|
|
||||||
hook := func(m *modules.ModulesConfig) error {
|
|
||||||
for _, tc := range m.ActiveModules {
|
|
||||||
if tc.ConfigFilename() != "" {
|
|
||||||
if tc.Watch() {
|
|
||||||
configFilenames = append(configFilenames, tc.ConfigFilename())
|
|
||||||
}
|
|
||||||
if err := l.applyThemeConfig(v1, tc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if hookBeforeFinalize != nil {
|
|
||||||
return hookBeforeFinalize(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
modulesClient := modules.NewClient(modules.ClientConfig{
|
|
||||||
Fs: l.Fs,
|
|
||||||
Logger: l.Logger,
|
|
||||||
HookBeforeFinalize: hook,
|
|
||||||
WorkingDir: workingDir,
|
|
||||||
ThemesDir: themesDir,
|
|
||||||
CacheDir: filecacheConfigs.CacheDirModules(),
|
|
||||||
ModuleConfig: modConfig,
|
|
||||||
IgnoreVendor: ignoreVendor,
|
|
||||||
})
|
|
||||||
|
|
||||||
v1.Set("modulesClient", modulesClient)
|
|
||||||
|
|
||||||
moduleConfig, err := modulesClient.Collect()
|
|
||||||
|
|
||||||
// Avoid recreating these later.
|
|
||||||
v1.Set("allModules", moduleConfig.ActiveModules)
|
|
||||||
|
|
||||||
if moduleConfig.GoModulesFilename != "" {
|
|
||||||
// We want to watch this for changes and trigger rebuild on version
|
|
||||||
// changes etc.
|
|
||||||
configFilenames = append(configFilenames, moduleConfig.GoModulesFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
return moduleConfig.ActiveModules, configFilenames, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l configLoader) applyThemeConfig(v1 *viper.Viper, theme modules.Module) error {
|
|
||||||
const (
|
|
||||||
paramsKey = "params"
|
|
||||||
languagesKey = "languages"
|
|
||||||
menuKey = "menus"
|
|
||||||
)
|
|
||||||
|
|
||||||
v2 := theme.Cfg()
|
|
||||||
|
|
||||||
for _, key := range []string{paramsKey, "outputformats", "mediatypes"} {
|
|
||||||
l.mergeStringMapKeepLeft("", key, v1, v2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only add params and new menu entries, we do not add language definitions.
|
|
||||||
if v1.IsSet(languagesKey) && v2.IsSet(languagesKey) {
|
|
||||||
v1Langs := v1.GetStringMap(languagesKey)
|
|
||||||
for k := range v1Langs {
|
|
||||||
langParamsKey := languagesKey + "." + k + "." + paramsKey
|
|
||||||
l.mergeStringMapKeepLeft(paramsKey, langParamsKey, v1, v2)
|
|
||||||
}
|
|
||||||
v2Langs := v2.GetStringMap(languagesKey)
|
|
||||||
for k := range v2Langs {
|
|
||||||
if k == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
langMenuKey := languagesKey + "." + k + "." + menuKey
|
|
||||||
if v2.IsSet(langMenuKey) {
|
|
||||||
// Only add if not in the main config.
|
|
||||||
v2menus := v2.GetStringMap(langMenuKey)
|
|
||||||
for k, v := range v2menus {
|
|
||||||
menuEntry := menuKey + "." + k
|
|
||||||
menuLangEntry := langMenuKey + "." + k
|
|
||||||
if !v1.IsSet(menuEntry) && !v1.IsSet(menuLangEntry) {
|
|
||||||
v1.Set(menuLangEntry, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add menu definitions from theme not found in project
|
|
||||||
if v2.IsSet(menuKey) {
|
|
||||||
v2menus := v2.GetStringMap(menuKey)
|
|
||||||
for k, v := range v2menus {
|
|
||||||
menuEntry := menuKey + "." + k
|
|
||||||
if !v1.IsSet(menuEntry) {
|
|
||||||
v1.SetDefault(menuEntry, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (configLoader) mergeStringMapKeepLeft(rootKey, key string, v1, v2 config.Provider) {
|
|
||||||
if !v2.IsSet(key) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v1.IsSet(key) && !(rootKey != "" && rootKey != key && v1.IsSet(rootKey)) {
|
servicesConfig, err := services.DecodeConfig(cfg)
|
||||||
v1.Set(key, v2.Get(key))
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m1 := v1.GetStringMap(key)
|
scfg.Privacy = privacyConfig
|
||||||
m2 := v2.GetStringMap(key)
|
scfg.Services = servicesConfig
|
||||||
|
|
||||||
for k, v := range m2 {
|
return
|
||||||
if _, found := m1[k]; !found {
|
|
||||||
if rootKey != "" && v1.IsSet(rootKey+"."+k) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m1[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDefaultSettingsFor(v *viper.Viper) error {
|
func (l configLoader) wrapFileError(err error, filename string) error {
|
||||||
v.RegisterAlias("indexes", "taxonomies")
|
err, _ = herrors.WithFileContextForFile(
|
||||||
|
err,
|
||||||
/*
|
filename,
|
||||||
|
filename,
|
||||||
TODO(bep) from 0.56 these are configured as module mounts.
|
l.Fs,
|
||||||
v.SetDefault("contentDir", "content")
|
herrors.SimpleLineMatcher)
|
||||||
v.SetDefault("layoutDir", "layouts")
|
return err
|
||||||
v.SetDefault("assetDir", "assets")
|
|
||||||
v.SetDefault("staticDir", "static")
|
|
||||||
v.SetDefault("dataDir", "data")
|
|
||||||
v.SetDefault("i18nDir", "i18n")
|
|
||||||
v.SetDefault("archetypeDir", "archetypes")
|
|
||||||
*/
|
|
||||||
|
|
||||||
v.SetDefault("cleanDestinationDir", false)
|
|
||||||
v.SetDefault("watch", false)
|
|
||||||
v.SetDefault("resourceDir", "resources")
|
|
||||||
v.SetDefault("publishDir", "public")
|
|
||||||
v.SetDefault("themesDir", "themes")
|
|
||||||
v.SetDefault("buildDrafts", false)
|
|
||||||
v.SetDefault("buildFuture", false)
|
|
||||||
v.SetDefault("buildExpired", false)
|
|
||||||
v.SetDefault("environment", hugo.EnvironmentProduction)
|
|
||||||
v.SetDefault("uglyURLs", false)
|
|
||||||
v.SetDefault("verbose", false)
|
|
||||||
v.SetDefault("ignoreCache", false)
|
|
||||||
v.SetDefault("canonifyURLs", false)
|
|
||||||
v.SetDefault("relativeURLs", false)
|
|
||||||
v.SetDefault("removePathAccents", false)
|
|
||||||
v.SetDefault("titleCaseStyle", "AP")
|
|
||||||
v.SetDefault("taxonomies", map[string]string{"tag": "tags", "category": "categories"})
|
|
||||||
v.SetDefault("permalinks", make(map[string]string))
|
|
||||||
v.SetDefault("sitemap", config.Sitemap{Priority: -1, Filename: "sitemap.xml"})
|
|
||||||
v.SetDefault("disableLiveReload", false)
|
|
||||||
v.SetDefault("pluralizeListTitles", true)
|
|
||||||
v.SetDefault("forceSyncStatic", false)
|
|
||||||
v.SetDefault("footnoteAnchorPrefix", "")
|
|
||||||
v.SetDefault("footnoteReturnLinkContents", "")
|
|
||||||
v.SetDefault("newContentEditor", "")
|
|
||||||
v.SetDefault("paginate", 10)
|
|
||||||
v.SetDefault("paginatePath", "page")
|
|
||||||
v.SetDefault("summaryLength", 70)
|
|
||||||
v.SetDefault("rssLimit", -1)
|
|
||||||
v.SetDefault("sectionPagesMenu", "")
|
|
||||||
v.SetDefault("disablePathToLower", false)
|
|
||||||
v.SetDefault("hasCJKLanguage", false)
|
|
||||||
v.SetDefault("enableEmoji", false)
|
|
||||||
v.SetDefault("pygmentsCodeFencesGuessSyntax", false)
|
|
||||||
v.SetDefault("defaultContentLanguage", "en")
|
|
||||||
v.SetDefault("defaultContentLanguageInSubdir", false)
|
|
||||||
v.SetDefault("enableMissingTranslationPlaceholders", false)
|
|
||||||
v.SetDefault("enableGitInfo", false)
|
|
||||||
v.SetDefault("ignoreFiles", make([]string, 0))
|
|
||||||
v.SetDefault("disableAliases", false)
|
|
||||||
v.SetDefault("debug", false)
|
|
||||||
v.SetDefault("disableFastRender", false)
|
|
||||||
v.SetDefault("timeout", "30s")
|
|
||||||
v.SetDefault("enableInlineShortcodes", false)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,15 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/media"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadConfig(t *testing.T) {
|
func TestLoadConfig(t *testing.T) {
|
||||||
|
@ -77,12 +81,7 @@ func TestLoadConfigFromTheme(t *testing.T) {
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
mainConfigBasic := `
|
mainConfigTemplate := `
|
||||||
theme = "test-theme"
|
|
||||||
baseURL = "https://example.com/"
|
|
||||||
|
|
||||||
`
|
|
||||||
mainConfig := `
|
|
||||||
theme = "test-theme"
|
theme = "test-theme"
|
||||||
baseURL = "https://example.com/"
|
baseURL = "https://example.com/"
|
||||||
|
|
||||||
|
@ -90,9 +89,12 @@ baseURL = "https://example.com/"
|
||||||
date = ["date","publishDate"]
|
date = ["date","publishDate"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
MERGE_PARAMS
|
||||||
p1 = "p1 main"
|
p1 = "p1 main"
|
||||||
p2 = "p2 main"
|
[params.b]
|
||||||
top = "top"
|
b1 = "b1 main"
|
||||||
|
[params.b.c]
|
||||||
|
bc1 = "bc1 main"
|
||||||
|
|
||||||
[mediaTypes]
|
[mediaTypes]
|
||||||
[mediaTypes."text/m1"]
|
[mediaTypes."text/m1"]
|
||||||
|
@ -130,7 +132,14 @@ expiryDate = ["date"]
|
||||||
[params]
|
[params]
|
||||||
p1 = "p1 theme"
|
p1 = "p1 theme"
|
||||||
p2 = "p2 theme"
|
p2 = "p2 theme"
|
||||||
p3 = "p3 theme"
|
[params.b]
|
||||||
|
b1 = "b1 theme"
|
||||||
|
b2 = "b2 theme"
|
||||||
|
[params.b.c]
|
||||||
|
bc1 = "bc1 theme"
|
||||||
|
bc2 = "bc2 theme"
|
||||||
|
[params.b.c.d]
|
||||||
|
bcd1 = "bcd1 theme"
|
||||||
|
|
||||||
[mediaTypes]
|
[mediaTypes]
|
||||||
[mediaTypes."text/m1"]
|
[mediaTypes."text/m1"]
|
||||||
|
@ -176,190 +185,137 @@ name = "menu-theme"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
b := newTestSitesBuilder(t)
|
buildForStrategy := func(t testing.TB, s string) *sitesBuilder {
|
||||||
b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig)
|
mainConfig := strings.ReplaceAll(mainConfigTemplate, "MERGE_PARAMS", s)
|
||||||
b.CreateSites().Build(BuildCfg{})
|
b := newTestSitesBuilder(t)
|
||||||
|
b.WithConfigFile("toml", mainConfig).WithThemeConfigFile("toml", themeConfig)
|
||||||
got := b.Cfg.(*viper.Viper).AllSettings()
|
return b.CreateSites().Build(BuildCfg{})
|
||||||
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"p1": "p1 main",
|
|
||||||
"p2": "p2 main",
|
|
||||||
"p3": "p3 theme",
|
|
||||||
"top": "top",
|
|
||||||
}`, got["params"])
|
|
||||||
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"date": []interface {}{
|
|
||||||
"date",
|
|
||||||
"publishDate",
|
|
||||||
},
|
|
||||||
}`, got["frontmatter"])
|
|
||||||
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"text/m1": map[string]interface {}{
|
|
||||||
"suffixes": []interface {}{
|
|
||||||
"m1main",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"text/m2": map[string]interface {}{
|
|
||||||
"suffixes": []interface {}{
|
|
||||||
"m2theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}`, got["mediatypes"])
|
|
||||||
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"o1": map[string]interface {}{
|
|
||||||
"basename": "o1main",
|
|
||||||
"mediatype": Type{
|
|
||||||
MainType: "text",
|
|
||||||
SubType: "m1",
|
|
||||||
Delimiter: ".",
|
|
||||||
FirstSuffix: SuffixInfo{
|
|
||||||
Suffix: "m1main",
|
|
||||||
FullSuffix: ".m1main",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"o2": map[string]interface {}{
|
|
||||||
"basename": "o2theme",
|
|
||||||
"mediatype": Type{
|
|
||||||
MainType: "text",
|
|
||||||
SubType: "m2",
|
|
||||||
Delimiter: ".",
|
|
||||||
FirstSuffix: SuffixInfo{
|
|
||||||
Suffix: "m2theme",
|
|
||||||
FullSuffix: ".m2theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}`, got["outputformats"])
|
|
||||||
|
|
||||||
b.AssertObject(`map[string]interface {}{
|
|
||||||
"en": map[string]interface {}{
|
|
||||||
"languagename": "English",
|
|
||||||
"menus": map[string]interface {}{
|
|
||||||
"theme": []map[string]interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-lang-en-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"params": map[string]interface {}{
|
|
||||||
"pl1": "p1-en-main",
|
|
||||||
"pl2": "p2-en-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"nb": map[string]interface {}{
|
|
||||||
"languagename": "Norsk",
|
|
||||||
"menus": map[string]interface {}{
|
|
||||||
"theme": []map[string]interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-lang-nb-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"params": map[string]interface {}{
|
|
||||||
"pl1": "p1-nb-main",
|
|
||||||
"pl2": "p2-nb-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`, got["languages"])
|
|
||||||
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"main": []map[string]interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-main-main",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"thememenu": []map[string]interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"top": []map[string]interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-top-main",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`, got["menus"])
|
|
||||||
|
|
||||||
c.Assert(got["baseurl"], qt.Equals, "https://example.com/")
|
|
||||||
|
|
||||||
if true {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
// Test variants with only values from theme
|
|
||||||
b = newTestSitesBuilder(t)
|
|
||||||
b.WithConfigFile("toml", mainConfigBasic).WithThemeConfigFile("toml", themeConfig)
|
|
||||||
b.CreateSites().Build(BuildCfg{})
|
|
||||||
|
|
||||||
got = b.Cfg.(*viper.Viper).AllSettings()
|
c.Run("Merge default", func(c *qt.C) {
|
||||||
|
b := buildForStrategy(c, "")
|
||||||
|
|
||||||
b.AssertObject(`map[string]interface {}{
|
got := b.Cfg.Get("").(maps.Params)
|
||||||
"p1": "p1 theme",
|
|
||||||
"p2": "p2 theme",
|
|
||||||
"p3": "p3 theme",
|
|
||||||
"test-theme": map[string]interface {}{
|
|
||||||
"p1": "p1 theme",
|
|
||||||
"p2": "p2 theme",
|
|
||||||
"p3": "p3 theme",
|
|
||||||
},
|
|
||||||
}`, got["params"])
|
|
||||||
|
|
||||||
c.Assert(got["languages"], qt.IsNil)
|
b.Assert(got["params"], qt.DeepEquals, maps.Params{
|
||||||
b.AssertObject(`
|
"b": maps.Params{
|
||||||
map[string]interface {}{
|
"b1": "b1 main",
|
||||||
"text/m1": map[string]interface {}{
|
"c": maps.Params{
|
||||||
"suffix": "m1theme",
|
"bc1": "bc1 main",
|
||||||
},
|
"bc2": "bc2 theme",
|
||||||
"text/m2": map[string]interface {}{
|
"d": maps.Params{"bcd1": string("bcd1 theme")},
|
||||||
"suffix": "m2theme",
|
},
|
||||||
},
|
"b2": "b2 theme",
|
||||||
}`, got["mediatypes"])
|
},
|
||||||
|
"p2": "p2 theme",
|
||||||
|
"p1": "p1 main",
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Assert(got["mediatypes"], qt.DeepEquals, maps.Params{
|
||||||
|
"text/m2": maps.Params{
|
||||||
|
"suffixes": []interface{}{
|
||||||
|
"m2theme",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"text/m1": maps.Params{
|
||||||
|
"suffixes": []interface{}{
|
||||||
|
"m1main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var eq = qt.CmpEquals(
|
||||||
|
cmp.Comparer(func(m1, m2 media.Type) bool {
|
||||||
|
if m1.SubType != m2.SubType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return m1.FirstSuffix == m2.FirstSuffix
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
mediaTypes := b.H.Sites[0].mediaTypesConfig
|
||||||
|
m1, _ := mediaTypes.GetByType("text/m1")
|
||||||
|
m2, _ := mediaTypes.GetByType("text/m2")
|
||||||
|
|
||||||
|
b.Assert(got["outputformats"], eq, maps.Params{
|
||||||
|
"o1": maps.Params{
|
||||||
|
"mediatype": m1,
|
||||||
|
"basename": "o1main",
|
||||||
|
},
|
||||||
|
"o2": maps.Params{
|
||||||
|
"basename": "o2theme",
|
||||||
|
"mediatype": m2,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Assert(got["languages"], qt.DeepEquals, maps.Params{
|
||||||
|
"en": maps.Params{
|
||||||
|
"languagename": "English",
|
||||||
|
"params": maps.Params{
|
||||||
|
"pl2": "p2-en-theme",
|
||||||
|
"pl1": "p1-en-main",
|
||||||
|
},
|
||||||
|
"menus": maps.Params{
|
||||||
|
"main": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"name": "menu-lang-en-main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"theme": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"name": "menu-lang-en-theme",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"nb": maps.Params{
|
||||||
|
"languagename": "Norsk",
|
||||||
|
"params": maps.Params{
|
||||||
|
"top": "top-nb-theme",
|
||||||
|
"pl1": "p1-nb-main",
|
||||||
|
"pl2": "p2-nb-theme",
|
||||||
|
},
|
||||||
|
"menus": maps.Params{
|
||||||
|
"main": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"name": "menu-lang-nb-main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"theme": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"name": "menu-lang-nb-theme",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"top": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"name": "menu-lang-nb-top",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(got["baseurl"], qt.Equals, "https://example.com/")
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Run("Merge shallow", func(c *qt.C) {
|
||||||
|
b := buildForStrategy(c, fmt.Sprintf("_merge=%q", "shallow"))
|
||||||
|
|
||||||
|
got := b.Cfg.Get("").(maps.Params)
|
||||||
|
|
||||||
|
// Shallow merge, only add new keys to params.
|
||||||
|
b.Assert(got["params"], qt.DeepEquals, maps.Params{
|
||||||
|
"p1": "p1 main",
|
||||||
|
"b": maps.Params{
|
||||||
|
"b1": "b1 main",
|
||||||
|
"c": maps.Params{
|
||||||
|
"bc1": "bc1 main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"p2": "p2 theme",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"o1": map[string]interface {}{
|
|
||||||
"basename": "o1theme",
|
|
||||||
"mediatype": Type{
|
|
||||||
MainType: "text",
|
|
||||||
SubType: "m1",
|
|
||||||
Suffix: "m1theme",
|
|
||||||
Delimiter: ".",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"o2": map[string]interface {}{
|
|
||||||
"basename": "o2theme",
|
|
||||||
"mediatype": Type{
|
|
||||||
MainType: "text",
|
|
||||||
SubType: "m2",
|
|
||||||
Suffix: "m2theme",
|
|
||||||
Delimiter: ".",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}`, got["outputformats"])
|
|
||||||
b.AssertObject(`
|
|
||||||
map[string]interface {}{
|
|
||||||
"main": []interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-main-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"thememenu": []interface {}{
|
|
||||||
map[string]interface {}{
|
|
||||||
"name": "menu-theme",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}`, got["menu"])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrivacyConfig(t *testing.T) {
|
func TestPrivacyConfig(t *testing.T) {
|
||||||
|
@ -490,7 +446,12 @@ intSlice = [5,7,9]
|
||||||
floatSlice = [3.14, 5.19]
|
floatSlice = [3.14, 5.19]
|
||||||
stringSlice = ["a", "b"]
|
stringSlice = ["a", "b"]
|
||||||
|
|
||||||
|
[outputFormats]
|
||||||
|
[outputFormats.ofbase]
|
||||||
|
mediaType = "text/plain"
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
paramWithNoEnvOverride="nooverride"
|
||||||
[params.api_config]
|
[params.api_config]
|
||||||
api_key="default_key"
|
api_key="default_key"
|
||||||
another_key="default another_key"
|
another_key="default another_key"
|
||||||
|
@ -504,9 +465,16 @@ quality = 75
|
||||||
|
|
||||||
b.WithSourceFile("themes/mytheme/config.toml", `
|
b.WithSourceFile("themes/mytheme/config.toml", `
|
||||||
|
|
||||||
|
[outputFormats]
|
||||||
|
[outputFormats.oftheme]
|
||||||
|
mediaType = "text/plain"
|
||||||
|
[outputFormats.ofbase]
|
||||||
|
mediaType = "application/xml"
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
[params.mytheme_section]
|
[params.mytheme_section]
|
||||||
theme_param="themevalue"
|
theme_param="themevalue"
|
||||||
|
theme_param_nooverride="nooverride"
|
||||||
[params.mytheme_section2]
|
[params.mytheme_section2]
|
||||||
theme_param="themevalue2"
|
theme_param="themevalue2"
|
||||||
|
|
||||||
|
@ -530,14 +498,16 @@ theme_param="themevalue2"
|
||||||
"HUGOxPARAMSxMYTHEME_SECTION2xTHEME_PARAM", "themevalue2_changed",
|
"HUGOxPARAMSxMYTHEME_SECTION2xTHEME_PARAM", "themevalue2_changed",
|
||||||
"HUGO_PARAMS_EMPTY", ``,
|
"HUGO_PARAMS_EMPTY", ``,
|
||||||
"HUGO_PARAMS_HTML", `<a target="_blank" />`,
|
"HUGO_PARAMS_HTML", `<a target="_blank" />`,
|
||||||
//
|
// Issue #8618
|
||||||
"HUGO_SERVICES_GOOGLEANALYTICS_ID", `gaid`,
|
"HUGO_SERVICES_GOOGLEANALYTICS_ID", `gaid`,
|
||||||
|
"HUGO_PARAMS_A_B_C", "abc",
|
||||||
)
|
)
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
|
||||||
cfg := b.H.Cfg
|
cfg := b.H.Cfg
|
||||||
scfg := b.H.Sites[0].siteConfigConfig.Services
|
s := b.H.Sites[0]
|
||||||
|
scfg := s.siteConfigConfig.Services
|
||||||
|
|
||||||
c.Assert(cfg.Get("environment"), qt.Equals, "test")
|
c.Assert(cfg.Get("environment"), qt.Equals, "test")
|
||||||
c.Assert(cfg.GetBool("enablegitinfo"), qt.Equals, false)
|
c.Assert(cfg.GetBool("enablegitinfo"), qt.Equals, false)
|
||||||
|
@ -551,9 +521,23 @@ theme_param="themevalue2"
|
||||||
c.Assert(cfg.Get("params.api_config.api_key"), qt.Equals, "new_key")
|
c.Assert(cfg.Get("params.api_config.api_key"), qt.Equals, "new_key")
|
||||||
c.Assert(cfg.Get("params.api_config.another_key"), qt.Equals, "default another_key")
|
c.Assert(cfg.Get("params.api_config.another_key"), qt.Equals, "default another_key")
|
||||||
c.Assert(cfg.Get("params.mytheme_section.theme_param"), qt.Equals, "themevalue_changed")
|
c.Assert(cfg.Get("params.mytheme_section.theme_param"), qt.Equals, "themevalue_changed")
|
||||||
|
c.Assert(cfg.Get("params.mytheme_section.theme_param_nooverride"), qt.Equals, "nooverride")
|
||||||
c.Assert(cfg.Get("params.mytheme_section2.theme_param"), qt.Equals, "themevalue2_changed")
|
c.Assert(cfg.Get("params.mytheme_section2.theme_param"), qt.Equals, "themevalue2_changed")
|
||||||
c.Assert(cfg.Get("params.empty"), qt.Equals, ``)
|
c.Assert(cfg.Get("params.empty"), qt.Equals, ``)
|
||||||
c.Assert(cfg.Get("params.html"), qt.Equals, `<a target="_blank" />`)
|
c.Assert(cfg.Get("params.html"), qt.Equals, `<a target="_blank" />`)
|
||||||
|
|
||||||
|
params := cfg.Get("params").(maps.Params)
|
||||||
|
c.Assert(params["paramwithnoenvoverride"], qt.Equals, "nooverride")
|
||||||
|
c.Assert(cfg.Get("params.paramwithnoenvoverride"), qt.Equals, "nooverride")
|
||||||
c.Assert(scfg.GoogleAnalytics.ID, qt.Equals, "gaid")
|
c.Assert(scfg.GoogleAnalytics.ID, qt.Equals, "gaid")
|
||||||
|
c.Assert(cfg.Get("params.a.b"), qt.DeepEquals, maps.Params{
|
||||||
|
"c": "abc",
|
||||||
|
})
|
||||||
|
|
||||||
|
ofBase, _ := s.outputFormatsConfig.GetByName("ofbase")
|
||||||
|
ofTheme, _ := s.outputFormatsConfig.GetByName("oftheme")
|
||||||
|
|
||||||
|
c.Assert(ofBase.MediaType, qt.Equals, media.TextType)
|
||||||
|
c.Assert(ofTheme.MediaType, qt.Equals, media.TextType)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/hugolib/paths"
|
"github.com/gohugoio/hugo/hugolib/paths"
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func initConfig(fs afero.Fs, cfg config.Provider) error {
|
func initConfig(fs afero.Fs, cfg config.Provider) error {
|
||||||
|
@ -76,7 +76,7 @@ func initConfig(fs afero.Fs, cfg config.Provider) error {
|
||||||
|
|
||||||
func TestNewBaseFs(t *testing.T) {
|
func TestNewBaseFs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
|
|
||||||
|
@ -181,8 +181,8 @@ theme = ["atheme"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConfig() *viper.Viper {
|
func createConfig() config.Provider {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "mycontent")
|
v.Set("contentDir", "mycontent")
|
||||||
v.Set("i18nDir", "myi18n")
|
v.Set("i18nDir", "myi18n")
|
||||||
v.Set("staticDir", "mystatic")
|
v.Set("staticDir", "mystatic")
|
||||||
|
@ -453,7 +453,7 @@ func countFilesAndGetFilenames(fs afero.Fs, dirname string) (int, []string, erro
|
||||||
return counter, filenames, nil
|
return counter, filenames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setConfigAndWriteSomeFilesTo(fs afero.Fs, v *viper.Viper, key, val string, num int) {
|
func setConfigAndWriteSomeFilesTo(fs afero.Fs, v config.Provider, key, val string, num int) {
|
||||||
workingDir := v.GetString("workingDir")
|
workingDir := v.GetString("workingDir")
|
||||||
v.Set(key, val)
|
v.Set(key, val)
|
||||||
fs.Mkdir(val, 0755)
|
fs.Mkdir(val, 0755)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/modules/npm"
|
"github.com/gohugoio/hugo/modules/npm"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
@ -37,7 +38,6 @@ import (
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/testmodBuilder/mods"
|
"github.com/gohugoio/testmodBuilder/mods"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHugoModulesVariants(t *testing.T) {
|
func TestHugoModulesVariants(t *testing.T) {
|
||||||
|
@ -45,7 +45,7 @@ func TestHugoModulesVariants(t *testing.T) {
|
||||||
t.Skip("skip (relative) long running modules test when running locally")
|
t.Skip("skip (relative) long running modules test when running locally")
|
||||||
}
|
}
|
||||||
|
|
||||||
config := `
|
tomlConfig := `
|
||||||
baseURL="https://example.org"
|
baseURL="https://example.org"
|
||||||
workingDir = %q
|
workingDir = %q
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ path="github.com/gohugoio/hugoTestModule2"
|
||||||
`
|
`
|
||||||
|
|
||||||
createConfig := func(workingDir, moduleOpts string) string {
|
createConfig := func(workingDir, moduleOpts string) string {
|
||||||
return fmt.Sprintf(config, workingDir, moduleOpts)
|
return fmt.Sprintf(tomlConfig, workingDir, moduleOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
newTestBuilder := func(t testing.TB, moduleOpts string) (*sitesBuilder, func()) {
|
newTestBuilder := func(t testing.TB, moduleOpts string) (*sitesBuilder, func()) {
|
||||||
|
@ -65,7 +65,7 @@ path="github.com/gohugoio/hugoTestModule2"
|
||||||
b.Assert(err, qt.IsNil)
|
b.Assert(err, qt.IsNil)
|
||||||
workingDir := filepath.Join(tempDir, "myhugosite")
|
workingDir := filepath.Join(tempDir, "myhugosite")
|
||||||
b.Assert(os.MkdirAll(workingDir, 0777), qt.IsNil)
|
b.Assert(os.MkdirAll(workingDir, 0777), qt.IsNil)
|
||||||
b.Fs = hugofs.NewDefault(viper.New())
|
b.Fs = hugofs.NewDefault(config.New())
|
||||||
b.WithWorkingDir(workingDir).WithConfigFile("toml", createConfig(workingDir, moduleOpts))
|
b.WithWorkingDir(workingDir).WithConfigFile("toml", createConfig(workingDir, moduleOpts))
|
||||||
b.WithTemplates(
|
b.WithTemplates(
|
||||||
"index.html", `
|
"index.html", `
|
||||||
|
@ -333,7 +333,7 @@ func TestHugoModulesMatrix(t *testing.T) {
|
||||||
for _, m := range testmods[:2] {
|
for _, m := range testmods[:2] {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-modules-test")
|
workingDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-modules-test")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
@ -671,7 +671,7 @@ func TestModulesSymlinks(t *testing.T) {
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
// We need to use the OS fs for this.
|
// We need to use the OS fs for this.
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-mod-sym")
|
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-mod-sym")
|
||||||
|
@ -839,13 +839,13 @@ workingDir = %q
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
config := fmt.Sprintf(configTemplate, workingDir)
|
tomlConfig := fmt.Sprintf(configTemplate, workingDir)
|
||||||
|
|
||||||
b := newTestSitesBuilder(t).Running()
|
b := newTestSitesBuilder(t).Running()
|
||||||
|
|
||||||
b.Fs = hugofs.NewDefault(viper.New())
|
b.Fs = hugofs.NewDefault(config.New())
|
||||||
|
|
||||||
b.WithWorkingDir(workingDir).WithConfigFile("toml", config)
|
b.WithWorkingDir(workingDir).WithConfigFile("toml", tomlConfig)
|
||||||
b.WithTemplatesAdded("index.html", `
|
b.WithTemplatesAdded("index.html", `
|
||||||
{{ .Title }}
|
{{ .Title }}
|
||||||
{{ .Content }}
|
{{ .Content }}
|
||||||
|
@ -960,16 +960,16 @@ workingDir = %q
|
||||||
%s
|
%s
|
||||||
|
|
||||||
`
|
`
|
||||||
config := fmt.Sprintf(configTemplate, workingDir, mounts)
|
tomlConfig := fmt.Sprintf(configTemplate, workingDir, mounts)
|
||||||
config = strings.Replace(config, "WORKING_DIR", workingDir, -1)
|
tomlConfig = strings.Replace(tomlConfig, "WORKING_DIR", workingDir, -1)
|
||||||
|
|
||||||
b := newTestSitesBuilder(c).Running()
|
b := newTestSitesBuilder(c).Running()
|
||||||
|
|
||||||
b.Fs = hugofs.NewDefault(viper.New())
|
b.Fs = hugofs.NewDefault(config.New())
|
||||||
|
|
||||||
os.MkdirAll(filepath.Join(workingDir, "content", "blog"), 0777)
|
os.MkdirAll(filepath.Join(workingDir, "content", "blog"), 0777)
|
||||||
|
|
||||||
b.WithWorkingDir(workingDir).WithConfigFile("toml", config)
|
b.WithWorkingDir(workingDir).WithConfigFile("toml", tomlConfig)
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
b: b,
|
b: b,
|
||||||
|
@ -1064,7 +1064,7 @@ func TestSiteWithGoModButNoModules(t *testing.T) {
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-no-mod")
|
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-no-mod")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
|
@ -1090,7 +1090,7 @@ func TestModuleAbsMount(t *testing.T) {
|
||||||
absContentDir, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-content")
|
absContentDir, clean2, err := htesting.CreateTempDir(hugofs.Os, "hugo-content")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,8 @@ func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {
|
||||||
s.h = h
|
s.h = h
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := applyDeps(cfg, sites...); err != nil {
|
var l configLoader
|
||||||
|
if err := l.applyDeps(cfg, sites...); err != nil {
|
||||||
return nil, errors.Wrap(err, "add site dependencies")
|
return nil, errors.Wrap(err, "add site dependencies")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +408,7 @@ func (h *HugoSites) loadGitInfo() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
|
func (l configLoader) applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
|
||||||
if cfg.TemplateProvider == nil {
|
if cfg.TemplateProvider == nil {
|
||||||
cfg.TemplateProvider = tplimpl.DefaultTemplateProvider
|
cfg.TemplateProvider = tplimpl.DefaultTemplateProvider
|
||||||
}
|
}
|
||||||
|
@ -446,7 +447,7 @@ func applyDeps(cfg deps.DepsCfg, sites ...*Site) error {
|
||||||
|
|
||||||
d.Site = s.Info
|
d.Site = s.Info
|
||||||
|
|
||||||
siteConfig, err := loadSiteConfig(s.language)
|
siteConfig, err := l.loadSiteConfig(s.language)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "load site config")
|
return errors.Wrap(err, "load site config")
|
||||||
}
|
}
|
||||||
|
@ -607,11 +608,12 @@ func (h *HugoSites) withSite(fn func(s *Site) error) error {
|
||||||
func (h *HugoSites) createSitesFromConfig(cfg config.Provider) error {
|
func (h *HugoSites) createSitesFromConfig(cfg config.Provider) error {
|
||||||
oldLangs, _ := h.Cfg.Get("languagesSorted").(langs.Languages)
|
oldLangs, _ := h.Cfg.Get("languagesSorted").(langs.Languages)
|
||||||
|
|
||||||
if err := loadLanguageSettings(h.Cfg, oldLangs); err != nil {
|
l := configLoader{cfg: h.Cfg}
|
||||||
|
if err := l.loadLanguageSettings(oldLangs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
depsCfg := deps.DepsCfg{Fs: h.Fs, Cfg: cfg}
|
depsCfg := deps.DepsCfg{Fs: h.Fs, Cfg: l.cfg}
|
||||||
|
|
||||||
sites, err := createSitesFromConfig(depsCfg)
|
sites, err := createSitesFromConfig(depsCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -629,7 +631,8 @@ func (h *HugoSites) createSitesFromConfig(cfg config.Provider) error {
|
||||||
s.h = h
|
s.h = h
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := applyDeps(depsCfg, sites...); err != nil {
|
var cl configLoader
|
||||||
|
if err := cl.applyDeps(depsCfg, sites...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fortytw2/leaktest"
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
@ -318,7 +316,7 @@ Some content.
|
||||||
// https://github.com/gohugoio/hugo/issues/5375
|
// https://github.com/gohugoio/hugo/issues/5375
|
||||||
func TestSiteBuildTimeout(t *testing.T) {
|
func TestSiteBuildTimeout(t *testing.T) {
|
||||||
if !htesting.IsCI() {
|
if !htesting.IsCI() {
|
||||||
defer leaktest.CheckTimeout(t, 10*time.Second)()
|
//defer leaktest.CheckTimeout(t, 10*time.Second)()
|
||||||
}
|
}
|
||||||
|
|
||||||
b := newTestSitesBuilder(t)
|
b := newTestSitesBuilder(t)
|
||||||
|
|
|
@ -21,11 +21,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// We have many tests for the different resize operations etc. in the resource package,
|
// We have many tests for the different resize operations etc. in the resource package,
|
||||||
|
@ -38,7 +38,7 @@ func TestImageOps(t *testing.T) {
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
newBuilder := func(timeout interface{}) *sitesBuilder {
|
newBuilder := func(timeout interface{}) *sitesBuilder {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("baseURL", "https://example.org")
|
v.Set("baseURL", "https://example.org")
|
||||||
v.Set("timeout", timeout)
|
v.Set("timeout", timeout)
|
||||||
|
|
|
@ -21,11 +21,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hexec"
|
"github.com/gohugoio/hugo/common/hexec"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
@ -88,7 +87,7 @@ document.body.textContent = greeter(user);`
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
|
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
|
||||||
b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
|
b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
|
||||||
|
@ -162,7 +161,7 @@ func TestJSBuild(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
config := fmt.Sprintf(`
|
tomlConfig := fmt.Sprintf(`
|
||||||
baseURL = "https://example.org"
|
baseURL = "https://example.org"
|
||||||
workingDir = %q
|
workingDir = %q
|
||||||
|
|
||||||
|
@ -177,8 +176,8 @@ path="github.com/gohugoio/hugoTestProjectJSModImports"
|
||||||
`, workDir)
|
`, workDir)
|
||||||
|
|
||||||
b := newTestSitesBuilder(t)
|
b := newTestSitesBuilder(t)
|
||||||
b.Fs = hugofs.NewDefault(viper.New())
|
b.Fs = hugofs.NewDefault(config.New())
|
||||||
b.WithWorkingDir(workDir).WithConfigFile("toml", config).WithLogger(loggers.NewInfoLogger())
|
b.WithWorkingDir(workDir).WithConfigFile("toml", tomlConfig).WithLogger(loggers.NewInfoLogger())
|
||||||
b.WithSourceFile("go.mod", `module github.com/gohugoio/tests/testHugoModules
|
b.WithSourceFile("go.mod", `module github.com/gohugoio/tests/testHugoModules
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
|
@ -16,13 +16,13 @@ package hugolib
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMinifyPublisher(t *testing.T) {
|
func TestMinifyPublisher(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("minify", true)
|
v.Set("minify", true)
|
||||||
v.Set("baseURL", "https://example.org/")
|
v.Set("baseURL", "https://example.org/")
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,7 @@ func (pm *pageMeta) setMetadata(parentBucket *pagesMapBucket, p *pageState, fron
|
||||||
|
|
||||||
if frontmatter != nil {
|
if frontmatter != nil {
|
||||||
// Needed for case insensitive fetching of params values
|
// Needed for case insensitive fetching of params values
|
||||||
maps.ToLower(frontmatter)
|
maps.PrepareParams(frontmatter)
|
||||||
if p.bucket != nil {
|
if p.bucket != nil {
|
||||||
// Check for any cascade define on itself.
|
// Check for any cascade define on itself.
|
||||||
if cv, found := frontmatter["cascade"]; found {
|
if cv, found := frontmatter["cascade"]; found {
|
||||||
|
|
|
@ -37,7 +37,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
@ -786,7 +785,7 @@ func TestPageWithLastmodFromGitInfo(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
// We need to use the OS fs for this.
|
// We need to use the OS fs for this.
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
fs.Destination = &afero.MemMapFs{}
|
fs.Destination = &afero.MemMapFs{}
|
||||||
|
|
||||||
|
@ -1066,7 +1065,7 @@ func TestChompBOM(t *testing.T) {
|
||||||
|
|
||||||
func TestPageWithEmoji(t *testing.T) {
|
func TestPageWithEmoji(t *testing.T) {
|
||||||
for _, enableEmoji := range []bool{true, false} {
|
for _, enableEmoji := range []bool{true, false} {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("enableEmoji", enableEmoji)
|
v.Set("enableEmoji", enableEmoji)
|
||||||
|
|
||||||
b := newTestSitesBuilder(t).WithViper(v)
|
b := newTestSitesBuilder(t).WithViper(v)
|
||||||
|
|
|
@ -23,6 +23,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs/files"
|
"github.com/gohugoio/hugo/hugofs/files"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
|
@ -35,7 +37,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
@ -352,12 +353,11 @@ func TestMultilingualDisableDefaultLanguage(t *testing.T) {
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
_, cfg := newTestBundleSourcesMultilingual(t)
|
_, cfg := newTestBundleSourcesMultilingual(t)
|
||||||
|
|
||||||
cfg.Set("disableLanguages", []string{"en"})
|
cfg.Set("disableLanguages", []string{"en"})
|
||||||
|
l := configLoader{cfg: cfg}
|
||||||
err := loadDefaultSettingsFor(cfg)
|
err := l.applyConfigDefaults()
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
err = loadLanguageSettings(cfg, nil)
|
err = l.loadLanguageSettings(nil)
|
||||||
c.Assert(err, qt.Not(qt.IsNil))
|
c.Assert(err, qt.Not(qt.IsNil))
|
||||||
c.Assert(err.Error(), qt.Contains, "cannot disable default language")
|
c.Assert(err.Error(), qt.Contains, "cannot disable default language")
|
||||||
}
|
}
|
||||||
|
@ -397,7 +397,7 @@ func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) {
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
// We need to use the OS fs for this.
|
// We need to use the OS fs for this.
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugosym")
|
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugosym")
|
||||||
|
@ -696,7 +696,7 @@ Single content.
|
||||||
b.AssertFileContent("public/section-not-bundle/single/index.html", "Section Single", "|<p>Single content.</p>")
|
b.AssertFileContent("public/section-not-bundle/single/index.html", "Section Single", "|<p>Single content.</p>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestBundleSources(t testing.TB) (*hugofs.Fs, *viper.Viper) {
|
func newTestBundleSources(t testing.TB) (*hugofs.Fs, config.Provider) {
|
||||||
cfg, fs := newTestCfgBasic()
|
cfg, fs := newTestCfgBasic()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
|
@ -863,7 +863,7 @@ Content for 은행.
|
||||||
return fs, cfg
|
return fs, cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestBundleSourcesMultilingual(t *testing.T) (*hugofs.Fs, *viper.Viper) {
|
func newTestBundleSourcesMultilingual(t *testing.T) (*hugofs.Fs, config.Provider) {
|
||||||
cfg, fs := newTestCfgBasic()
|
cfg, fs := newTestCfgBasic()
|
||||||
|
|
||||||
workDir := "/work"
|
workDir := "/work"
|
||||||
|
@ -1319,7 +1319,7 @@ func TestPageBundlerHome(t *testing.T) {
|
||||||
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-bundler-home")
|
workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-bundler-home")
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("workingDir", workDir)
|
cfg.Set("workingDir", workDir)
|
||||||
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
fs := hugofs.NewFrom(hugofs.Os, cfg)
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ func (c *pagesCollector) isCascadingEdit(dir contentDirKey) (bool, string) {
|
||||||
|
|
||||||
section = s
|
section = s
|
||||||
|
|
||||||
maps.ToLower(pf.FrontMatter)
|
maps.PrepareParams(pf.FrontMatter)
|
||||||
cascade1, ok := pf.FrontMatter["cascade"]
|
cascade1, ok := pf.FrontMatter["cascade"]
|
||||||
hasCascade := n.p.bucket.cascade != nil && len(n.p.bucket.cascade) > 0
|
hasCascade := n.p.bucket.cascade != nil && len(n.p.bucket.cascade) > 0
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -16,17 +16,16 @@ package paths
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/langs"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/langs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewPaths(t *testing.T) {
|
func TestNewPaths(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
|
|
||||||
v.Set("languages", map[string]interface{}{
|
v.Set("languages", map[string]interface{}{
|
||||||
|
|
|
@ -19,14 +19,14 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/hexec"
|
"github.com/gohugoio/hugo/common/hexec"
|
||||||
|
|
||||||
jww "github.com/spf13/jwalterweatherman"
|
jww "github.com/spf13/jwalterweatherman"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
@ -91,7 +91,7 @@ class Car2 {
|
||||||
var logBuf bytes.Buffer
|
var logBuf bytes.Buffer
|
||||||
logger := loggers.NewBasicLoggerForWriter(jww.LevelInfo, &logBuf)
|
logger := loggers.NewBasicLoggerForWriter(jww.LevelInfo, &logBuf)
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
|
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
|
||||||
b := newTestSitesBuilder(t).WithLogger(logger)
|
b := newTestSitesBuilder(t).WithLogger(logger)
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
|
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/dartsass"
|
||||||
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -35,8 +37,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting"
|
"github.com/gohugoio/hugo/htesting"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
@ -65,7 +65,7 @@ func TestSCSSWithIncludePaths(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
b := newTestSitesBuilder(c).WithLogger(loggers.NewErrorLogger())
|
b := newTestSitesBuilder(c).WithLogger(loggers.NewErrorLogger())
|
||||||
// Need to use OS fs for this.
|
// Need to use OS fs for this.
|
||||||
|
@ -130,7 +130,7 @@ func TestSCSSWithRegularCSSImport(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
defer clean()
|
defer clean()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
b := newTestSitesBuilder(c).WithLogger(loggers.NewErrorLogger())
|
b := newTestSitesBuilder(c).WithLogger(loggers.NewErrorLogger())
|
||||||
// Need to use OS fs for this.
|
// Need to use OS fs for this.
|
||||||
|
@ -230,7 +230,7 @@ func TestSCSSWithThemeOverrides(t *testing.T) {
|
||||||
theme := "mytheme"
|
theme := "mytheme"
|
||||||
themesDir := filepath.Join(workDir, "themes")
|
themesDir := filepath.Join(workDir, "themes")
|
||||||
themeDirs := filepath.Join(themesDir, theme)
|
themeDirs := filepath.Join(themesDir, theme)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("theme", theme)
|
v.Set("theme", theme)
|
||||||
b := newTestSitesBuilder(c).WithLogger(loggers.NewErrorLogger())
|
b := newTestSitesBuilder(c).WithLogger(loggers.NewErrorLogger())
|
||||||
|
@ -345,7 +345,7 @@ func TestSCSSWithIncludePathsSass(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
defer clean1()
|
defer clean1()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("theme", "mytheme")
|
v.Set("theme", "mytheme")
|
||||||
b := newTestSitesBuilder(t).WithLogger(loggers.NewErrorLogger())
|
b := newTestSitesBuilder(t).WithLogger(loggers.NewErrorLogger())
|
||||||
|
@ -974,7 +974,7 @@ h1 {
|
||||||
|
|
||||||
var logBuf bytes.Buffer
|
var logBuf bytes.Buffer
|
||||||
|
|
||||||
newTestBuilder := func(v *viper.Viper) *sitesBuilder {
|
newTestBuilder := func(v config.Provider) *sitesBuilder {
|
||||||
v.Set("workingDir", workDir)
|
v.Set("workingDir", workDir)
|
||||||
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
|
v.Set("disableKinds", []string{"taxonomy", "term", "page"})
|
||||||
logger := loggers.NewBasicLoggerForWriter(jww.LevelInfo, &logBuf)
|
logger := loggers.NewBasicLoggerForWriter(jww.LevelInfo, &logBuf)
|
||||||
|
@ -997,7 +997,7 @@ Styles Content: Len: {{ len $styles.Content }}|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
b := newTestBuilder(viper.New())
|
b := newTestBuilder(config.New())
|
||||||
|
|
||||||
cssDir := filepath.Join(workDir, "assets", "css", "components")
|
cssDir := filepath.Join(workDir, "assets", "css", "components")
|
||||||
b.Assert(os.MkdirAll(cssDir, 0777), qt.IsNil)
|
b.Assert(os.MkdirAll(cssDir, 0777), qt.IsNil)
|
||||||
|
@ -1049,7 +1049,7 @@ Styles Content: Len: 770878|
|
||||||
build := func(s string, shouldFail bool) error {
|
build := func(s string, shouldFail bool) error {
|
||||||
b.Assert(os.RemoveAll(filepath.Join(workDir, "public")), qt.IsNil)
|
b.Assert(os.RemoveAll(filepath.Join(workDir, "public")), qt.IsNil)
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("build", map[string]interface{}{
|
v.Set("build", map[string]interface{}{
|
||||||
"useResourceCacheWhen": s,
|
"useResourceCacheWhen": s,
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,7 +16,7 @@ package hugolib
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
const robotTxtTemplate = `User-agent: Googlebot
|
const robotTxtTemplate = `User-agent: Googlebot
|
||||||
|
@ -28,7 +28,7 @@ const robotTxtTemplate = `User-agent: Googlebot
|
||||||
func TestRobotsTXTOutput(t *testing.T) {
|
func TestRobotsTXTOutput(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("baseURL", "http://auth/bub/")
|
cfg.Set("baseURL", "http://auth/bub/")
|
||||||
cfg.Set("enableRobotsTXT", true)
|
cfg.Set("enableRobotsTXT", true)
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/markup/asciidocext"
|
"github.com/gohugoio/hugo/markup/asciidocext"
|
||||||
"github.com/gohugoio/hugo/markup/rst"
|
"github.com/gohugoio/hugo/markup/rst"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/parser/pageparser"
|
"github.com/gohugoio/hugo/parser/pageparser"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
|
|
||||||
|
@ -1214,7 +1213,7 @@ title: "Hugo Rocks!"
|
||||||
func TestShortcodeEmoji(t *testing.T) {
|
func TestShortcodeEmoji(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("enableEmoji", true)
|
v.Set("enableEmoji", true)
|
||||||
|
|
||||||
builder := newTestSitesBuilder(t).WithViper(v)
|
builder := newTestSitesBuilder(t).WithViper(v)
|
||||||
|
@ -1279,7 +1278,7 @@ func TestShortcodeRef(t *testing.T) {
|
||||||
t.Run(fmt.Sprintf("plainIDAnchors=%t", plainIDAnchors), func(t *testing.T) {
|
t.Run(fmt.Sprintf("plainIDAnchors=%t", plainIDAnchors), func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("baseURL", "https://example.org")
|
v.Set("baseURL", "https://example.org")
|
||||||
v.Set("blackfriday", map[string]interface{}{
|
v.Set("blackfriday", map[string]interface{}{
|
||||||
"plainIDAnchors": plainIDAnchors,
|
"plainIDAnchors": plainIDAnchors,
|
||||||
|
|
|
@ -77,7 +77,6 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Site contains all the information relevant for constructing a static
|
// Site contains all the information relevant for constructing a static
|
||||||
|
@ -501,9 +500,9 @@ But this also means that your site configuration may not do what you expect. If
|
||||||
var relatedContentConfig related.Config
|
var relatedContentConfig related.Config
|
||||||
|
|
||||||
if cfg.Language.IsSet("related") {
|
if cfg.Language.IsSet("related") {
|
||||||
relatedContentConfig, err = related.DecodeConfig(cfg.Language.Get("related"))
|
relatedContentConfig, err = related.DecodeConfig(cfg.Language.GetParams("related"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "failed to decode related config")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
relatedContentConfig = related.DefaultConfig
|
relatedContentConfig = related.DefaultConfig
|
||||||
|
@ -574,7 +573,8 @@ func NewSite(cfg deps.DepsCfg) (*Site, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = applyDeps(cfg, s); err != nil {
|
var l configLoader
|
||||||
|
if err = l.applyDeps(cfg, s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,11 +586,11 @@ func NewSite(cfg deps.DepsCfg) (*Site, error) {
|
||||||
// Note: This is mainly used in single site tests.
|
// Note: This is mainly used in single site tests.
|
||||||
// TODO(bep) test refactor -- remove
|
// TODO(bep) test refactor -- remove
|
||||||
func NewSiteDefaultLang(withTemplate ...func(templ tpl.TemplateManager) error) (*Site, error) {
|
func NewSiteDefaultLang(withTemplate ...func(templ tpl.TemplateManager) error) (*Site, error) {
|
||||||
v := viper.New()
|
l := configLoader{cfg: config.New()}
|
||||||
if err := loadDefaultSettingsFor(v); err != nil {
|
if err := l.applyConfigDefaults(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newSiteForLang(langs.NewDefaultLanguage(v), withTemplate...)
|
return newSiteForLang(langs.NewDefaultLanguage(l.cfg), withTemplate...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnglishSite creates a new site in English language.
|
// NewEnglishSite creates a new site in English language.
|
||||||
|
@ -598,11 +598,11 @@ func NewSiteDefaultLang(withTemplate ...func(templ tpl.TemplateManager) error) (
|
||||||
// Note: This is mainly used in single site tests.
|
// Note: This is mainly used in single site tests.
|
||||||
// TODO(bep) test refactor -- remove
|
// TODO(bep) test refactor -- remove
|
||||||
func NewEnglishSite(withTemplate ...func(templ tpl.TemplateManager) error) (*Site, error) {
|
func NewEnglishSite(withTemplate ...func(templ tpl.TemplateManager) error) (*Site, error) {
|
||||||
v := viper.New()
|
l := configLoader{cfg: config.New()}
|
||||||
if err := loadDefaultSettingsFor(v); err != nil {
|
if err := l.applyConfigDefaults(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newSiteForLang(langs.NewLanguage("en", v), withTemplate...)
|
return newSiteForLang(langs.NewLanguage("en", l.cfg), withTemplate...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSiteForLang creates a new site in the given language.
|
// newSiteForLang creates a new site in the given language.
|
||||||
|
@ -1314,7 +1314,7 @@ func (s *Site) initializeSiteInfo() error {
|
||||||
return vvv
|
return vvv
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
m := cast.ToStringMapBool(v)
|
m := maps.ToStringMapBool(v)
|
||||||
uglyURLs = func(p page.Page) bool {
|
uglyURLs = func(p page.Page) bool {
|
||||||
return m[p.Section()]
|
return m[p.Section()]
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSiteWithPageOutputs(t *testing.T) {
|
func TestSiteWithPageOutputs(t *testing.T) {
|
||||||
|
@ -333,7 +333,7 @@ func TestCreateSiteOutputFormats(t *testing.T) {
|
||||||
page.KindSection: []string{"JSON"},
|
page.KindSection: []string{"JSON"},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
||||||
|
@ -358,7 +358,7 @@ func TestCreateSiteOutputFormats(t *testing.T) {
|
||||||
// Issue #4528
|
// Issue #4528
|
||||||
t.Run("Mixed case", func(t *testing.T) {
|
t.Run("Mixed case", func(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
|
|
||||||
outputsConfig := map[string]interface{}{
|
outputsConfig := map[string]interface{}{
|
||||||
// Note that we in Hugo 0.53.0 renamed this Kind to "taxonomy",
|
// Note that we in Hugo 0.53.0 renamed this Kind to "taxonomy",
|
||||||
|
@ -380,7 +380,7 @@ func TestCreateSiteOutputFormatsInvalidConfig(t *testing.T) {
|
||||||
page.KindHome: []string{"FOO", "JSON"},
|
page.KindHome: []string{"FOO", "JSON"},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
_, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
_, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
||||||
|
@ -394,7 +394,7 @@ func TestCreateSiteOutputFormatsEmptyConfig(t *testing.T) {
|
||||||
page.KindHome: []string{},
|
page.KindHome: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg.GetStringMap("outputs"), false)
|
||||||
|
@ -409,7 +409,7 @@ func TestCreateSiteOutputFormatsCustomFormats(t *testing.T) {
|
||||||
page.KindHome: []string{},
|
page.KindHome: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("outputs", outputsConfig)
|
cfg.Set("outputs", outputsConfig)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -23,10 +23,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gobuffalo/flect"
|
"github.com/gobuffalo/flect"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/publisher"
|
"github.com/gohugoio/hugo/publisher"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
|
@ -363,7 +362,7 @@ func TestMainSections(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
for _, paramSet := range []bool{false, true} {
|
for _, paramSet := range []bool{false, true} {
|
||||||
c.Run(fmt.Sprintf("param-%t", paramSet), func(c *qt.C) {
|
c.Run(fmt.Sprintf("param-%t", paramSet), func(c *qt.C) {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
if paramSet {
|
if paramSet {
|
||||||
v.Set("params", map[string]interface{}{
|
v.Set("params", map[string]interface{}{
|
||||||
"mainSections": []string{"a1", "a2"},
|
"mainSections": []string{"a1", "a2"},
|
||||||
|
|
|
@ -19,20 +19,19 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/identity"
|
"github.com/gohugoio/hugo/identity"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/tpl"
|
"github.com/gohugoio/hugo/tpl"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTemplateLookupOrder(t *testing.T) {
|
func TestTemplateLookupOrder(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
fs *hugofs.Fs
|
fs *hugofs.Fs
|
||||||
cfg *viper.Viper
|
cfg config.Provider
|
||||||
th testHelper
|
th testHelper
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/gohugoio/hugo/common/herrors"
|
"github.com/gohugoio/hugo/common/herrors"
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
|
@ -39,7 +40,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/tpl"
|
"github.com/gohugoio/hugo/tpl"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ type sitesBuilder struct {
|
||||||
// Default toml
|
// Default toml
|
||||||
configFormat string
|
configFormat string
|
||||||
configFileSet bool
|
configFileSet bool
|
||||||
viperSet bool
|
configSet bool
|
||||||
|
|
||||||
// Default is empty.
|
// Default is empty.
|
||||||
// TODO(bep) revisit this and consider always setting it to something.
|
// TODO(bep) revisit this and consider always setting it to something.
|
||||||
|
@ -111,7 +111,7 @@ type filenameContent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestSitesBuilder(t testing.TB) *sitesBuilder {
|
func newTestSitesBuilder(t testing.TB) *sitesBuilder {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
|
|
||||||
litterOptions := litter.Options{
|
litterOptions := litter.Options{
|
||||||
|
@ -140,7 +140,7 @@ func newTestSitesBuilderFromDepsCfg(t testing.TB, d deps.DepsCfg) *sitesBuilder
|
||||||
|
|
||||||
b.WithWorkingDir(workingDir)
|
b.WithWorkingDir(workingDir)
|
||||||
|
|
||||||
return b.WithViper(d.Cfg.(*viper.Viper))
|
return b.WithViper(d.Cfg.(config.Provider))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) Running() *sitesBuilder {
|
func (s *sitesBuilder) Running() *sitesBuilder {
|
||||||
|
@ -186,26 +186,26 @@ func (s *sitesBuilder) WithConfigTemplate(data interface{}, format, configTempla
|
||||||
return s.WithConfigFile(format, b.String())
|
return s.WithConfigFile(format, b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) WithViper(v *viper.Viper) *sitesBuilder {
|
func (s *sitesBuilder) WithViper(v config.Provider) *sitesBuilder {
|
||||||
s.T.Helper()
|
s.T.Helper()
|
||||||
if s.configFileSet {
|
if s.configFileSet {
|
||||||
s.T.Fatal("WithViper: use Viper or config.toml, not both")
|
s.T.Fatal("WithViper: use Viper or config.toml, not both")
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
s.viperSet = true
|
s.configSet = true
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Write to a config file to make sure the tests follow the same code path.
|
// Write to a config file to make sure the tests follow the same code path.
|
||||||
var buff bytes.Buffer
|
var buff bytes.Buffer
|
||||||
m := v.AllSettings()
|
m := v.Get("").(maps.Params)
|
||||||
s.Assert(parser.InterfaceToConfig(m, metadecoders.TOML, &buff), qt.IsNil)
|
s.Assert(parser.InterfaceToConfig(m, metadecoders.TOML, &buff), qt.IsNil)
|
||||||
return s.WithConfigFile("toml", buff.String())
|
return s.WithConfigFile("toml", buff.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sitesBuilder) WithConfigFile(format, conf string) *sitesBuilder {
|
func (s *sitesBuilder) WithConfigFile(format, conf string) *sitesBuilder {
|
||||||
s.T.Helper()
|
s.T.Helper()
|
||||||
if s.viperSet {
|
if s.configSet {
|
||||||
s.T.Fatal("WithConfigFile: use Viper or config.toml, not both")
|
s.T.Fatal("WithConfigFile: use config.Config or config.toml, not both")
|
||||||
}
|
}
|
||||||
s.configFileSet = true
|
s.configFileSet = true
|
||||||
filename := s.absFilename("config." + format)
|
filename := s.absFilename("config." + format)
|
||||||
|
@ -845,14 +845,14 @@ func (th testHelper) replaceDefaultContentLanguageValue(value string) string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadTestConfig(fs afero.Fs, withConfig ...func(cfg config.Provider) error) (*viper.Viper, error) {
|
func loadTestConfig(fs afero.Fs, withConfig ...func(cfg config.Provider) error) (config.Provider, error) {
|
||||||
v, _, err := LoadConfig(ConfigSourceDescriptor{Fs: fs}, withConfig...)
|
v, _, err := LoadConfig(ConfigSourceDescriptor{Fs: fs}, withConfig...)
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestCfgBasic() (*viper.Viper, *hugofs.Fs) {
|
func newTestCfgBasic() (config.Provider, *hugofs.Fs) {
|
||||||
mm := afero.NewMemMapFs()
|
mm := afero.NewMemMapFs()
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("defaultContentLanguageInSubdir", true)
|
v.Set("defaultContentLanguageInSubdir", true)
|
||||||
|
|
||||||
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(mm), v)
|
fs := hugofs.NewFrom(hugofs.NewBaseFileDecorator(mm), v)
|
||||||
|
@ -860,7 +860,7 @@ func newTestCfgBasic() (*viper.Viper, *hugofs.Fs) {
|
||||||
return v, fs
|
return v, fs
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestCfg(withConfig ...func(cfg config.Provider) error) (*viper.Viper, *hugofs.Fs) {
|
func newTestCfg(withConfig ...func(cfg config.Provider) error) (config.Provider, *hugofs.Fs) {
|
||||||
mm := afero.NewMemMapFs()
|
mm := afero.NewMemMapFs()
|
||||||
|
|
||||||
v, err := loadTestConfig(mm, func(cfg config.Provider) error {
|
v, err := loadTestConfig(mm, func(cfg config.Provider) error {
|
||||||
|
|
|
@ -43,13 +43,13 @@ func LoadLanguageSettings(cfg config.Provider, oldLangs Languages) (c LanguagesC
|
||||||
|
|
||||||
var languages map[string]interface{}
|
var languages map[string]interface{}
|
||||||
|
|
||||||
languagesFromConfig := cfg.GetStringMap("languages")
|
languagesFromConfig := cfg.GetParams("languages")
|
||||||
disableLanguages := cfg.GetStringSlice("disableLanguages")
|
disableLanguages := cfg.GetStringSlice("disableLanguages")
|
||||||
|
|
||||||
if len(disableLanguages) == 0 {
|
if len(disableLanguages) == 0 {
|
||||||
languages = languagesFromConfig
|
languages = languagesFromConfig
|
||||||
} else {
|
} else {
|
||||||
languages = make(map[string]interface{})
|
languages = make(maps.Params)
|
||||||
for k, v := range languagesFromConfig {
|
for k, v := range languagesFromConfig {
|
||||||
for _, disabled := range disableLanguages {
|
for _, disabled := range disableLanguages {
|
||||||
if disabled == defaultLang {
|
if disabled == defaultLang {
|
||||||
|
@ -57,7 +57,7 @@ func LoadLanguageSettings(cfg config.Provider, oldLangs Languages) (c LanguagesC
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.EqualFold(k, disabled) {
|
if strings.EqualFold(k, disabled) {
|
||||||
v.(map[string]interface{})["disabled"] = true
|
v.(maps.Params)["disabled"] = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ func toSortedLanguages(cfg config.Provider, l map[string]interface{}) (Languages
|
||||||
case "params":
|
case "params":
|
||||||
m := maps.ToStringMap(v)
|
m := maps.ToStringMap(v)
|
||||||
// Needed for case insensitive fetching of params values
|
// Needed for case insensitive fetching of params values
|
||||||
maps.ToLower(m)
|
maps.PrepareParams(m)
|
||||||
for k, vv := range m {
|
for k, vv := range m {
|
||||||
language.SetParam(k, vv)
|
language.SetParam(k, vv)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
|
||||||
|
@ -500,9 +499,9 @@ func newDepsConfig(tp *TranslationProvider, cfg config.Provider, fs *hugofs.Fs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getConfig() *viper.Viper {
|
func getConfig() config.Provider {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.SetDefault("defaultContentLanguage", "en")
|
v.Set("defaultContentLanguage", "en")
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
v.Set("dataDir", "data")
|
v.Set("dataDir", "data")
|
||||||
v.Set("i18nDir", "i18n")
|
v.Set("i18nDir", "i18n")
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/maps"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/spf13/cast"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// These are the settings that should only be looked up in the global Viper
|
// These are the settings that should only be looked up in the global Viper
|
||||||
|
@ -55,18 +54,20 @@ type Language struct {
|
||||||
// absolute directory reference. It is what we get.
|
// absolute directory reference. It is what we get.
|
||||||
ContentDir string
|
ContentDir string
|
||||||
|
|
||||||
|
// Global config.
|
||||||
Cfg config.Provider
|
Cfg config.Provider
|
||||||
|
|
||||||
|
// Language specific config.
|
||||||
|
LocalCfg config.Provider
|
||||||
|
|
||||||
|
// Composite config.
|
||||||
|
config.Provider
|
||||||
|
|
||||||
// These are params declared in the [params] section of the language merged with the
|
// These are params declared in the [params] section of the language merged with the
|
||||||
// site's params, the most specific (language) wins on duplicate keys.
|
// site's params, the most specific (language) wins on duplicate keys.
|
||||||
params map[string]interface{}
|
params map[string]interface{}
|
||||||
paramsMu sync.Mutex
|
paramsMu sync.Mutex
|
||||||
paramsSet bool
|
paramsSet bool
|
||||||
|
|
||||||
// These are config values, i.e. the settings declared outside of the [params] section of the language.
|
|
||||||
// This is the map Hugo looks in when looking for configuration values (baseURL etc.).
|
|
||||||
// Values in this map can also be fetched from the params map above.
|
|
||||||
settings map[string]interface{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Language) String() string {
|
func (l *Language) String() string {
|
||||||
|
@ -81,9 +82,12 @@ func NewLanguage(lang string, cfg config.Provider) *Language {
|
||||||
for k, v := range cfg.GetStringMap("params") {
|
for k, v := range cfg.GetStringMap("params") {
|
||||||
params[k] = v
|
params[k] = v
|
||||||
}
|
}
|
||||||
maps.ToLower(params)
|
maps.PrepareParams(params)
|
||||||
|
|
||||||
l := &Language{Lang: lang, ContentDir: cfg.GetString("contentDir"), Cfg: cfg, params: params, settings: make(map[string]interface{})}
|
localCfg := config.New()
|
||||||
|
compositeConfig := config.NewCompositeConfig(cfg, localCfg)
|
||||||
|
|
||||||
|
l := &Language{Lang: lang, ContentDir: cfg.GetString("contentDir"), Cfg: cfg, LocalCfg: localCfg, Provider: compositeConfig, params: params}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +137,7 @@ func (l *Language) Params() maps.Params {
|
||||||
l.paramsMu.Lock()
|
l.paramsMu.Lock()
|
||||||
defer l.paramsMu.Unlock()
|
defer l.paramsMu.Unlock()
|
||||||
if !l.paramsSet {
|
if !l.paramsSet {
|
||||||
maps.ToLower(l.params)
|
maps.PrepareParams(l.params)
|
||||||
l.paramsSet = true
|
l.paramsSet = true
|
||||||
}
|
}
|
||||||
return l.params
|
return l.params
|
||||||
|
@ -183,42 +187,6 @@ func (l *Language) SetParam(k string, v interface{}) {
|
||||||
l.params[k] = v
|
l.params[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBool returns the value associated with the key as a boolean.
|
|
||||||
func (l *Language) GetBool(key string) bool { return cast.ToBool(l.Get(key)) }
|
|
||||||
|
|
||||||
// GetString returns the value associated with the key as a string.
|
|
||||||
func (l *Language) GetString(key string) string { return cast.ToString(l.Get(key)) }
|
|
||||||
|
|
||||||
// GetInt returns the value associated with the key as an int.
|
|
||||||
func (l *Language) GetInt(key string) int { return cast.ToInt(l.Get(key)) }
|
|
||||||
|
|
||||||
// GetStringMap returns the value associated with the key as a map of interfaces.
|
|
||||||
func (l *Language) GetStringMap(key string) map[string]interface{} {
|
|
||||||
return maps.ToStringMap(l.Get(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStringMapString returns the value associated with the key as a map of strings.
|
|
||||||
func (l *Language) GetStringMapString(key string) map[string]string {
|
|
||||||
return cast.ToStringMapString(l.Get(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStringSlice returns the value associated with the key as a slice of strings.
|
|
||||||
func (l *Language) GetStringSlice(key string) []string {
|
|
||||||
return cast.ToStringSlice(l.Get(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns a value associated with the key relying on specified language.
|
|
||||||
// Get is case-insensitive for a key.
|
|
||||||
//
|
|
||||||
// Get returns an interface. For a specific value use one of the Get____ methods.
|
|
||||||
func (l *Language) Get(key string) interface{} {
|
|
||||||
local := l.GetLocal(key)
|
|
||||||
if local != nil {
|
|
||||||
return local
|
|
||||||
}
|
|
||||||
return l.Cfg.Get(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLocal gets a configuration value set on language level. It will
|
// GetLocal gets a configuration value set on language level. It will
|
||||||
// not fall back to any global value.
|
// not fall back to any global value.
|
||||||
// It will return nil if a value with the given key cannot be found.
|
// It will return nil if a value with the given key cannot be found.
|
||||||
|
@ -228,31 +196,29 @@ func (l *Language) GetLocal(key string) interface{} {
|
||||||
}
|
}
|
||||||
key = strings.ToLower(key)
|
key = strings.ToLower(key)
|
||||||
if !globalOnlySettings[key] {
|
if !globalOnlySettings[key] {
|
||||||
if v, ok := l.settings[key]; ok {
|
return l.LocalCfg.Get(key)
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the value for the key in the language's params.
|
func (l *Language) Set(k string, v interface{}) {
|
||||||
func (l *Language) Set(key string, value interface{}) {
|
k = strings.ToLower(k)
|
||||||
if l == nil {
|
if globalOnlySettings[k] {
|
||||||
panic("language not set")
|
return
|
||||||
}
|
}
|
||||||
key = strings.ToLower(key)
|
l.Provider.Set(k, v)
|
||||||
l.settings[key] = value
|
}
|
||||||
|
|
||||||
|
// Merge is currently not supported for Language.
|
||||||
|
func (l *Language) Merge(key string, value interface{}) {
|
||||||
|
panic("Not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSet checks whether the key is set in the language or the related config store.
|
// IsSet checks whether the key is set in the language or the related config store.
|
||||||
func (l *Language) IsSet(key string) bool {
|
func (l *Language) IsSet(key string) bool {
|
||||||
key = strings.ToLower(key)
|
|
||||||
|
|
||||||
key = strings.ToLower(key)
|
key = strings.ToLower(key)
|
||||||
if !globalOnlySettings[key] {
|
if !globalOnlySettings[key] {
|
||||||
if _, ok := l.settings[key]; ok {
|
return l.Provider.IsSet(key)
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return l.Cfg.IsSet(key)
|
return l.Cfg.IsSet(key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,14 @@ package langs
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetGlobalOnlySetting(t *testing.T) {
|
func TestGetGlobalOnlySetting(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("defaultContentLanguageInSubdir", true)
|
v.Set("defaultContentLanguageInSubdir", true)
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
v.Set("paginatePath", "page")
|
v.Set("paginatePath", "page")
|
||||||
|
@ -37,7 +38,7 @@ func TestGetGlobalOnlySetting(t *testing.T) {
|
||||||
func TestLanguageParams(t *testing.T) {
|
func TestLanguageParams(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("p1", "p1cfg")
|
v.Set("p1", "p1cfg")
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,17 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/markup/converter"
|
"github.com/gohugoio/hugo/markup/converter"
|
||||||
"github.com/gohugoio/hugo/markup/markup_config"
|
"github.com/gohugoio/hugo/markup/markup_config"
|
||||||
"github.com/gohugoio/hugo/markup/tableofcontents"
|
"github.com/gohugoio/hugo/markup/tableofcontents"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAsciidoctorDefaultArgs(t *testing.T) {
|
func TestAsciidoctorDefaultArgs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
|
|
||||||
p, err := Provider.New(
|
p, err := Provider.New(
|
||||||
|
@ -57,7 +57,7 @@ func TestAsciidoctorDefaultArgs(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorNonDefaultArgs(t *testing.T) {
|
func TestAsciidoctorNonDefaultArgs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
mconf.AsciidocExt.Backend = "manpage"
|
mconf.AsciidocExt.Backend = "manpage"
|
||||||
mconf.AsciidocExt.NoHeaderOrFooter = false
|
mconf.AsciidocExt.NoHeaderOrFooter = false
|
||||||
|
@ -88,7 +88,7 @@ func TestAsciidoctorNonDefaultArgs(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorDisallowedArgs(t *testing.T) {
|
func TestAsciidoctorDisallowedArgs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
mconf.AsciidocExt.Backend = "disallowed-backend"
|
mconf.AsciidocExt.Backend = "disallowed-backend"
|
||||||
mconf.AsciidocExt.Extensions = []string{"./disallowed-extension"}
|
mconf.AsciidocExt.Extensions = []string{"./disallowed-extension"}
|
||||||
|
@ -117,7 +117,7 @@ func TestAsciidoctorDisallowedArgs(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorArbitraryExtension(t *testing.T) {
|
func TestAsciidoctorArbitraryExtension(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
mconf.AsciidocExt.Extensions = []string{"arbitrary-extension"}
|
mconf.AsciidocExt.Extensions = []string{"arbitrary-extension"}
|
||||||
p, err := Provider.New(
|
p, err := Provider.New(
|
||||||
|
@ -142,7 +142,7 @@ func TestAsciidoctorArbitraryExtension(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorDisallowedExtension(t *testing.T) {
|
func TestAsciidoctorDisallowedExtension(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
for _, disallowedExtension := range []string{
|
for _, disallowedExtension := range []string{
|
||||||
`foo-bar//`,
|
`foo-bar//`,
|
||||||
`foo-bar\\ `,
|
`foo-bar\\ `,
|
||||||
|
@ -177,7 +177,7 @@ func TestAsciidoctorDisallowedExtension(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorWorkingFolderCurrent(t *testing.T) {
|
func TestAsciidoctorWorkingFolderCurrent(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
mconf.AsciidocExt.WorkingFolderCurrent = true
|
mconf.AsciidocExt.WorkingFolderCurrent = true
|
||||||
mconf.AsciidocExt.Trace = false
|
mconf.AsciidocExt.Trace = false
|
||||||
|
@ -208,7 +208,7 @@ func TestAsciidoctorWorkingFolderCurrent(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorWorkingFolderCurrentAndExtensions(t *testing.T) {
|
func TestAsciidoctorWorkingFolderCurrentAndExtensions(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
mconf.AsciidocExt.NoHeaderOrFooter = true
|
mconf.AsciidocExt.NoHeaderOrFooter = true
|
||||||
mconf.AsciidocExt.Extensions = []string{"asciidoctor-html5s", "asciidoctor-diagram"}
|
mconf.AsciidocExt.Extensions = []string{"asciidoctor-html5s", "asciidoctor-diagram"}
|
||||||
|
@ -247,7 +247,7 @@ func TestAsciidoctorWorkingFolderCurrentAndExtensions(t *testing.T) {
|
||||||
|
|
||||||
func TestAsciidoctorAttributes(t *testing.T) {
|
func TestAsciidoctorAttributes(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
mconf := markup_config.Default
|
mconf := markup_config.Default
|
||||||
mconf.AsciidocExt.Attributes = map[string]string{"my-base-url": "https://gohugo.io/", "my-attribute-name": "my value"}
|
mconf.AsciidocExt.Attributes = map[string]string{"my-base-url": "https://gohugo.io/", "my-attribute-name": "my value"}
|
||||||
mconf.AsciidocExt.Trace = false
|
mconf.AsciidocExt.Trace = false
|
||||||
|
|
|
@ -16,7 +16,7 @@ package blackfriday
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/markup/converter"
|
"github.com/gohugoio/hugo/markup/converter"
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ func TestGetAllFlags(t *testing.T) {
|
||||||
func TestConvert(t *testing.T) {
|
func TestConvert(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
p, err := Provider.New(converter.ProviderConfig{
|
p, err := Provider.New(converter.ProviderConfig{
|
||||||
Cfg: viper.New(),
|
Cfg: config.New(),
|
||||||
})
|
})
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
conv, err := p.New(converter.DocumentContext{})
|
conv, err := p.New(converter.DocumentContext{})
|
||||||
|
@ -153,7 +153,7 @@ func TestConvert(t *testing.T) {
|
||||||
func TestGetHTMLRendererAnchors(t *testing.T) {
|
func TestGetHTMLRendererAnchors(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
p, err := Provider.New(converter.ProviderConfig{
|
p, err := Provider.New(converter.ProviderConfig{
|
||||||
Cfg: viper.New(),
|
Cfg: config.New(),
|
||||||
})
|
})
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
conv, err := p.New(converter.DocumentContext{
|
conv, err := p.New(converter.DocumentContext{
|
||||||
|
|
|
@ -17,16 +17,15 @@ package highlight
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
func TestConfig(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
c.Run("applyLegacyConfig", func(c *qt.C) {
|
c.Run("applyLegacyConfig", func(c *qt.C) {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("pygmentsStyle", "hugo")
|
v.Set("pygmentsStyle", "hugo")
|
||||||
v.Set("pygmentsUseClasses", false)
|
v.Set("pygmentsUseClasses", false)
|
||||||
v.Set("pygmentsCodeFences", false)
|
v.Set("pygmentsCodeFences", false)
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/markup/tableofcontents"
|
"github.com/gohugoio/hugo/markup/tableofcontents"
|
||||||
"github.com/gohugoio/hugo/parser"
|
"github.com/gohugoio/hugo/parser"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/spf13/cast"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -73,7 +72,7 @@ func normalizeConfig(m map[string]interface{}) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vm := cast.ToStringMap(v)
|
vm := maps.ToStringMap(v)
|
||||||
// Changed from a bool in 0.81.0
|
// Changed from a bool in 0.81.0
|
||||||
if vv, found := vm["attribute"]; found {
|
if vv, found := vm["attribute"]; found {
|
||||||
if vvb, ok := vv.(bool); ok {
|
if vvb, ok := vv.(bool); ok {
|
||||||
|
|
|
@ -16,7 +16,7 @@ package markup_config
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
@ -26,7 +26,7 @@ func TestConfig(t *testing.T) {
|
||||||
|
|
||||||
c.Run("Decode", func(c *qt.C) {
|
c.Run("Decode", func(c *qt.C) {
|
||||||
c.Parallel()
|
c.Parallel()
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
v.Set("markup", map[string]interface{}{
|
v.Set("markup", map[string]interface{}{
|
||||||
"goldmark": map[string]interface{}{
|
"goldmark": map[string]interface{}{
|
||||||
|
@ -55,7 +55,7 @@ func TestConfig(t *testing.T) {
|
||||||
|
|
||||||
c.Run("legacy", func(c *qt.C) {
|
c.Run("legacy", func(c *qt.C) {
|
||||||
c.Parallel()
|
c.Parallel()
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
v.Set("blackfriday", map[string]interface{}{
|
v.Set("blackfriday", map[string]interface{}{
|
||||||
"angledQuotes": true,
|
"angledQuotes": true,
|
||||||
|
|
|
@ -16,17 +16,15 @@ package markup
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/markup/converter"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
"github.com/gohugoio/hugo/markup/converter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConverterRegistry(t *testing.T) {
|
func TestConverterRegistry(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
r, err := NewConverterProvider(converter.ProviderConfig{Cfg: viper.New()})
|
r, err := NewConverterProvider(converter.ProviderConfig{Cfg: config.New()})
|
||||||
|
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert("goldmark", qt.Equals, r.GetMarkupConfig().DefaultMarkdownHandler)
|
c.Assert("goldmark", qt.Equals, r.GetMarkupConfig().DefaultMarkdownHandler)
|
||||||
|
|
|
@ -16,7 +16,7 @@ package mmark
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func TestGetMmarkExtensions(t *testing.T) {
|
||||||
|
|
||||||
func TestConvert(t *testing.T) {
|
func TestConvert(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
p, err := Provider.New(converter.ProviderConfig{Cfg: viper.New(), Logger: loggers.NewErrorLogger()})
|
p, err := Provider.New(converter.ProviderConfig{Cfg: config.New(), Logger: loggers.NewErrorLogger()})
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
conv, err := p.New(converter.DocumentContext{})
|
conv, err := p.New(converter.DocumentContext{})
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
|
@ -16,8 +16,9 @@ package org
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/markup/converter"
|
"github.com/gohugoio/hugo/markup/converter"
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ func TestConvert(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
p, err := Provider.New(converter.ProviderConfig{
|
p, err := Provider.New(converter.ProviderConfig{
|
||||||
Logger: loggers.NewErrorLogger(),
|
Logger: loggers.NewErrorLogger(),
|
||||||
Cfg: viper.New(),
|
Cfg: config.New(),
|
||||||
})
|
})
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
conv, err := p.New(converter.DocumentContext{})
|
conv, err := p.New(converter.DocumentContext{})
|
||||||
|
|
|
@ -385,8 +385,8 @@ func DecodeTypes(mms ...map[string]interface{}) (Types, error) {
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vm := v.(map[string]interface{})
|
vm := maps.ToStringMap(v)
|
||||||
maps.ToLower(vm)
|
maps.PrepareParams(vm)
|
||||||
_, delimiterSet := vm["delimiter"]
|
_, delimiterSet := vm["delimiter"]
|
||||||
_, suffixSet := vm["suffix"]
|
_, suffixSet := vm["suffix"]
|
||||||
|
|
||||||
|
|
|
@ -99,10 +99,10 @@ func decodeConfig(cfg config.Provider) (conf minifyConfig, err error) {
|
||||||
|
|
||||||
// Handle upstream renames.
|
// Handle upstream renames.
|
||||||
if td, found := m["tdewolff"]; found {
|
if td, found := m["tdewolff"]; found {
|
||||||
tdm := cast.ToStringMap(td)
|
tdm := maps.ToStringMap(td)
|
||||||
for _, key := range []string{"css", "svg"} {
|
for _, key := range []string{"css", "svg"} {
|
||||||
if v, found := tdm[key]; found {
|
if v, found := tdm[key]; found {
|
||||||
vm := cast.ToStringMap(v)
|
vm := maps.ToStringMap(v)
|
||||||
if vv, found := vm["decimal"]; found {
|
if vv, found := vm["decimal"]; found {
|
||||||
vvi := cast.ToInt(vv)
|
vvi := cast.ToInt(vv)
|
||||||
if vvi > 0 {
|
if vvi > 0 {
|
||||||
|
|
|
@ -16,14 +16,14 @@ package minifiers
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
func TestConfig(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
v.Set("minify", map[string]interface{}{
|
v.Set("minify", map[string]interface{}{
|
||||||
"disablexml": true,
|
"disablexml": true,
|
||||||
|
@ -53,7 +53,7 @@ func TestConfig(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigLegacy(t *testing.T) {
|
func TestConfigLegacy(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
|
|
||||||
// This was a bool < Hugo v0.58.
|
// This was a bool < Hugo v0.58.
|
||||||
v.Set("minify", true)
|
v.Set("minify", true)
|
||||||
|
|
|
@ -19,16 +19,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/media"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
|
|
||||||
var rawJS string
|
var rawJS string
|
||||||
|
@ -76,7 +75,7 @@ func TestNew(t *testing.T) {
|
||||||
|
|
||||||
func TestConfigureMinify(t *testing.T) {
|
func TestConfigureMinify(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("minify", map[string]interface{}{
|
v.Set("minify", map[string]interface{}{
|
||||||
"disablexml": true,
|
"disablexml": true,
|
||||||
"tdewolff": map[string]interface{}{
|
"tdewolff": map[string]interface{}{
|
||||||
|
@ -110,7 +109,7 @@ func TestConfigureMinify(t *testing.T) {
|
||||||
|
|
||||||
func TestJSONRoundTrip(t *testing.T) {
|
func TestJSONRoundTrip(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
|
|
||||||
for _, test := range []string{`{
|
for _, test := range []string{`{
|
||||||
|
@ -148,7 +147,7 @@ func TestJSONRoundTrip(t *testing.T) {
|
||||||
|
|
||||||
func TestBugs(t *testing.T) {
|
func TestBugs(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
|
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
|
@ -171,7 +170,7 @@ func TestBugs(t *testing.T) {
|
||||||
// Renamed to Precision in v2.7.0. Check that we support both.
|
// Renamed to Precision in v2.7.0. Check that we support both.
|
||||||
func TestDecodeConfigDecimalIsNowPrecision(t *testing.T) {
|
func TestDecodeConfigDecimalIsNowPrecision(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("minify", map[string]interface{}{
|
v.Set("minify", map[string]interface{}{
|
||||||
"disablexml": true,
|
"disablexml": true,
|
||||||
"tdewolff": map[string]interface{}{
|
"tdewolff": map[string]interface{}{
|
||||||
|
|
|
@ -424,7 +424,7 @@ func (c *collector) applyThemeConfig(tc *moduleAdapter) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Warnf("Failed to read module config for %q in %q: %s", tc.Path(), themeTOML, err)
|
c.logger.Warnf("Failed to read module config for %q in %q: %s", tc.Path(), themeTOML, err)
|
||||||
} else {
|
} else {
|
||||||
maps.ToLower(themeCfg)
|
maps.PrepareParams(themeCfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/spf13/cast"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
)
|
)
|
||||||
|
@ -122,7 +122,7 @@ func Pack(fs afero.Fs, fis []hugofs.FileMetaInfo) error {
|
||||||
var commentsm map[string]interface{}
|
var commentsm map[string]interface{}
|
||||||
comments, found := b.originalPackageJSON["comments"]
|
comments, found := b.originalPackageJSON["comments"]
|
||||||
if found {
|
if found {
|
||||||
commentsm = cast.ToStringMap(comments)
|
commentsm = maps.ToStringMap(comments)
|
||||||
} else {
|
} else {
|
||||||
commentsm = make(map[string]interface{})
|
commentsm = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ func (b *packageBuilder) addm(source string, m map[string]interface{}) {
|
||||||
// These packages will be added by order of import (project, module1, module2...),
|
// These packages will be added by order of import (project, module1, module2...),
|
||||||
// so that should at least give the project control over the situation.
|
// so that should at least give the project control over the situation.
|
||||||
if devDeps, found := m[devDependenciesKey]; found {
|
if devDeps, found := m[devDependenciesKey]; found {
|
||||||
mm := cast.ToStringMapString(devDeps)
|
mm := maps.ToStringMapString(devDeps)
|
||||||
for k, v := range mm {
|
for k, v := range mm {
|
||||||
if _, added := b.devDependencies[k]; !added {
|
if _, added := b.devDependencies[k]; !added {
|
||||||
b.devDependencies[k] = v
|
b.devDependencies[k] = v
|
||||||
|
@ -215,7 +215,7 @@ func (b *packageBuilder) addm(source string, m map[string]interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if deps, found := m[dependenciesKey]; found {
|
if deps, found := m[dependenciesKey]; found {
|
||||||
mm := cast.ToStringMapString(deps)
|
mm := maps.ToStringMapString(deps)
|
||||||
for k, v := range mm {
|
for k, v := range mm {
|
||||||
if _, added := b.dependencies[k]; !added {
|
if _, added := b.dependencies[k]; !added {
|
||||||
b.dependencies[k] = v
|
b.dependencies[k] = v
|
||||||
|
|
|
@ -368,7 +368,11 @@ func decode(mediaTypes media.Types, input interface{}, output *Format) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return decoder.Decode(input)
|
if err = decoder.Decode(input); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to decode output format configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/minifiers"
|
"github.com/gohugoio/hugo/minifiers"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClassCollector(t *testing.T) {
|
func TestClassCollector(t *testing.T) {
|
||||||
|
@ -138,7 +139,7 @@ func TestClassCollector(t *testing.T) {
|
||||||
if skipMinifyTest[test.name] {
|
if skipMinifyTest[test.name] {
|
||||||
c.Skip("skip minify test")
|
c.Skip("skip minify test")
|
||||||
}
|
}
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
m, _ := minifiers.New(media.DefaultTypes, output.DefaultFormats, v)
|
m, _ := minifiers.New(media.DefaultTypes, output.DefaultFormats, v)
|
||||||
m.Minify(media.HTMLType, w, strings.NewReader(test.html))
|
m.Minify(media.HTMLType, w, strings.NewReader(test.html))
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/common/types"
|
"github.com/gohugoio/hugo/common/types"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
|
@ -404,16 +406,11 @@ func norm(num, min, max int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeConfig decodes a slice of map into Config.
|
// DecodeConfig decodes a slice of map into Config.
|
||||||
func DecodeConfig(in interface{}) (Config, error) {
|
func DecodeConfig(m maps.Params) (Config, error) {
|
||||||
if in == nil {
|
if m == nil {
|
||||||
return Config{}, errors.New("no related config provided")
|
return Config{}, errors.New("no related config provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
m, ok := in.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
return Config{}, fmt.Errorf("expected map[string]interface {} got %T", in)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(m) == 0 {
|
if len(m) == 0 {
|
||||||
return Config{}, errors.New("empty related config provided")
|
return Config{}, errors.New("empty related config provided")
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
)
|
)
|
||||||
|
@ -72,7 +73,7 @@ func newTestFd() *FrontMatterDescriptor {
|
||||||
func TestFrontMatterNewConfig(t *testing.T) {
|
func TestFrontMatterNewConfig(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
|
|
||||||
cfg.Set("frontmatter", map[string]interface{}{
|
cfg.Set("frontmatter", map[string]interface{}{
|
||||||
"date": []string{"publishDate", "LastMod"},
|
"date": []string{"publishDate", "LastMod"},
|
||||||
|
@ -89,7 +90,7 @@ func TestFrontMatterNewConfig(t *testing.T) {
|
||||||
c.Assert(fc.publishDate, qt.DeepEquals, []string{"date"})
|
c.Assert(fc.publishDate, qt.DeepEquals, []string{"date"})
|
||||||
|
|
||||||
// Default
|
// Default
|
||||||
cfg = viper.New()
|
cfg = config.New()
|
||||||
fc, err = newFrontmatterConfig(cfg)
|
fc, err = newFrontmatterConfig(cfg)
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
c.Assert(fc.date, qt.DeepEquals, []string{"date", "publishdate", "pubdate", "published", "lastmod", "modified"})
|
c.Assert(fc.date, qt.DeepEquals, []string{"date", "publishdate", "pubdate", "published", "lastmod", "modified"})
|
||||||
|
@ -117,7 +118,7 @@ func TestFrontMatterDatesHandlers(t *testing.T) {
|
||||||
|
|
||||||
for _, handlerID := range []string{":filename", ":fileModTime", ":git"} {
|
for _, handlerID := range []string{":filename", ":fileModTime", ":git"} {
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
|
|
||||||
cfg.Set("frontmatter", map[string]interface{}{
|
cfg.Set("frontmatter", map[string]interface{}{
|
||||||
"date": []string{handlerID, "date"},
|
"date": []string{handlerID, "date"},
|
||||||
|
@ -157,7 +158,7 @@ func TestFrontMatterDatesCustomConfig(t *testing.T) {
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("frontmatter", map[string]interface{}{
|
cfg.Set("frontmatter", map[string]interface{}{
|
||||||
"date": []string{"mydate"},
|
"date": []string{"mydate"},
|
||||||
"lastmod": []string{"publishdate"},
|
"lastmod": []string{"publishdate"},
|
||||||
|
@ -204,7 +205,7 @@ func TestFrontMatterDatesDefaultKeyword(t *testing.T) {
|
||||||
|
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
|
|
||||||
cfg.Set("frontmatter", map[string]interface{}{
|
cfg.Set("frontmatter", map[string]interface{}{
|
||||||
"date": []string{"mydate", ":default"},
|
"date": []string{"mydate", ":default"},
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
|
@ -196,7 +196,7 @@ func doTestPagerNoPages(t *testing.T, paginator *Paginator) {
|
||||||
func TestPaginationURLFactory(t *testing.T) {
|
func TestPaginationURLFactory(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("paginatePath", "zoo")
|
cfg.Set("paginatePath", "zoo")
|
||||||
|
|
||||||
for _, uglyURLs := range []bool{false, true} {
|
for _, uglyURLs := range []bool{false, true} {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/bep/gitmap"
|
"github.com/bep/gitmap"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/navigation"
|
"github.com/gohugoio/hugo/navigation"
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func newTestPageWithFile(filename string) *testPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestPathSpec() *helpers.PathSpec {
|
func newTestPathSpec() *helpers.PathSpec {
|
||||||
return newTestPathSpecFor(viper.New())
|
return newTestPathSpecFor(config.New())
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestPathSpecFor(cfg config.Provider) *helpers.PathSpec {
|
func newTestPathSpecFor(cfg config.Provider) *helpers.PathSpec {
|
||||||
|
|
|
@ -130,7 +130,7 @@ func AssignMetadata(metadata []map[string]interface{}, resources ...resource.Res
|
||||||
if found {
|
if found {
|
||||||
m := maps.ToStringMap(params)
|
m := maps.ToStringMap(params)
|
||||||
// Needed for case insensitive fetching of params values
|
// Needed for case insensitive fetching of params values
|
||||||
maps.ToLower(m)
|
maps.PrepareParams(m)
|
||||||
ma.updateParams(m)
|
ma.updateParams(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,17 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/cache/filecache"
|
"github.com/gohugoio/hugo/cache/filecache"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/gohugoio/hugo/output"
|
"github.com/gohugoio/hugo/output"
|
||||||
"github.com/gohugoio/hugo/resources"
|
"github.com/gohugoio/hugo/resources"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewTestResourceSpec() (*resources.Spec, error) {
|
func NewTestResourceSpec() (*resources.Spec, error) {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("baseURL", "https://example.org")
|
cfg.Set("baseURL", "https://example.org")
|
||||||
cfg.Set("publishDir", "public")
|
cfg.Set("publishDir", "public")
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,9 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/evanw/esbuild/pkg/api"
|
"github.com/evanw/esbuild/pkg/api"
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/media"
|
"github.com/gohugoio/hugo/media"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/spf13/cast"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -348,7 +347,7 @@ func toBuildOptions(opts Options) (buildOptions api.BuildOptions, err error) {
|
||||||
|
|
||||||
var defines map[string]string
|
var defines map[string]string
|
||||||
if opts.Defines != nil {
|
if opts.Defines != nil {
|
||||||
defines = cast.ToStringMapString(opts.Defines)
|
defines = maps.ToStringMapString(opts.Defines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default we only need to specify outDir and no outFile
|
// By default we only need to specify outDir and no outFile
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
|
|
||||||
|
@ -22,7 +23,6 @@ import (
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/resources/resource"
|
"github.com/gohugoio/hugo/resources/resource"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type specDescriptor struct {
|
type specDescriptor struct {
|
||||||
|
@ -31,8 +31,8 @@ type specDescriptor struct {
|
||||||
fs afero.Fs
|
fs afero.Fs
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTestCfg() *viper.Viper {
|
func createTestCfg() config.Provider {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("resourceDir", "resources")
|
cfg.Set("resourceDir", "resources")
|
||||||
cfg.Set("contentDir", "content")
|
cfg.Set("contentDir", "content")
|
||||||
cfg.Set("dataDir", "data")
|
cfg.Set("dataDir", "data")
|
||||||
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/modules"
|
"github.com/gohugoio/hugo/modules"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
|
@ -28,8 +30,6 @@ import (
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/helpers"
|
"github.com/gohugoio/hugo/helpers"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEmptySourceFilesystem(t *testing.T) {
|
func TestEmptySourceFilesystem(t *testing.T) {
|
||||||
|
@ -76,8 +76,8 @@ func TestUnicodeNorm(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestConfig() *viper.Viper {
|
func newTestConfig() config.Provider {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
v.Set("dataDir", "data")
|
v.Set("dataDir", "data")
|
||||||
v.Set("i18nDir", "i18n")
|
v.Set("i18nDir", "i18n")
|
||||||
|
|
|
@ -15,18 +15,18 @@ package cast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gohugoio/hugo/common/loggers"
|
"github.com/gohugoio/hugo/common/loggers"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/docshelper"
|
"github.com/gohugoio/hugo/docshelper"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file provides documentation support and is randomly put into this package.
|
// This file provides documentation support and is randomly put into this package.
|
||||||
func init() {
|
func init() {
|
||||||
docsProvider := func() docshelper.DocProvider {
|
docsProvider := func() docshelper.DocProvider {
|
||||||
d := &deps.Deps{
|
d := &deps.Deps{
|
||||||
Cfg: viper.New(),
|
Cfg: config.New(),
|
||||||
Log: loggers.NewErrorLogger(),
|
Log: loggers.NewErrorLogger(),
|
||||||
BuildStartListeners: &deps.Listeners{},
|
BuildStartListeners: &deps.Listeners{},
|
||||||
Site: page.NewDummyHugoSite(newTestConfig()),
|
Site: page.NewDummyHugoSite(newTestConfig()),
|
||||||
|
@ -46,8 +46,8 @@ func init() {
|
||||||
docshelper.AddDocProviderFunc(docsProvider)
|
docshelper.AddDocProviderFunc(docsProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestConfig() *viper.Viper {
|
func newTestConfig() config.Provider {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tstNoStringer struct{}
|
type tstNoStringer struct{}
|
||||||
|
@ -986,7 +986,7 @@ func newDeps(cfg config.Provider) *deps.Deps {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestNs() *Namespace {
|
func newTestNs() *Namespace {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
return New(newDeps(v))
|
return New(newDeps(v))
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
|
@ -28,7 +28,7 @@ func TestInit(t *testing.T) {
|
||||||
var found bool
|
var found bool
|
||||||
var ns *internal.TemplateFuncsNamespace
|
var ns *internal.TemplateFuncsNamespace
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
langs.LoadLanguageSettings(v, nil)
|
langs.LoadLanguageSettings(v, nil)
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,12 @@ import (
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/gohugoio/hugo/langs"
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScpGetLocal(t *testing.T) {
|
func TestScpGetLocal(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
fs := hugofs.NewMem(v)
|
fs := hugofs.NewMem(v)
|
||||||
ps := helpers.FilePathSeparator
|
ps := helpers.FilePathSeparator
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ func TestScpGetRemoteParallel(t *testing.T) {
|
||||||
c.Assert(err, qt.IsNil)
|
c.Assert(err, qt.IsNil)
|
||||||
|
|
||||||
for _, ignoreCache := range []bool{false} {
|
for _, ignoreCache := range []bool{false} {
|
||||||
cfg := viper.New()
|
cfg := config.New()
|
||||||
cfg.Set("ignoreCache", ignoreCache)
|
cfg.Set("ignoreCache", ignoreCache)
|
||||||
cfg.Set("contentDir", "content")
|
cfg.Set("contentDir", "content")
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ func newDeps(cfg config.Provider) *deps.Deps {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestNs() *Namespace {
|
func newTestNs() *Namespace {
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
return New(newDeps(v))
|
return New(newDeps(v))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/maps"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,7 +72,7 @@ func (ns *Namespace) Jsonify(args ...interface{}) (template.HTML, error) {
|
||||||
case 2:
|
case 2:
|
||||||
var opts map[string]string
|
var opts map[string]string
|
||||||
|
|
||||||
opts, err = cast.ToStringMapStringE(args[0])
|
opts, err = maps.ToStringMapStringE(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,21 @@ package hugo
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
var found bool
|
var found bool
|
||||||
var ns *internal.TemplateFuncsNamespace
|
var ns *internal.TemplateFuncsNamespace
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
s := page.NewDummyHugoSite(v)
|
s := page.NewDummyHugoSite(v)
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tstNoStringer struct{}
|
type tstNoStringer struct{}
|
||||||
|
@ -82,7 +82,7 @@ func TestNSConfig(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", "/a/b")
|
v.Set("workingDir", "/a/b")
|
||||||
|
|
||||||
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
||||||
|
|
|
@ -17,11 +17,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/hugofs"
|
"github.com/gohugoio/hugo/hugofs"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReadFile(t *testing.T) {
|
func TestReadFile(t *testing.T) {
|
||||||
|
@ -30,7 +31,7 @@ func TestReadFile(t *testing.T) {
|
||||||
|
|
||||||
workingDir := "/home/hugo"
|
workingDir := "/home/hugo"
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workingDir)
|
v.Set("workingDir", workingDir)
|
||||||
|
|
||||||
// f := newTestFuncsterWithViper(v)
|
// f := newTestFuncsterWithViper(v)
|
||||||
|
@ -68,7 +69,7 @@ func TestFileExists(t *testing.T) {
|
||||||
|
|
||||||
workingDir := "/home/hugo"
|
workingDir := "/home/hugo"
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workingDir)
|
v.Set("workingDir", workingDir)
|
||||||
|
|
||||||
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
||||||
|
@ -103,7 +104,7 @@ func TestStat(t *testing.T) {
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
workingDir := "/home/hugo"
|
workingDir := "/home/hugo"
|
||||||
|
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("workingDir", workingDir)
|
v.Set("workingDir", workingDir)
|
||||||
|
|
||||||
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
ns := New(&deps.Deps{Fs: hugofs.NewMem(v)})
|
||||||
|
|
|
@ -18,11 +18,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ns = New(&deps.Deps{Cfg: viper.New()})
|
var ns = New(&deps.Deps{Cfg: config.New()})
|
||||||
|
|
||||||
type tstNoStringer struct{}
|
type tstNoStringer struct{}
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,7 @@ func (ns *Namespace) ToCSS(args ...interface{}) (resource.Resource, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if m != nil {
|
if m != nil {
|
||||||
maps.ToLower(m)
|
maps.PrepareParams(m)
|
||||||
if t, found := m["transpiler"]; found {
|
if t, found := m["transpiler"]; found {
|
||||||
switch t {
|
switch t {
|
||||||
case transpilerDart, transpilerLibSass:
|
case transpilerDart, transpilerLibSass:
|
||||||
|
|
|
@ -16,12 +16,13 @@ package site
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
|
@ -29,7 +30,7 @@ func TestInit(t *testing.T) {
|
||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
var ns *internal.TemplateFuncsNamespace
|
var ns *internal.TemplateFuncsNamespace
|
||||||
v := viper.New()
|
v := config.New()
|
||||||
v.Set("contentDir", "content")
|
v.Set("contentDir", "content")
|
||||||
s := page.NewDummyHugoSite(v)
|
s := page.NewDummyHugoSite(v)
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,13 @@ package strings
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
|
@ -30,7 +31,7 @@ func TestInit(t *testing.T) {
|
||||||
var ns *internal.TemplateFuncsNamespace
|
var ns *internal.TemplateFuncsNamespace
|
||||||
|
|
||||||
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
||||||
ns = nsf(&deps.Deps{Cfg: viper.New()})
|
ns = nsf(&deps.Deps{Cfg: config.New()})
|
||||||
if ns.Name == name {
|
if ns.Name == name {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue