summaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/allconfig/allconfig.go136
-rw-r--r--config/allconfig/alldecoders.go2
-rw-r--r--config/allconfig/configlanguage.go12
-rw-r--r--config/allconfig/docshelper.go3
-rw-r--r--config/allconfig/integration_test.go7
-rw-r--r--config/allconfig/load.go12
-rw-r--r--config/commonConfig.go23
-rw-r--r--config/commonConfig_test.go14
-rw-r--r--config/configProvider.go3
-rw-r--r--config/env.go37
-rw-r--r--config/namespace.go3
-rw-r--r--config/namespace_test.go12
-rw-r--r--config/testconfig/testconfig.go5
13 files changed, 149 insertions, 120 deletions
diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go
index 9f0d73ecd..5788e792b 100644
--- a/config/allconfig/allconfig.go
+++ b/config/allconfig/allconfig.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -30,6 +30,7 @@ import (
"github.com/gohugoio/hugo/common/hugo"
"github.com/gohugoio/hugo/common/loggers"
"github.com/gohugoio/hugo/common/maps"
+ "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/urls"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/config/privacy"
@@ -283,12 +284,13 @@ func (c *Config) CompileConfig(logger loggers.Logger) error {
disabledLangs := make(map[string]bool)
for _, lang := range c.DisableLanguages {
- if lang == c.DefaultContentLanguage {
- return fmt.Errorf("cannot disable default content language %q", lang)
- }
disabledLangs[lang] = true
}
for lang, language := range c.Languages {
+ if !language.Disabled && disabledLangs[lang] {
+ language.Disabled = true
+ c.Languages[lang] = language
+ }
if language.Disabled {
disabledLangs[lang] = true
if lang == c.DefaultContentLanguage {
@@ -408,15 +410,19 @@ type ConfigCompiled struct {
}
// This may be set after the config is compiled.
-func (c *ConfigCompiled) SetMainSectionsIfNotSet(sections []string) {
+func (c *ConfigCompiled) SetMainSections(sections []string) {
c.mu.Lock()
defer c.mu.Unlock()
- if c.MainSections != nil {
- return
- }
c.MainSections = sections
}
+// IsMainSectionsSet returns whether the main sections have been set.
+func (c *ConfigCompiled) IsMainSectionsSet() bool {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ return c.MainSections != nil
+}
+
// This is set after the config is compiled by the server command.
func (c *ConfigCompiled) SetBaseURL(baseURL, baseURLLiveReload urls.BaseURL) {
c.BaseURL = baseURL
@@ -425,7 +431,6 @@ func (c *ConfigCompiled) SetBaseURL(baseURL, baseURLLiveReload urls.BaseURL) {
// RootConfig holds all the top-level configuration options in Hugo
type RootConfig struct {
-
// The base URL of the site.
// Note that the default value is empty, but Hugo requires a valid URL (e.g. "https://example.com/") to work properly.
// <docsmeta>{"identifiers": ["URL"] }</docsmeta>
@@ -648,13 +653,16 @@ type Configs struct {
LanguageConfigMap map[string]*Config
LanguageConfigSlice []*Config
- IsMultihost bool
- Languages langs.Languages
- LanguagesDefaultFirst langs.Languages
+ IsMultihost bool
Modules modules.Modules
ModulesClient *modules.Client
+ // All below is set in Init.
+ Languages langs.Languages
+ LanguagesDefaultFirst langs.Languages
+ ContentPathParser paths.PathParser
+
configLangs []config.AllProvider
}
@@ -674,6 +682,58 @@ func (c *Configs) IsZero() bool {
}
func (c *Configs) Init() error {
+ var languages langs.Languages
+ defaultContentLanguage := c.Base.DefaultContentLanguage
+ for k, v := range c.LanguageConfigMap {
+ c.LanguageConfigSlice = append(c.LanguageConfigSlice, v)
+ languageConf := v.Languages[k]
+ language, err := langs.NewLanguage(k, defaultContentLanguage, v.TimeZone, languageConf)
+ if err != nil {
+ return err
+ }
+ languages = append(languages, language)
+ }
+
+ // Sort the sites by language weight (if set) or lang.
+ sort.Slice(languages, func(i, j int) bool {
+ li := languages[i]
+ lj := languages[j]
+ if li.Weight != lj.Weight {
+ return li.Weight < lj.Weight
+ }
+ return li.Lang < lj.Lang
+ })
+
+ for _, l := range languages {
+ c.LanguageConfigSlice = append(c.LanguageConfigSlice, c.LanguageConfigMap[l.Lang])
+ }
+
+ // Filter out disabled languages.
+ var n int
+ for _, l := range languages {
+ if !l.Disabled {
+ languages[n] = l
+ n++
+ }
+ }
+ languages = languages[:n]
+
+ var languagesDefaultFirst langs.Languages
+ for _, l := range languages {
+ if l.Lang == defaultContentLanguage {
+ languagesDefaultFirst = append(languagesDefaultFirst, l)
+ }
+ }
+ for _, l := range languages {
+ if l.Lang != defaultContentLanguage {
+ languagesDefaultFirst = append(languagesDefaultFirst, l)
+ }
+ }
+
+ c.Languages = languages
+ c.LanguagesDefaultFirst = languagesDefaultFirst
+ c.ContentPathParser = paths.PathParser{LanguageIndex: languagesDefaultFirst.AsIndexSet()}
+
c.configLangs = make([]config.AllProvider, len(c.Languages))
for i, l := range c.LanguagesDefaultFirst {
c.configLangs[i] = ConfigLanguage{
@@ -751,7 +811,6 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
}
langConfigMap := make(map[string]*Config)
- var langConfigs []*Config
languagesConfig := cfg.GetStringMap("languages")
var isMultiHost bool
@@ -848,65 +907,24 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
}
}
- var languages langs.Languages
- defaultContentLanguage := all.DefaultContentLanguage
- for k, v := range langConfigMap {
- languageConf := v.Languages[k]
- language, err := langs.NewLanguage(k, defaultContentLanguage, v.TimeZone, languageConf)
- if err != nil {
- return nil, err
- }
- languages = append(languages, language)
- }
-
- // Sort the sites by language weight (if set) or lang.
- sort.Slice(languages, func(i, j int) bool {
- li := languages[i]
- lj := languages[j]
- if li.Weight != lj.Weight {
- return li.Weight < lj.Weight
- }
- return li.Lang < lj.Lang
- })
-
- for _, l := range languages {
- langConfigs = append(langConfigs, langConfigMap[l.Lang])
- }
-
- var languagesDefaultFirst langs.Languages
- for _, l := range languages {
- if l.Lang == defaultContentLanguage {
- languagesDefaultFirst = append(languagesDefaultFirst, l)
- }
- }
- for _, l := range languages {
- if l.Lang != defaultContentLanguage {
- languagesDefaultFirst = append(languagesDefaultFirst, l)
- }
- }
-
bcfg.PublishDir = all.PublishDir
res.BaseConfig = bcfg
all.CommonDirs.CacheDir = bcfg.CacheDir
- for _, l := range langConfigs {
+ for _, l := range langConfigMap {
l.CommonDirs.CacheDir = bcfg.CacheDir
}
cm := &Configs{
- Base: all,
- LanguageConfigMap: langConfigMap,
- LanguageConfigSlice: langConfigs,
- LoadingInfo: res,
- IsMultihost: isMultiHost,
- Languages: languages,
- LanguagesDefaultFirst: languagesDefaultFirst,
+ Base: all,
+ LanguageConfigMap: langConfigMap,
+ LoadingInfo: res,
+ IsMultihost: isMultiHost,
}
return cm, nil
}
func decodeConfigFromParams(fs afero.Fs, logger loggers.Logger, bcfg config.BaseConfig, p config.Provider, target *Config, keys []string) error {
-
var decoderSetups []decodeWeight
if len(keys) == 0 {
diff --git a/config/allconfig/alldecoders.go b/config/allconfig/alldecoders.go
index dc58882f3..f96c19cfc 100644
--- a/config/allconfig/alldecoders.go
+++ b/config/allconfig/alldecoders.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
diff --git a/config/allconfig/configlanguage.go b/config/allconfig/configlanguage.go
index 2c5a116f4..71bd232de 100644
--- a/config/allconfig/configlanguage.go
+++ b/config/allconfig/configlanguage.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -16,6 +16,7 @@ package allconfig
import (
"time"
+ "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/urls"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/langs"
@@ -41,10 +42,15 @@ func (c ConfigLanguage) LanguagesDefaultFirst() langs.Languages {
return c.m.LanguagesDefaultFirst
}
+func (c ConfigLanguage) PathParser() paths.PathParser {
+ return c.m.ContentPathParser
+}
+
func (c ConfigLanguage) LanguagePrefix() string {
if c.DefaultContentLanguageInSubdir() && c.DefaultContentLanguage() == c.Language().Lang {
return c.Language().Lang
}
+
if !c.IsMultiLingual() || c.DefaultContentLanguage() == c.Language().Lang {
return ""
}
@@ -119,6 +125,10 @@ func (c ConfigLanguage) Quiet() bool {
return c.m.Base.Internal.Quiet
}
+func (c ConfigLanguage) Watching() bool {
+ return c.m.Base.Internal.Watch
+}
+
// GetConfigSection is mostly used in tests. The switch statement isn't complete, but what's in use.
func (c ConfigLanguage) GetConfigSection(s string) any {
switch s {
diff --git a/config/allconfig/docshelper.go b/config/allconfig/docshelper.go
index 48a09de51..1a5fb6153 100644
--- a/config/allconfig/docshelper.go
+++ b/config/allconfig/docshelper.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -22,7 +22,6 @@ import (
// This is is just some helpers used to create some JSON used in the Hugo docs.
func init() {
docsProvider := func() docshelper.DocProvider {
-
cfg := config.New()
for configRoot, v := range allDecoderSetups {
if v.internalOrDeprecated {
diff --git a/config/allconfig/integration_test.go b/config/allconfig/integration_test.go
index fcb92e71d..4f2f1a06e 100644
--- a/config/allconfig/integration_test.go
+++ b/config/allconfig/integration_test.go
@@ -10,7 +10,6 @@ import (
)
func TestDirsMount(t *testing.T) {
-
files := `
-- hugo.toml --
baseURL = "https://example.com"
@@ -44,7 +43,7 @@ Title: {{ .Title }}
hugolib.IntegrationTestConfig{T: t, TxtarString: files},
).Build()
- //b.AssertFileContent("public/p1/index.html", "Title: p1")
+ // b.AssertFileContent("public/p1/index.html", "Title: p1")
sites := b.H.Sites
b.Assert(len(sites), qt.Equals, 2)
@@ -58,7 +57,7 @@ Title: {{ .Title }}
enConcp := sites[0].Conf
enConf := enConcp.GetConfig().(*allconfig.Config)
- b.Assert(enConcp.BaseURL().String(), qt.Equals, "https://example.com")
+ b.Assert(enConcp.BaseURL().String(), qt.Equals, "https://example.com/")
modConf := enConf.Module
b.Assert(modConf.Mounts, qt.HasLen, 8)
b.Assert(modConf.Mounts[0].Source, qt.Equals, filepath.FromSlash("content/en"))
@@ -67,11 +66,9 @@ Title: {{ .Title }}
b.Assert(modConf.Mounts[1].Source, qt.Equals, filepath.FromSlash("content/sv"))
b.Assert(modConf.Mounts[1].Target, qt.Equals, "content")
b.Assert(modConf.Mounts[1].Lang, qt.Equals, "sv")
-
}
func TestConfigAliases(t *testing.T) {
-
files := `
-- hugo.toml --
baseURL = "https://example.com"
diff --git a/config/allconfig/load.go b/config/allconfig/load.go
index 7d706c7e3..eceed31f4 100644
--- a/config/allconfig/load.go
+++ b/config/allconfig/load.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -37,6 +37,7 @@ import (
"github.com/spf13/afero"
)
+//lint:ignore ST1005 end user message.
var ErrNoConfigFile = errors.New("Unable to locate config file or config directory. Perhaps you need to create a new site.\n Run `hugo help new` for details.\n")
func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
@@ -566,15 +567,6 @@ func (l configLoader) deleteMergeStrategies() {
})
}
-func (l configLoader) loadModulesConfig() (modules.Config, error) {
- modConfig, err := modules.DecodeConfig(l.cfg)
- if err != nil {
- return modules.Config{}, err
- }
-
- return modConfig, nil
-}
-
func (l configLoader) wrapFileError(err error, filename string) error {
fe := herrors.UnwrapFileError(err)
if fe != nil {
diff --git a/config/commonConfig.go b/config/commonConfig.go
index ef9d47553..6ca061093 100644
--- a/config/commonConfig.go
+++ b/config/commonConfig.go
@@ -86,28 +86,21 @@ var defaultBuild = BuildConfig{
CacheBusters: []CacheBuster{
{
- Source: `assets/.*\.(js|ts|jsx|tsx)`,
- Target: `(js|scripts|javascript)`,
- },
- {
- Source: `assets/.*\.(css|sass|scss)$`,
- Target: cssTargetCachebusterRe,
- },
- {
Source: `(postcss|tailwind)\.config\.js`,
Target: cssTargetCachebusterRe,
},
- // This is deliberately coarse grained; it will cache bust resources with "json" in the cache key when js files changes, which is good.
- {
- Source: `assets/.*\.(.*)$`,
- Target: `$1`,
- },
},
}
// BuildConfig holds some build related configuration.
type BuildConfig struct {
- UseResourceCacheWhen string // never, fallback, always. Default is fallback
+ // When to use the resource file cache.
+ // One of never, fallback, always. Default is fallback
+ UseResourceCacheWhen string
+
+ // When enabled, will duplicate bundled resource files across languages that
+ // doesn't have a translated version.
+ DuplicateResourceFiles bool
// When enabled, will collect and write a hugo_stats.json with some build
// related aggregated data (e.g. CSS class names).
@@ -373,7 +366,6 @@ func (c *CacheBuster) CompileConfig(logger loggers.Logger) error {
return match
}
-
}
return compileErr
}
@@ -416,7 +408,6 @@ func DecodeServer(cfg Provider) (Server, error) {
Status: 404,
},
}
-
}
return *s, nil
diff --git a/config/commonConfig_test.go b/config/commonConfig_test.go
index 8aa1318dd..425d3e970 100644
--- a/config/commonConfig_test.go
+++ b/config/commonConfig_test.go
@@ -148,21 +148,13 @@ func TestBuildConfigCacheBusters(t *testing.T) {
l := loggers.NewDefault()
c.Assert(conf.CompileConfig(l), qt.IsNil)
- m, err := conf.MatchCacheBuster(l, "assets/foo/main.js")
- c.Assert(err, qt.IsNil)
+ m, _ := conf.MatchCacheBuster(l, "tailwind.config.js")
c.Assert(m, qt.IsNotNil)
- c.Assert(m("scripts"), qt.IsTrue)
- c.Assert(m("asdf"), qt.IsFalse)
-
- m, _ = conf.MatchCacheBuster(l, "tailwind.config.js")
c.Assert(m("css"), qt.IsTrue)
c.Assert(m("js"), qt.IsFalse)
- m, err = conf.MatchCacheBuster(l, "assets/foo.json")
- c.Assert(err, qt.IsNil)
- c.Assert(m, qt.IsNotNil)
- c.Assert(m("json"), qt.IsTrue)
-
+ m, _ = conf.MatchCacheBuster(l, "foo.bar")
+ c.Assert(m, qt.IsNil)
}
func TestBuildConfigCacheBusterstTailwindSetup(t *testing.T) {
diff --git a/config/configProvider.go b/config/configProvider.go
index 11099e407..2536639ea 100644
--- a/config/configProvider.go
+++ b/config/configProvider.go
@@ -17,6 +17,7 @@ import (
"time"
"github.com/gohugoio/hugo/common/maps"
+ "github.com/gohugoio/hugo/common/paths"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/common/urls"
"github.com/gohugoio/hugo/langs"
@@ -30,6 +31,7 @@ type AllProvider interface {
LanguagePrefix() string
BaseURL() urls.BaseURL
BaseURLLiveReload() urls.BaseURL
+ PathParser() paths.PathParser
Environment() string
IsMultihost() bool
IsMultiLingual() bool
@@ -54,6 +56,7 @@ type AllProvider interface {
BuildFuture() bool
BuildDrafts() bool
Running() bool
+ Watching() bool
PrintUnusedTemplates() bool
EnableMissingTranslationPlaceholders() bool
TemplateMetrics() bool
diff --git a/config/env.go b/config/env.go
index 1e9266b17..0ad5ecaea 100644
--- a/config/env.go
+++ b/config/env.go
@@ -18,6 +18,12 @@ import (
"runtime"
"strconv"
"strings"
+
+ "github.com/pbnjay/memory"
+)
+
+const (
+ gigabyte = 1 << 30
)
// GetNumWorkerMultiplier returns the base value used to calculate the number
@@ -33,6 +39,37 @@ func GetNumWorkerMultiplier() int {
return runtime.NumCPU()
}
+// GetMemoryLimit returns the upper memory limit in bytes for Hugo's in-memory caches.
+// Note that this does not represent "all of the memory" that Hugo will use,
+// so it needs to be set to a lower number than the available system memory.
+// It will read from the HUGO_MEMORYLIMIT (in Gigabytes) environment variable.
+// If that is not set, it will set aside a quarter of the total system memory.
+func GetMemoryLimit() uint64 {
+ if mem := os.Getenv("HUGO_MEMORYLIMIT"); mem != "" {
+ if v := stringToGibabyte(mem); v > 0 {
+ return v
+ }
+
+ }
+
+ // There is a FreeMemory function, but as the kernel in most situations
+ // will take whatever memory that is left and use for caching etc.,
+ // that value is not something that we can use.
+ m := memory.TotalMemory()
+ if m != 0 {
+ return uint64(m / 4)
+ }
+
+ return 2 * gigabyte
+}
+
+func stringToGibabyte(f string) uint64 {
+ if v, err := strconv.ParseFloat(f, 32); err == nil && v > 0 {
+ return uint64(v * gigabyte)
+ }
+ return 0
+}
+
// SetEnvVars sets vars on the form key=value in the oldVars slice.
func SetEnvVars(oldVars *[]string, keyValues ...string) {
for i := 0; i < len(keyValues); i += 2 {
diff --git a/config/namespace.go b/config/namespace.go
index 3ecd01014..b518c6c01 100644
--- a/config/namespace.go
+++ b/config/namespace.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -20,7 +20,6 @@ import (
)
func DecodeNamespace[S, C any](configSource any, buildConfig func(any) (C, any, error)) (*ConfigNamespace[S, C], error) {
-
// Calculate the hash of the input (not including any defaults applied later).
// This allows us to introduce new config options without breaking the hash.
h := identity.HashString(configSource)
diff --git a/config/namespace_test.go b/config/namespace_test.go
index 008237c13..9bd23e08e 100644
--- a/config/namespace_test.go
+++ b/config/namespace_test.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -26,7 +26,7 @@ func TestNamespace(t *testing.T) {
c := qt.New(t)
c.Assert(true, qt.Equals, true)
- //ns, err := config.DecodeNamespace[map[string]DocsMediaTypeConfig](in, defaultMediaTypesConfig, buildConfig)
+ // ns, err := config.DecodeNamespace[map[string]DocsMediaTypeConfig](in, defaultMediaTypesConfig, buildConfig)
ns, err := DecodeNamespace[[]*tstNsExt](
map[string]interface{}{"foo": "bar"},
@@ -46,23 +46,15 @@ func TestNamespace(t *testing.T) {
c.Assert(ns.SourceHash, qt.Equals, "14368731254619220105")
c.Assert(ns.Config, qt.DeepEquals, &tstNsExt{Foo: "bar"})
c.Assert(ns.Signature(), qt.DeepEquals, []*tstNsExt(nil))
-
}
type (
tstNsExt struct {
Foo string
}
- tstNsInt struct {
- Foo string
- }
)
func (t *tstNsExt) Init() error {
t.Foo = strings.ToUpper(t.Foo)
return nil
}
-func (t *tstNsInt) Compile(ext *tstNsExt) error {
- t.Foo = ext.Foo + " qux"
- return nil
-}
diff --git a/config/testconfig/testconfig.go b/config/testconfig/testconfig.go
index 4aafd69f0..8f70e6cb7 100644
--- a/config/testconfig/testconfig.go
+++ b/config/testconfig/testconfig.go
@@ -1,4 +1,4 @@
-// Copyright 2023 The Hugo Authors. All rights reserved.
+// Copyright 2024 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.
@@ -36,7 +36,7 @@ func GetTestConfigs(fs afero.Fs, cfg config.Provider) *allconfig.Configs {
// Make sure that the workingDir exists.
workingDir := cfg.GetString("workingDir")
if workingDir != "" {
- if err := fs.MkdirAll(workingDir, 0777); err != nil {
+ if err := fs.MkdirAll(workingDir, 0o777); err != nil {
panic(err)
}
}
@@ -46,7 +46,6 @@ func GetTestConfigs(fs afero.Fs, cfg config.Provider) *allconfig.Configs {
panic(err)
}
return configs
-
}
func GetTestConfig(fs afero.Fs, cfg config.Provider) config.AllProvider {