summaryrefslogtreecommitdiffstats
path: root/hugolib
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-06-09 10:58:18 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-06-14 17:00:32 +0200
commitd392893cd73dc00c927f342778f6dca9628d328e (patch)
treee2ea3eec09f36b7122ecdbc498c3c130e240e85c /hugolib
parenta886dd53b80322e1edf924f2ede4d4ea037c5baf (diff)
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
Diffstat (limited to 'hugolib')
-rw-r--r--hugolib/config.go680
-rw-r--r--hugolib/config_test.go372
-rw-r--r--hugolib/filesystems/basefs_test.go10
-rw-r--r--hugolib/hugo_modules_test.go30
-rw-r--r--hugolib/hugo_sites.go15
-rw-r--r--hugolib/hugo_sites_build_errors_test.go4
-rw-r--r--hugolib/image_test.go4
-rw-r--r--hugolib/js_test.go11
-rw-r--r--hugolib/minify_publisher_test.go4
-rw-r--r--hugolib/page__meta.go2
-rw-r--r--hugolib/page_test.go5
-rw-r--r--hugolib/pagebundler_test.go18
-rw-r--r--hugolib/pages_capture.go2
-rw-r--r--hugolib/paths/paths_test.go7
-rw-r--r--hugolib/resource_chain_babel_test.go6
-rw-r--r--hugolib/resource_chain_test.go18
-rw-r--r--hugolib/robotstxt_test.go4
-rw-r--r--hugolib/shortcode_test.go7
-rw-r--r--hugolib/site.go22
-rw-r--r--hugolib/site_output_test.go12
-rw-r--r--hugolib/site_test.go5
-rw-r--r--hugolib/template_test.go5
-rw-r--r--hugolib/testhelpers_test.go26
23 files changed, 601 insertions, 668 deletions
diff --git a/hugolib/config.go b/hugolib/config.go
index eaa6710ae..f559d7fd3 100644
--- a/hugolib/config.go
+++ b/hugolib/config.go
@@ -43,34 +43,136 @@ import (
"github.com/gohugoio/hugo/config/services"
"github.com/gohugoio/hugo/helpers"
"github.com/spf13/afero"
- "github.com/spf13/viper"
)
-// 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
+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")
- // Services contains config for services such as Google Analytics etc.
- Services services.Config
-}
+// LoadConfig loads Hugo configuration into a new Viper and then adds
+// a set of defaults.
+func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provider) error) (config.Provider, []string, error) {
-func loadSiteConfig(cfg config.Provider) (scfg SiteConfig, err error) {
- privacyConfig, err := privacy.DecodeConfig(cfg)
+ 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
+ return l.cfg, configFiles, err
}
- servicesConfig, err := services.DecodeConfig(cfg)
+ // 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
+ return l.cfg, configFiles, err
}
- scfg.Privacy = privacyConfig
- scfg.Services = servicesConfig
+ configFiles = append(configFiles, modulesConfigFiles...)
- return
+ 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
+}
+
+// LoadConfigDefault is a convenience method to load the default "config.toml" config.
+func LoadConfigDefault(fs afero.Fs) (config.Provider, error) {
+ v, _, err := LoadConfig(ConfigSourceDescriptor{Fs: fs, Filename: "config.toml"})
+ return v, err
}
// ConfigSourceDescriptor describes where to find the config (e.g. config.toml etc.).
@@ -98,6 +200,13 @@ type ConfigSourceDescriptor struct {
Environ []string
}
+func (d ConfigSourceDescriptor) configFileDir() string {
+ if d.Path != "" {
+ return d.Path
+ }
+ return d.WorkingDir
+}
+
func (d ConfigSourceDescriptor) configFilenames() []string {
if d.Filename == "" {
return []string{"config"}
@@ -105,185 +214,219 @@ func (d ConfigSourceDescriptor) configFilenames() []string {
return strings.Split(d.Filename, ",")
}
-func (d ConfigSourceDescriptor) configFileDir() string {
- if d.Path != "" {
- return d.Path
- }
- return d.WorkingDir
+// 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
+
+ // Services contains config for services such as Google Analytics etc.
+ Services services.Config
}
-// LoadConfigDefault is a convenience method to load the default "config.toml" config.
-func LoadConfigDefault(fs afero.Fs) (*viper.Viper, error) {
- v, _, err := LoadConfig(ConfigSourceDescriptor{Fs: fs, Filename: "config.toml"})
- return v, err
+type configLoader struct {
+ cfg config.Provider
+ ConfigSourceDescriptor
}
-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")
+// Handle some legacy values.
+func (l configLoader) applyConfigAliases() error {
+ aliases := []types.KeyValueStr{{Key: "taxonomies", Value: "indexes"}}
-// LoadConfig loads Hugo configuration into a new Viper and then adds
-// a set of defaults.
-func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provider) error) (*viper.Viper, []string, error) {
- if d.Environment == "" {
- d.Environment = hugo.EnvironmentProduction
+ for _, alias := range aliases {
+ if l.cfg.IsSet(alias.Key) {
+ vv := l.cfg.Get(alias.Key)
+ l.cfg.Set(alias.Value, vv)
+ }
}
- if len(d.Environ) == 0 {
- d.Environ = os.Environ()
- }
+ return nil
+}
- var configFiles []string
+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)
- v := viper.New()
- l := configLoader{ConfigSourceDescriptor: d}
+ return nil
+}
- 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
- }
+func (l configLoader) applyOsEnvOverrides(environ []string) error {
+ if len(environ) == 0 {
+ return nil
}
- if d.AbsConfigDir != "" {
- dirnames, err := l.loadConfigFromConfigDir(v)
- if err == nil {
- configFiles = append(configFiles, dirnames...)
- } else if err != ErrNoConfigFile {
- return nil, nil, err
- }
- }
+ const delim = "__env__delim"
- if err := loadDefaultSettingsFor(v); err != nil {
- return v, configFiles, err
- }
+ // 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,
+ })
- // 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, l.cfg.Get)
+ if err != nil {
+ return err
}
- for _, env := range hugoEnv {
- existing, nestedKey, owner, err := maps.GetNestedParamFn(env.Key, delim, v.Get)
+ if existing != nil {
+ val, err := metadecoders.Default.UnmarshalStringTo(env.Value, existing)
if err != nil {
- return err
+ continue
}
- 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
+ if owner != nil {
+ owner[nestedKey] = val
} else {
- v.Set(strings.ReplaceAll(env.Key, delim, "."), env.Value)
+ 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
+ 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")
}
- if err := applyOsEnvOverrides(); err != nil {
- return v, configFiles, err
- }
+ themesDir := paths.AbsPathify(l.WorkingDir, v1.GetString("themesDir"))
- // 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", "**")
+ var ignoreVendor glob.Glob
+ if s := v1.GetString("ignoreVendorPaths"); s != "" {
+ ignoreVendor, _ = hglob.GetGlob(hglob.NormalizePath(s))
}
- modulesConfig, err := l.loadModulesConfig(v)
+ filecacheConfigs, err := filecache.DecodeConfig(l.Fs, v1)
if err != nil {
- return v, configFiles, err
+ return nil, nil, 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
- }
+ v1.Set("filecacheConfigs", filecacheConfigs)
- mods := m.ActiveModules
+ var configFilenames []string
- // Apply default project mounts.
- if err := modules.ApplyProjectConfigDefaults(v, mods[0]); err != nil {
- return err
+ 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
}
- _, modulesConfigFiles, err := l.collectModules(modulesConfig, v, collectHook)
+ modulesClient := modules.NewClient(modules.ClientConfig{
+ Fs: l.Fs,
+ Logger: l.Logger,
+ HookBeforeFinalize: hook,
+ WorkingDir: workingDir,
+ ThemesDir: themesDir,
+ CacheDir: filecacheConfigs.CacheDirModules(),
+ ModuleConfig: modConfig,
+ IgnoreVendor: ignoreVendor,
+ })
- if err == nil && len(modulesConfigFiles) > 0 {
- configFiles = append(configFiles, modulesConfigFiles...)
- }
+ v1.Set("modulesClient", modulesClient)
- if err := applyOsEnvOverrides(); err != nil {
- return v, configFiles, err
- }
+ moduleConfig, err := modulesClient.Collect()
- return v, configFiles, err
-}
+ // Avoid recreating these later.
+ v1.Set("allModules", moduleConfig.ActiveModules)
-func loadLanguageSettings(cfg config.Provider, oldLangs langs.Languages) error {
- _, err := langs.LoadLanguageSettings(cfg, oldLangs)
- return err
-}
+ if moduleConfig.GoModulesFilename != "" {
+ // We want to watch this for changes and trigger rebuild on version
+ // changes etc.
+ configFilenames = append(configFilenames, moduleConfig.GoModulesFilename)
+ }
-type configLoader struct {
- ConfigSourceDescriptor
+ return moduleConfig.ActiveModules, configFilenames, err
}
-func (l configLoader) loadConfig(configName string, v *viper.Viper) (string, error) {
+func (l configLoader) loadConfig(configName string) (string, error) {
baseDir := l.configFileDir()
var baseFilename string
if filepath.IsAbs(configName) {
@@ -318,24 +461,13 @@ func (l configLoader) loadConfig(configName string, v *viper.Viper) (string, err
return "", l.wrapFileError(err, filename)
}
- if err = v.MergeConfigMap(m); err != nil {
- return "", l.wrapFileError(err, filename)
- }
+ // Set overwrites keys of the same name, recursively.
+ l.cfg.Set("", m)
return filename, nil
}
-func (l configLoader) wrapFileError(err error, filename string) error {
- err, _ = herrors.WithFileContextForFile(
- err,
- filename,
- filename,
- l.Fs,
- herrors.SimpleLineMatcher)
- return err
-}
-
-func (l configLoader) loadConfigFromConfigDir(v *viper.Viper) ([]string, error) {
+func (l configLoader) loadConfigFromConfigDir() ([]string, error) {
sourceFs := l.Fs
configDir := l.AbsConfigDir
@@ -421,9 +553,8 @@ func (l configLoader) loadConfigFromConfigDir(v *viper.Viper) ([]string, error)
// Migrate menu => menus etc.
config.RenameKeys(root)
- if err := v.MergeConfigMap(root); err != nil {
- return l.wrapFileError(err, path)
- }
+ // Set will overwrite keys with the same name, recursively.
+ l.cfg.Set("", root)
return nil
})
@@ -436,8 +567,13 @@ func (l configLoader) loadConfigFromConfigDir(v *viper.Viper) ([]string, error)
return dirnames, nil
}
-func (l configLoader) loadModulesConfig(v1 *viper.Viper) (modules.Config, error) {
- modConfig, err := modules.DecodeConfig(v1)
+func (l configLoader) loadLanguageSettings(oldLangs langs.Languages) error {
+ _, err := langs.LoadLanguageSettings(l.cfg, oldLangs)
+ return err
+}
+
+func (l configLoader) loadModulesConfig() (modules.Config, error) {
+ modConfig, err := modules.DecodeConfig(l.cfg)
if err != nil {
return modules.Config{}, err
}
@@ -445,211 +581,29 @@ func (l configLoader) loadModulesConfig(v1 *viper.Viper) (modules.Config, error)
return modConfig, nil
}
-func (l configLoader) collectModules(modConfig modules.Config, v1 *viper.Viper, 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)
+func (configLoader) loadSiteConfig(cfg config.Provider) (scfg SiteConfig, err error) {
+ privacyConfig, err := privacy.DecodeConfig(cfg)
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
}
- if !v1.IsSet(key) && !(rootKey != "" && rootKey != key && v1.IsSet(rootKey)) {
- v1.Set(key, v2.Get(key))
+ servicesConfig, err := services.DecodeConfig(cfg)
+ if err != nil {
return
}
- m1 := v1.GetStringMap(key)
- m2 := v2.GetStringMap(key)
+ scfg.Privacy = privacyConfig
+ scfg.Services = servicesConfig
- for k, v := range m2 {
- if _, found := m1[k]; !found {
- if rootKey != "" && v1.IsSet(rootKey+"."+k) {
- continue
- }
- m1[k] = v
- }
- }
+ return
}
-func loadDefaultSettingsFor(v *viper.Viper) error {
- v.RegisterAlias("indexes", "taxonomies")
-
- /*
-
- TODO(bep) from 0.56 these are configured as module mounts.
- v.SetDefault("contentDir", "content")
- v.SetDefault("layoutDir", "layouts")
- v.SetDefault("assetDir", "assets")
- v.SetDefault("staticDir", "static")
- v.SetDefault("dataDir", "data")
- v.SetDefault("i18nDir", "i18n")
- v.SetDefault("archetypeDir", "archetypes")
- */
-
- v.SetDefault("cleanDestinationDir", false)