mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Allow setting the delimiter used for setting config via OS env, e.g. HUGO_
Fixes #7829
This commit is contained in:
parent
8a6e706053
commit
7e223b3baa
4 changed files with 53 additions and 24 deletions
|
@ -84,7 +84,7 @@ func GetNestedParam(keyStr, separator string, candidates ...Params) (interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interface{}) (interface{}, string, map[string]interface{}, error) {
|
func GetNestedParamFn(keyStr, separator string, lookupFn func(key string) interface{}) (interface{}, string, map[string]interface{}, error) {
|
||||||
keySegments := strings.Split(strings.ToLower(keyStr), separator)
|
keySegments := strings.Split(keyStr, separator)
|
||||||
if len(keySegments) == 0 {
|
if len(keySegments) == 0 {
|
||||||
return nil, "", nil, nil
|
return nil, "", nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,6 +427,8 @@ Names must be prefixed with `HUGO_` and the configuration key must be set in upp
|
||||||
To set config params, prefix the name with `HUGO_PARAMS_`
|
To set config params, prefix the name with `HUGO_PARAMS_`
|
||||||
{{% /note %}}
|
{{% /note %}}
|
||||||
|
|
||||||
|
{{< new-in "0.79.0" >}} If you are using snake_cased variable names, the above will not work, so since Hugo 0.79.0 Hugo determines the delimiter to use by the first character after `HUGO`. This allows you to define environment variables on the form `HUGOxPARAMSxAPI_KEY=abcdefgh`, using any [allowed](https://stackoverflow.com/questions/2821043/allowed-characters-in-linux-environment-variable-names#:~:text=So%20names%20may%20contain%20any,not%20begin%20with%20a%20digit.) delimiter.
|
||||||
|
|
||||||
{{< todo >}}
|
{{< todo >}}
|
||||||
Test and document setting params via JSON env var.
|
Test and document setting params via JSON env var.
|
||||||
{{< /todo >}}
|
{{< /todo >}}
|
||||||
|
|
|
@ -18,6 +18,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/common/types"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
hglob "github.com/gohugoio/hugo/hugofs/glob"
|
hglob "github.com/gohugoio/hugo/hugofs/glob"
|
||||||
|
|
||||||
|
@ -166,45 +168,59 @@ func LoadConfig(d ConfigSourceDescriptor, doWithConfig ...func(cfg config.Provid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const delim = "__env__delim"
|
||||||
|
|
||||||
// Apply environment overrides
|
// Apply environment overrides
|
||||||
if len(d.Environ) > 0 {
|
if len(d.Environ) > 0 {
|
||||||
// Extract all that start with the HUGO_ prefix
|
// Extract all that start with the HUGO prefix.
|
||||||
const hugoEnvPrefix = "HUGO_"
|
// The delimiter is the following rune, usually "_".
|
||||||
var hugoEnv []string
|
const hugoEnvPrefix = "HUGO"
|
||||||
|
var hugoEnv []types.KeyValueStr
|
||||||
for _, v := range d.Environ {
|
for _, v := range d.Environ {
|
||||||
key, val := config.SplitEnvVar(v)
|
key, val := config.SplitEnvVar(v)
|
||||||
if strings.HasPrefix(key, hugoEnvPrefix) {
|
if strings.HasPrefix(key, hugoEnvPrefix) {
|
||||||
hugoEnv = append(hugoEnv, strings.ToLower(strings.TrimPrefix(key, hugoEnvPrefix)), val)
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hugoEnv) > 0 {
|
for _, env := range hugoEnv {
|
||||||
for i := 0; i < len(hugoEnv); i += 2 {
|
existing, nestedKey, owner, err := maps.GetNestedParamFn(env.Key, delim, v.Get)
|
||||||
key, valStr := strings.ToLower(hugoEnv[i]), hugoEnv[i+1]
|
if err != nil {
|
||||||
|
return v, configFiles, err
|
||||||
|
}
|
||||||
|
|
||||||
existing, nestedKey, owner, err := maps.GetNestedParamFn(key, "_", v.Get)
|
if existing != nil {
|
||||||
|
val, err := metadecoders.Default.UnmarshalStringTo(env.Value, existing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return v, configFiles, err
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if existing != nil {
|
if owner != nil {
|
||||||
val, err := metadecoders.Default.UnmarshalStringTo(valStr, existing)
|
owner[nestedKey] = val
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if owner != nil {
|
|
||||||
owner[nestedKey] = val
|
|
||||||
} else {
|
|
||||||
v.Set(key, val)
|
|
||||||
}
|
|
||||||
} else if nestedKey != "" {
|
|
||||||
owner[nestedKey] = valStr
|
|
||||||
} else {
|
} else {
|
||||||
v.Set(key, valStr)
|
v.Set(env.Key, val)
|
||||||
}
|
}
|
||||||
|
} else if nestedKey != "" {
|
||||||
|
owner[nestedKey] = env.Value
|
||||||
|
} else {
|
||||||
|
v.Set(env.Key, env.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We made this a Glob pattern in Hugo 0.75, we don't need both.
|
// We made this a Glob pattern in Hugo 0.75, we don't need both.
|
||||||
|
|
|
@ -492,6 +492,11 @@ intSlice = [5,7,9]
|
||||||
floatSlice = [3.14, 5.19]
|
floatSlice = [3.14, 5.19]
|
||||||
stringSlice = ["a", "b"]
|
stringSlice = ["a", "b"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
[params.api_config]
|
||||||
|
api_key="default_key"
|
||||||
|
another_key="default another_key"
|
||||||
|
|
||||||
[imaging]
|
[imaging]
|
||||||
anchor = "smart"
|
anchor = "smart"
|
||||||
quality = 75
|
quality = 75
|
||||||
|
@ -508,6 +513,10 @@ quality = 75
|
||||||
"HUGO_STRINGSLICE", `["c", "d"]`,
|
"HUGO_STRINGSLICE", `["c", "d"]`,
|
||||||
"HUGO_INTSLICE", `[5, 8, 9]`,
|
"HUGO_INTSLICE", `[5, 8, 9]`,
|
||||||
"HUGO_FLOATSLICE", `[5.32]`,
|
"HUGO_FLOATSLICE", `[5.32]`,
|
||||||
|
// https://github.com/gohugoio/hugo/issues/7829
|
||||||
|
"HUGOxPARAMSxAPI_CONFIGxAPI_KEY", "new_key",
|
||||||
|
// Delimiters are case sensitive.
|
||||||
|
"HUGOxPARAMSxAPI_CONFIGXANOTHER_KEY", "another_key",
|
||||||
)
|
)
|
||||||
|
|
||||||
b.Build(BuildCfg{})
|
b.Build(BuildCfg{})
|
||||||
|
@ -523,5 +532,7 @@ quality = 75
|
||||||
c.Assert(cfg.Get("stringSlice"), qt.DeepEquals, []interface{}{"c", "d"})
|
c.Assert(cfg.Get("stringSlice"), qt.DeepEquals, []interface{}{"c", "d"})
|
||||||
c.Assert(cfg.Get("floatSlice"), qt.DeepEquals, []interface{}{5.32})
|
c.Assert(cfg.Get("floatSlice"), qt.DeepEquals, []interface{}{5.32})
|
||||||
c.Assert(cfg.Get("intSlice"), qt.DeepEquals, []interface{}{5, 8, 9})
|
c.Assert(cfg.Get("intSlice"), qt.DeepEquals, []interface{}{5, 8, 9})
|
||||||
|
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")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue