URI: 
       Handle transient errors in config loading etc. - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 05542130ba0205d3d8d14575b7e49ed42a855b9a
   DIR parent 5251f015bfff40b49f92f8855834d5682f925860
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Wed, 17 May 2023 13:12:49 +0200
       
       Handle transient errors in config loading etc.
       
       As in: Get the Kubernetes site to build with the new Hugo version.
       
       Updates #10947
       
       Diffstat:
         M config/allconfig/allconfig.go       |      20 +++++++++++++++++++-
         M config/allconfig/load.go            |       8 +++++++-
         M hugolib/config_test.go              |      38 ++++++++++++++++++++++++++++++-
         M hugolib/site.go                     |       4 ++++
         M hugolib/site_new.go                 |       2 +-
         M langs/language.go                   |       7 ++++++-
         M resources/page/site.go              |      22 ++++++++++++++++++++++
       
       7 files changed, 96 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go
       @@ -182,6 +182,7 @@ func (c Config) cloneForLang() *Config {
        }
        
        func (c *Config) CompileConfig() error {
       +        var transientErr error
                s := c.Timeout
                if _, err := strconv.Atoi(s); err == nil {
                        // A number, assume seconds.
       @@ -209,7 +210,8 @@ func (c *Config) CompileConfig() error {
                                }
                                f, found := outputFormats.GetByName(format)
                                if !found {
       -                                return fmt.Errorf("unknown output format %q for kind %q", format, kind)
       +                                transientErr = fmt.Errorf("unknown output format %q for kind %q", format, kind)
       +                                continue
                                }
                                kindOutputFormats[kind] = append(kindOutputFormats[kind], f)
                        }
       @@ -288,6 +290,7 @@ func (c *Config) CompileConfig() error {
                        IgnoreFile:        ignoreFile,
                        MainSections:      c.MainSections,
                        Clock:             clock,
       +                transientErr:      transientErr,
                }
        
                for _, s := range allDecoderSetups {
       @@ -323,6 +326,11 @@ type ConfigCompiled struct {
                IgnoreFile        func(filename string) bool
                MainSections      []string
                Clock             time.Time
       +
       +        // This is set to the last transient error found during config compilation.
       +        // With themes/modules we compule the configuration in multiple passes, and
       +        // errors with missing output format definitions may resolve itself.
       +        transientErr error
        }
        
        // This may be set after the config is compiled.
       @@ -565,6 +573,16 @@ type Configs struct {
                configLangs []config.AllProvider
        }
        
       +// transientErr returns the last transient error found during config compilation.
       +func (c *Configs) transientErr() error {
       +        for _, l := range c.LanguageConfigSlice {
       +                if l.C.transientErr != nil {
       +                        return l.C.transientErr
       +                }
       +        }
       +        return nil
       +}
       +
        func (c *Configs) IsZero() bool {
                // A config always has at least one language.
                return c == nil || len(c.Languages) == 0
   DIR diff --git a/config/allconfig/load.go b/config/allconfig/load.go
       @@ -63,13 +63,19 @@ func LoadConfig(d ConfigSourceDescriptor) (*Configs, error) {
                if err != nil {
                        return nil, fmt.Errorf("failed to load modules: %w", err)
                }
       +
                if len(l.ModulesConfigFiles) > 0 {
                        // Config merged in from modules.
                        // Re-read the config.
                        configs, err = FromLoadConfigResult(d.Fs, res)
                        if err != nil {
       -                        return nil, fmt.Errorf("failed to create config: %w", err)
       +                        return nil, fmt.Errorf("failed to create config from modules config: %w", err)
       +                }
       +                if err := configs.transientErr(); err != nil {
       +                        return nil, fmt.Errorf("failed to create config from modules config: %w", err)
                        }
       +        } else if err := configs.transientErr(); err != nil {
       +                return nil, fmt.Errorf("failed to create config: %w", err)
                }
        
                configs.Modules = moduleConfig.ActiveModules
   DIR diff --git a/hugolib/config_test.go b/hugolib/config_test.go
       @@ -742,6 +742,42 @@ themeconfigdirparam: {{ site.Params.themeconfigdirparam }}
        
        }
        
       +func TestConfigOutputFormatDefinedInTheme(t *testing.T) {
       +        t.Parallel()
       +
       +        files := `
       +-- hugo.toml --
       +theme = "mytheme"
       +[outputFormats]
       +[outputFormats.myotherformat]
       +baseName = 'myotherindex'
       +mediaType = 'text/html'
       +[outputs]
       +  home = ['myformat']
       +-- themes/mytheme/hugo.toml --
       +[outputFormats]
       +[outputFormats.myformat]
       +baseName = 'myindex'
       +mediaType = 'text/html'
       +-- layouts/index.html --
       +Home.
       +
       +
       +
       +`
       +
       +        b, err := NewIntegrationTestBuilder(
       +                IntegrationTestConfig{
       +                        T:           t,
       +                        TxtarString: files,
       +                },
       +        ).BuildE()
       +
       +        b.Assert(err, qt.IsNil)
       +        b.AssertFileContent("public/myindex.html", "Home.")
       +
       +}
       +
        func TestReproCommentsIn10947(t *testing.T) {
                t.Parallel()
        
       @@ -768,7 +804,7 @@ title: "My Swedish Section"
        ---
        -- layouts/index.html --
        {{ range $i, $e := (slice site .Site) }}
       -{{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultiLingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|
       +{{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultiLingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }}
        {{ end }}
        
        
   DIR diff --git a/hugolib/site.go b/hugolib/site.go
       @@ -273,6 +273,10 @@ func (s *Site) Language() *langs.Language {
                return s.language
        }
        
       +func (s *Site) Languages() langs.Languages {
       +        return s.h.Configs.Languages
       +}
       +
        func (s *Site) isEnabled(kind string) bool {
                if kind == kindUnknown {
                        panic("Unknown kind")
   DIR diff --git a/hugolib/site_new.go b/hugolib/site_new.go
       @@ -431,7 +431,7 @@ func (s *Site) GoogleAnalytics() string {
                return s.Config().Services.GoogleAnalytics.ID
        }
        
       -func (s *Site) Param(key string) (any, error) {
       +func (s *Site) Param(key any) (any, error) {
                return resource.Param(s, nil, key)
        }
        
   DIR diff --git a/langs/language.go b/langs/language.go
       @@ -87,7 +87,8 @@ var DeprecationFunc = func(item, alternative string, err bool) {}
        
        const paramsDeprecationWarning = `.Language.Params is deprecated and will be removed in a future release. Use site.Params instead.
        
       -Also, for all but custom parameters, you need to use the built in Hugo variables, e.g. site.Title, site.LanguageCode; site.Language.Params.Title will not work.
       +- For all but custom parameters, you need to use the built in Hugo variables, e.g. site.Title, site.LanguageCode; site.Language.Params.Title will not work.
       +- All custom parameters needs to be placed below params, e.g. [languages.en.params] in TOML.
        
        See https://gohugo.io/content-management/multilingual/#changes-in-hugo-01120
        
       @@ -111,6 +112,10 @@ func (l *Language) loadLocation(tzStr string) error {
                return nil
        }
        
       +func (l *Language) String() string {
       +        return l.Lang
       +}
       +
        // Languages is a sortable list of languages.
        type Languages []*Language
        
   DIR diff --git a/resources/page/site.go b/resources/page/site.go
       @@ -35,6 +35,9 @@ type Site interface {
                // Returns the Language configured for this Site.
                Language() *langs.Language
        
       +        // Returns all the languages configured for all sites.
       +        Languages() langs.Languages
       +
                GetPage(ref ...string) (Page, error)
        
                // AllPages returns all pages for all languages.
       @@ -94,6 +97,9 @@ type Site interface {
                // Returns the Params configured for this site.
                Params() maps.Params
        
       +        // Param is a convenience method to do lookups in Params.
       +        Param(key any) (any, error)
       +
                // Returns a map of all the data inside /data.
                Data() map[string]any
        
       @@ -174,6 +180,10 @@ func (s *siteWrapper) Language() *langs.Language {
                return s.s.Language()
        }
        
       +func (s *siteWrapper) Languages() langs.Languages {
       +        return s.s.Languages()
       +}
       +
        func (s *siteWrapper) AllPages() Pages {
                return s.s.AllPages()
        }
       @@ -254,6 +264,10 @@ func (s *siteWrapper) Params() maps.Params {
                return s.s.Params()
        }
        
       +func (s *siteWrapper) Param(key any) (any, error) {
       +        return s.s.Param(key)
       +}
       +
        func (s *siteWrapper) Data() map[string]any {
                return s.s.Data()
        }
       @@ -334,6 +348,10 @@ func (t testSite) Current() Site {
                return t
        }
        
       +func (t testSite) Languages() langs.Languages {
       +        return nil
       +}
       +
        func (t testSite) GoogleAnalytics() string {
                return ""
        }
       @@ -410,6 +428,10 @@ func (s testSite) IsMultiLingual() bool {
                return false
        }
        
       +func (s testSite) Param(key any) (any, error) {
       +        return nil, nil
       +}
       +
        // NewDummyHugoSite creates a new minimal test site.
        func NewDummyHugoSite(cfg config.Provider) Site {
                return testSite{