Allow partial redefinition of the ouputs config
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 10 Mar 2018 10:45:29 +0000 (11:45 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sat, 10 Mar 2018 15:57:25 +0000 (16:57 +0100)
Fixes #4487

hugolib/site_output.go
hugolib/site_output_test.go
output/outputFormat.go

index 5a99692a37157109a2888796b2646d6936cdf14e..497092e8ca4cc3f157ca1ef17535e77384448fc2 100644 (file)
@@ -24,9 +24,46 @@ import (
        "github.com/spf13/cast"
 )
 
+func createDefaultOutputFormats(allFormats output.Formats, cfg config.Provider) map[string]output.Formats {
+       rssOut, _ := allFormats.GetByName(output.RSSFormat.Name)
+       htmlOut, _ := allFormats.GetByName(output.HTMLFormat.Name)
+       robotsOut, _ := allFormats.GetByName(output.RobotsTxtFormat.Name)
+       sitemapOut, _ := allFormats.GetByName(output.SitemapFormat.Name)
+
+       // TODO(bep) this mumbo jumbo is deprecated and should be removed, but there are tests that
+       // depends on this, so that will have to wait.
+       rssBase := cfg.GetString("rssURI")
+       if rssBase == "" || rssBase == "index.xml" {
+               rssBase = rssOut.BaseName
+       } else {
+               // Remove in Hugo 0.36.
+               helpers.Deprecated("Site config", "rssURI", "Set baseName in outputFormats.RSS", true)
+               // RSS has now a well defined media type, so strip any suffix provided
+               rssBase = strings.TrimSuffix(rssBase, path.Ext(rssBase))
+       }
+
+       rssOut.BaseName = rssBase
+
+       return map[string]output.Formats{
+               KindPage:         output.Formats{htmlOut},
+               KindHome:         output.Formats{htmlOut, rssOut},
+               KindSection:      output.Formats{htmlOut, rssOut},
+               KindTaxonomy:     output.Formats{htmlOut, rssOut},
+               KindTaxonomyTerm: output.Formats{htmlOut, rssOut},
+               // Below are for conistency. They are currently not used during rendering.
+               kindRSS:       output.Formats{rssOut},
+               kindSitemap:   output.Formats{sitemapOut},
+               kindRobotsTXT: output.Formats{robotsOut},
+               kind404:       output.Formats{htmlOut},
+       }
+
+}
+
 func createSiteOutputFormats(allFormats output.Formats, cfg config.Provider) (map[string]output.Formats, error) {
+       defaultOutputFormats := createDefaultOutputFormats(allFormats, cfg)
+
        if !cfg.IsSet("outputs") {
-               return createDefaultOutputFormats(allFormats, cfg)
+               return defaultOutputFormats, nil
        }
 
        outFormats := make(map[string]output.Formats)
@@ -37,6 +74,8 @@ func createSiteOutputFormats(allFormats output.Formats, cfg config.Provider) (ma
                return outFormats, nil
        }
 
+       seen := make(map[string]bool)
+
        for k, v := range outputs {
                var formats output.Formats
                vals := cast.ToStringSlice(v)
@@ -48,52 +87,21 @@ func createSiteOutputFormats(allFormats output.Formats, cfg config.Provider) (ma
                        formats = append(formats, f)
                }
 
+               // This effectively prevents empty outputs entries for a given Kind.
+               // We need at least one.
                if len(formats) > 0 {
+                       seen[k] = true
                        outFormats[k] = formats
                }
        }
 
-       // Make sure every kind has at least one output format
-       for _, kind := range allKinds {
-               if _, found := outFormats[kind]; !found {
-                       outFormats[kind] = output.Formats{output.HTMLFormat}
+       // Add defaults for the entries not provided by the user.
+       for k, v := range defaultOutputFormats {
+               if !seen[k] {
+                       outFormats[k] = v
                }
        }
 
        return outFormats, nil
 
 }
-
-func createDefaultOutputFormats(allFormats output.Formats, cfg config.Provider) (map[string]output.Formats, error) {
-       outFormats := make(map[string]output.Formats)
-       rssOut, _ := allFormats.GetByName(output.RSSFormat.Name)
-       htmlOut, _ := allFormats.GetByName(output.HTMLFormat.Name)
-
-       for _, kind := range allKinds {
-               var formats output.Formats
-               // All have HTML
-               formats = append(formats, htmlOut)
-
-               // All but page have RSS
-               if kind != KindPage {
-
-                       rssBase := cfg.GetString("rssURI")
-                       if rssBase == "" || rssBase == "index.xml" {
-                               rssBase = rssOut.BaseName
-                       } else {
-                               // Remove in Hugo 0.36.
-                               helpers.Deprecated("Site config", "rssURI", "Set baseName in outputFormats.RSS", true)
-                               // RSS has now a well defined media type, so strip any suffix provided
-                               rssBase = strings.TrimSuffix(rssBase, path.Ext(rssBase))
-                       }
-
-                       rssOut.BaseName = rssBase
-                       formats = append(formats, rssOut)
-
-               }
-
-               outFormats[kind] = formats
-       }
-
-       return outFormats, nil
-}
index a8a43d62518dd93169c30bd516979e64dac6cea4..7da6f105fe2d4bf53f9ebdda5e95789a4bb53b8f 100644 (file)
@@ -14,7 +14,6 @@
 package hugolib
 
 import (
-       "reflect"
        "strings"
        "testing"
 
@@ -29,54 +28,6 @@ import (
        "github.com/spf13/viper"
 )
 
-func TestDefaultOutputFormats(t *testing.T) {
-       t.Parallel()
-       defs, err := createDefaultOutputFormats(output.DefaultFormats, viper.New())
-
-       require.NoError(t, err)
-
-       tests := []struct {
-               name string
-               kind string
-               want output.Formats
-       }{
-               {"RSS not for regular pages", KindPage, output.Formats{output.HTMLFormat}},
-               {"Home Sweet Home", KindHome, output.Formats{output.HTMLFormat, output.RSSFormat}},
-       }
-
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       if got := defs[tt.kind]; !reflect.DeepEqual(got, tt.want) {
-                               t.Errorf("createDefaultOutputFormats(%v) = %v, want %v", tt.kind, got, tt.want)
-                       }
-               })
-       }
-}
-
-func TestDefaultOutputFormatsWithOverrides(t *testing.T) {
-       t.Parallel()
-
-       htmlOut := output.HTMLFormat
-       htmlOut.BaseName = "htmlindex"
-       rssOut := output.RSSFormat
-       rssOut.BaseName = "feed"
-
-       defs, err := createDefaultOutputFormats(output.Formats{htmlOut, rssOut}, viper.New())
-
-       homeDefs := defs[KindHome]
-
-       rss, found := homeDefs.GetByName("RSS")
-       require.True(t, found)
-       require.Equal(t, rss.BaseName, "feed")
-
-       html, found := homeDefs.GetByName("HTML")
-       require.True(t, found)
-       require.Equal(t, html.BaseName, "htmlindex")
-
-       require.NoError(t, err)
-
-}
-
 func TestSiteWithPageOutputs(t *testing.T) {
        for _, outputs := range [][]string{{"html", "json", "calendar"}, {"json"}} {
                t.Run(fmt.Sprintf("%v", outputs), func(t *testing.T) {
@@ -373,3 +324,83 @@ baseName = "customdelimbase"
        require.Equal(t, "/blog/customdelimbase_del", outputs.Get("CUS").RelPermalink())
 
 }
+
+func TestCreateSiteOutputFormats(t *testing.T) {
+       assert := require.New(t)
+
+       outputsConfig := map[string]interface{}{
+               KindHome:    []string{"HTML", "JSON"},
+               KindSection: []string{"JSON"},
+       }
+
+       cfg := viper.New()
+       cfg.Set("outputs", outputsConfig)
+
+       outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg)
+       assert.NoError(err)
+       assert.Equal(output.Formats{output.JSONFormat}, outputs[KindSection])
+       assert.Equal(output.Formats{output.HTMLFormat, output.JSONFormat}, outputs[KindHome])
+
+       // Defaults
+       assert.Equal(output.Formats{output.HTMLFormat, output.RSSFormat}, outputs[KindTaxonomy])
+       assert.Equal(output.Formats{output.HTMLFormat, output.RSSFormat}, outputs[KindTaxonomyTerm])
+       assert.Equal(output.Formats{output.HTMLFormat}, outputs[KindPage])
+
+       // These aren't (currently) in use when rendering in Hugo,
+       // but the pages needs to be assigned an output format,
+       // so these should also be correct/sensible.
+       assert.Equal(output.Formats{output.RSSFormat}, outputs[kindRSS])
+       assert.Equal(output.Formats{output.SitemapFormat}, outputs[kindSitemap])
+       assert.Equal(output.Formats{output.RobotsTxtFormat}, outputs[kindRobotsTXT])
+       assert.Equal(output.Formats{output.HTMLFormat}, outputs[kind404])
+
+}
+
+func TestCreateSiteOutputFormatsInvalidConfig(t *testing.T) {
+       assert := require.New(t)
+
+       outputsConfig := map[string]interface{}{
+               KindHome: []string{"FOO", "JSON"},
+       }
+
+       cfg := viper.New()
+       cfg.Set("outputs", outputsConfig)
+
+       _, err := createSiteOutputFormats(output.DefaultFormats, cfg)
+       assert.Error(err)
+}
+
+func TestCreateSiteOutputFormatsEmptyConfig(t *testing.T) {
+       assert := require.New(t)
+
+       outputsConfig := map[string]interface{}{
+               KindHome: []string{},
+       }
+
+       cfg := viper.New()
+       cfg.Set("outputs", outputsConfig)
+
+       outputs, err := createSiteOutputFormats(output.DefaultFormats, cfg)
+       assert.NoError(err)
+       assert.Equal(output.Formats{output.HTMLFormat, output.RSSFormat}, outputs[KindHome])
+}
+
+func TestCreateSiteOutputFormatsCustomFormats(t *testing.T) {
+       assert := require.New(t)
+
+       outputsConfig := map[string]interface{}{
+               KindHome: []string{},
+       }
+
+       cfg := viper.New()
+       cfg.Set("outputs", outputsConfig)
+
+       var (
+               customRSS  = output.Format{Name: "RSS", BaseName: "customRSS"}
+               customHTML = output.Format{Name: "HTML", BaseName: "customHTML"}
+       )
+
+       outputs, err := createSiteOutputFormats(output.Formats{customRSS, customHTML}, cfg)
+       assert.NoError(err)
+       assert.Equal(output.Formats{customHTML, customRSS}, outputs[KindHome])
+}
index 0920e573655c35fcd95ad54464bb03cb53c802c9..8778501602050e5e1f1c71b764455636d6458647 100644 (file)
@@ -140,6 +140,14 @@ var (
                NoUgly:    true,
                Rel:       "alternate",
        }
+
+       SitemapFormat = Format{
+               Name:      "Sitemap",
+               MediaType: media.XMLType,
+               BaseName:  "sitemap",
+               NoUgly:    true,
+               Rel:       "sitemap",
+       }
 )
 
 var DefaultFormats = Formats{
@@ -149,7 +157,9 @@ var DefaultFormats = Formats{
        CSVFormat,
        HTMLFormat,
        JSONFormat,
+       RobotsTxtFormat,
        RSSFormat,
+       SitemapFormat,
 }
 
 func init() {