From 05542130ba0205d3d8d14575b7e49ed42a855b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Wed, 17 May 2023 13:12:49 +0200 Subject: [PATCH] Handle transient errors in config loading etc. As in: Get the Kubernetes site to build with the new Hugo version. Updates #10947 --- config/allconfig/allconfig.go | 20 +++++++++++++++++- config/allconfig/load.go | 8 +++++++- hugolib/config_test.go | 38 ++++++++++++++++++++++++++++++++++- hugolib/site.go | 4 ++++ hugolib/site_new.go | 2 +- langs/language.go | 7 ++++++- resources/page/site.go | 22 ++++++++++++++++++++ 7 files changed, 96 insertions(+), 5 deletions(-) diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go index 4daae3ccb13..6731b9003f6 100644 --- 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 diff --git a/config/allconfig/load.go b/config/allconfig/load.go index 9f27e867e41..2d1a84423ac 100644 --- 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 diff --git a/hugolib/config_test.go b/hugolib/config_test.go index 93060134d36..e27068da699 100644 --- 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 }} diff --git a/hugolib/site.go b/hugolib/site.go index b055cf690cc..301d66daca4 100644 --- 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") diff --git a/hugolib/site_new.go b/hugolib/site_new.go index 2b959a8da2e..b0b34e45782 100644 --- 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) } diff --git a/langs/language.go b/langs/language.go index 5bf80274d03..232331cae88 100644 --- 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 diff --git a/resources/page/site.go b/resources/page/site.go index d36857bb1b5..899042391ad 100644 --- 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{