diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2023-01-04 18:24:36 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2023-05-16 18:01:29 +0200 |
commit | 241b21b0fd34d91fccb2ce69874110dceae6f926 (patch) | |
tree | d4e0118eac7e9c42f065815447a70805f8d6ad3e /hugolib | |
parent | 6aededf6b42011c3039f5f66487a89a8dd65e0e7 (diff) |
Create a struct with all of Hugo's config options
Primary motivation is documentation, but it will also hopefully simplify the code.
Also,
* Lower case the default output format names; this is in line with the custom ones (map keys) and how
it's treated all the places. This avoids doing `stringds.EqualFold` everywhere.
Closes #10896
Closes #10620
Diffstat (limited to 'hugolib')
63 files changed, 1913 insertions, 4140 deletions
diff --git a/hugolib/alias.go b/hugolib/alias.go index 071f73d41..1bc0e5424 100644 --- a/hugolib/alias.go +++ b/hugolib/alias.go @@ -101,7 +101,7 @@ func (s *Site) publishDestAlias(allowRoot bool, path, permalink string, outputFo OutputFormat: outputFormat, } - if s.Info.relativeURLs || s.Info.canonifyURLs { + if s.conf.RelativeURLs || s.conf.CanonifyURLs { pd.AbsURLPath = s.absURLPath(targetPath) } diff --git a/hugolib/breaking_changes_test.go b/hugolib/breaking_changes_test.go index 495baff3e..533205deb 100644 --- a/hugolib/breaking_changes_test.go +++ b/hugolib/breaking_changes_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 The Hugo Authors. All rights reserved. +// Copyright 2023 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. @@ -12,119 +12,3 @@ // limitations under the License. package hugolib - -import ( - "fmt" - "testing" - - qt "github.com/frankban/quicktest" -) - -func Test073(t *testing.T) { - assertDisabledTaxonomyAndTerm := func(b *sitesBuilder, taxonomy, term bool) { - b.Assert(b.CheckExists("public/tags/index.html"), qt.Equals, taxonomy) - b.Assert(b.CheckExists("public/tags/tag1/index.html"), qt.Equals, term) - } - - assertOutputTaxonomyAndTerm := func(b *sitesBuilder, taxonomy, term bool) { - b.Assert(b.CheckExists("public/tags/index.json"), qt.Equals, taxonomy) - b.Assert(b.CheckExists("public/tags/tag1/index.json"), qt.Equals, term) - } - - for _, this := range []struct { - name string - config string - assert func(err error, out string, b *sitesBuilder) - }{ - { - "Outputs for both taxonomy and taxonomyTerm", - `[outputs] - taxonomy = ["JSON"] - taxonomyTerm = ["JSON"] - -`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.IsNil) - assertOutputTaxonomyAndTerm(b, true, true) - }, - }, - { - "Outputs for taxonomyTerm", - `[outputs] -taxonomyTerm = ["JSON"] - -`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.IsNil) - assertOutputTaxonomyAndTerm(b, true, false) - }, - }, - { - "Outputs for taxonomy only", - `[outputs] -taxonomy = ["JSON"] - -`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.Not(qt.IsNil)) - b.Assert(out, qt.Contains, `ignoreErrors = ["error-output-taxonomy"]`) - }, - }, - { - "Outputs for taxonomy only, ignore error", - ` -ignoreErrors = ["error-output-taxonomy"] -[outputs] -taxonomy = ["JSON"] - -`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.IsNil) - assertOutputTaxonomyAndTerm(b, true, false) - }, - }, - { - "Disable both taxonomy and taxonomyTerm", - `disableKinds = ["taxonomy", "taxonomyTerm"]`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.IsNil) - assertDisabledTaxonomyAndTerm(b, false, false) - }, - }, - { - "Disable only taxonomyTerm", - `disableKinds = ["taxonomyTerm"]`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.IsNil) - assertDisabledTaxonomyAndTerm(b, false, true) - }, - }, - { - "Disable only taxonomy", - `disableKinds = ["taxonomy"]`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.Not(qt.IsNil)) - b.Assert(out, qt.Contains, `ignoreErrors = ["error-disable-taxonomy"]`) - }, - }, - { - "Disable only taxonomy, ignore error", - `disableKinds = ["taxonomy"] - ignoreErrors = ["error-disable-taxonomy"]`, - func(err error, out string, b *sitesBuilder) { - b.Assert(err, qt.IsNil) - assertDisabledTaxonomyAndTerm(b, false, true) - }, - }, - } { - t.Run(this.name, func(t *testing.T) { - b := newTestSitesBuilder(t).WithConfigFile("toml", this.config) - b.WithTemplatesAdded("_default/list.json", "JSON") - out, err := captureStdout(func() error { - return b.BuildE(BuildCfg{}) - }) - fmt.Println(out) - this.assert(err, out, b) - }) - } -} diff --git a/hugolib/cascade_test.go b/hugolib/cascade_test.go index dff2082b6..0f607ecb5 100644 --- a/hugolib/cascade_test.go +++ b/hugolib/cascade_test.go @@ -159,33 +159,33 @@ func TestCascade(t *testing.T) { b.Build(BuildCfg{}) b.AssertFileContent("public/index.html", ` -12|term|categories/cool/_index.md|Cascade Category|cat.png|categories|HTML-| -12|term|categories/catsect1|catsect1|cat.png|categories|HTML-| -12|term|categories/funny|funny|cat.png|categories|HTML-| -12|taxonomy|categories/_index.md|My Categories|cat.png|categories|HTML-| -32|term|categories/sad/_index.md|Cascade Category|sad.png|categories|HTML-| -42|term|tags/blue|blue|home.png|tags|HTML-| -42|taxonomy|tags|Cascade Home|home.png|tags|HTML-| -42|section|sectnocontent|Cascade Home|home.png|sectnocontent|HTML-| -42|section|sect3|Cascade Home|home.png|sect3|HTML-| -42|page|bundle1/index.md|Cascade Home|home.png|page|HTML-| -42|page|p2.md|Cascade Home|home.png|page|HTML-| -42|page|sect2/p2.md|Cascade Home|home.png|sect2|HTML-| -42|page|sect3/nofrontmatter.md|Cascade Home|home.png|sect3|HTML-| -42|page|sect3/p1.md|Cascade Home|home.png|sect3|HTML-| -42|page|sectnocontent/p1.md|Cascade Home|home.png|sectnocontent|HTML-| -42|section|sectnofrontmatter/_index.md|Cascade Home|home.png|sectnofrontmatter|HTML-| -42|term|tags/green|green|home.png|tags|HTML-| -42|home|_index.md|Home|home.png|page|HTML-| -42|page|p1.md|p1|home.png|page|HTML-| -42|section|sect1/_index.md|Sect1|sect1.png|stype|HTML-| -42|section|sect1/s1_2/_index.md|Sect1_2|sect1.png|stype|HTML-| -42|page|sect1/s1_2/p1.md|Sect1_2_p1|sect1.png|stype|HTML-| -42|page|sect1/s1_2/p2.md|Sect1_2_p2|sect1.png|stype|HTML-| -42|section|sect2/_index.md|Sect2|home.png|sect2|HTML-| -42|page|sect2/p1.md|Sect2_p1|home.png|sect2|HTML-| -52|page|sect4/p1.md|Cascade Home|home.png|sect4|RSS-| -52|section|sect4/_index.md|Sect4|home.png|sect4|RSS-| +12|term|categories/cool/_index.md|Cascade Category|cat.png|categories|html-| +12|term|categories/catsect1|catsect1|cat.png|categories|html-| +12|term|categories/funny|funny|cat.png|categories|html-| +12|taxonomy|categories/_index.md|My Categories|cat.png|categories|html-| +32|term|categories/sad/_index.md|Cascade Category|sad.png|categories|html-| +42|term|tags/blue|blue|home.png|tags|html-| +42|taxonomy|tags|Cascade Home|home.png|tags|html-| +42|section|sectnocontent|Cascade Home|home.png|sectnocontent|html-| +42|section|sect3|Cascade Home|home.png|sect3|html-| +42|page|bundle1/index.md|Cascade Home|home.png|page|html-| +42|page|p2.md|Cascade Home|home.png|page|html-| +42|page|sect2/p2.md|Cascade Home|home.png|sect2|html-| +42|page|sect3/nofrontmatter.md|Cascade Home|home.png|sect3|html-| +42|page|sect3/p1.md|Cascade Home|home.png|sect3|html-| +42|page|sectnocontent/p1.md|Cascade Home|home.png|sectnocontent|html-| +42|section|sectnofrontmatter/_index.md|Cascade Home|home.png|sectnofrontmatter|html-| +42|term|tags/green|green|home.png|tags|html-| +42|home|_index.md|Home|home.png|page|html-| +42|page|p1.md|p1|home.png|page|html-| +42|section|sect1/_index.md|Sect1|sect1.png|stype|html-| +42|section|sect1/s1_2/_index.md|Sect1_2|sect1.png|stype|html-| +42|page|sect1/s1_2/p1.md|Sect1_2_p1|sect1.png|stype|html-| +42|page|sect1/s1_2/p2.md|Sect1_2_p2|sect1.png|stype|html-| +42|section|sect2/_index.md|Sect2|home.png|sect2|html-| +42|page|sect2/p1.md|Sect2_p1|home.png|sect2|html-| +52|page|sect4/p1.md|Cascade Home|home.png|sect4|rss-| +52|section|sect4/_index.md|Sect4|home.png|sect4|rss-| `) // Check that type set in cascade gets the correct layout. diff --git a/hugolib/codeowners.go b/hugolib/codeowners.go index 162ee16ae..c1a6a2b7b 100644 --- a/hugolib/codeowners.go +++ b/hugolib/codeowners.go @@ -18,7 +18,6 @@ import ( "path" "github.com/gohugoio/hugo/common/herrors" - "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/resources/page" "github.com/hairyhenderson/go-codeowners" "github.com/spf13/afero" @@ -52,9 +51,7 @@ func (c *codeownerInfo) forPage(p page.Page) []string { return c.owners.Owners(p.File().Filename()) } -func newCodeOwners(cfg config.Provider) (*codeownerInfo, error) { - workingDir := cfg.GetString("workingDir") - +func newCodeOwners(workingDir string) (*codeownerInfo, error) { r, err := findCodeOwnersFile(workingDir) if err != nil || r == nil { return nil, err diff --git a/hugolib/config.go b/hugolib/config.go index 059424e85..af3f0647f 100644 --- a/hugolib/config.go +++ b/hugolib/config.go @@ -16,526 +16,170 @@ package hugolib import ( "os" "path/filepath" - "strings" - - "github.com/gohugoio/hugo/common/hexec" - "github.com/gohugoio/hugo/common/types" - - "github.com/gohugoio/hugo/common/maps" - cpaths "github.com/gohugoio/hugo/common/paths" - - "github.com/gobwas/glob" - hglob "github.com/gohugoio/hugo/hugofs/glob" - - "github.com/gohugoio/hugo/common/loggers" - - "github.com/gohugoio/hugo/cache/filecache" - - "github.com/gohugoio/hugo/parser/metadecoders" - - "errors" - - "github.com/gohugoio/hugo/common/herrors" - "github.com/gohugoio/hugo/common/hugo" - "github.com/gohugoio/hugo/langs" - "github.com/gohugoio/hugo/modules" "github.com/gohugoio/hugo/config" - "github.com/gohugoio/hugo/config/privacy" - "github.com/gohugoio/hugo/config/security" - "github.com/gohugoio/hugo/config/services" - "github.com/gohugoio/hugo/helpers" + "github.com/gohugoio/hugo/config/allconfig" "github.com/spf13/afero" ) -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") - -// 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) { - if d.Environment == "" { - d.Environment = hugo.EnvironmentProduction - } - - if len(d.Environ) == 0 && !hugo.IsRunningAsTest() { - d.Environ = os.Environ() - } - - var configFiles []string - - l := configLoader{ConfigSourceDescriptor: d, cfg: config.New()} - // Make sure we always do this, even in error situations, - // as we have commands (e.g. "hugo mod init") that will - // use a partial configuration to do its job. - defer l.deleteMergeStrategies() - - names := d.configFilenames() - - if names != nil { - for _, name := range names { - var filename string - filename, err := l.loadConfig(name) - if err == nil { - configFiles = append(configFiles, filename) - } else if err != ErrNoConfigFile { - return nil, nil, l.wrapFileError(err, filename) - } - } - } else { - for _, name := range config.DefaultConfigNames { - var filename string - filename, err := l.loadConfig(name) - if err == nil { - configFiles = append(configFiles, filename) - break - } else if err != ErrNoConfigFile { - return nil, nil, l.wrapFileError(err, filename) - } - } - } - - if d.AbsConfigDir != "" { - - dcfg, dirnames, err := config.LoadConfigFromDir(l.Fs, d.AbsConfigDir, l.Environment) - - if err == nil { - if len(dirnames) > 0 { - l.cfg.Set("", dcfg.Get("")) - configFiles = append(configFiles, dirnames...) - } - } else if err != ErrNoConfigFile { - if len(dirnames) > 0 { - return nil, nil, l.wrapFileError(err, dirnames[0]) - } - return nil, nil, err - } - } - - if err := l.applyConfigDefaults(); err != nil { - return l.cfg, configFiles, err - } - - 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 - } - } - - // 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() +// DefaultConfig returns the default configuration. +func DefaultConfig() *allconfig.Config { + fs := afero.NewMemMapFs() + all, err := allconfig.LoadConfig(allconfig.ConfigSourceDescriptor{Fs: fs}) 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 accidentally show up in other settings. - l.deleteMergeStrategies() - - 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, modulesCollectErr := l.collectModules(modulesConfig, l.cfg, collectHook) + panic(err) + } + return all.Base +} + +// ExampleConfig returns the some example configuration for documentation. +func ExampleConfig() (*allconfig.Config, error) { + // Apply so |