From 40b1b8f70373dacf2458fbd9a67be32fc6830f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sun, 16 Oct 2016 19:28:21 +0200 Subject: [PATCH] Fix case issue Viper vs Blackfriday config There are still work to be done in the case department, but that will have to be another day. Fixes #2581 See https://github.com/spf13/viper/issues/261 --- helpers/content.go | 23 +++++++++++------- helpers/general.go | 23 ++++++++++++++++++ helpers/general_test.go | 53 +++++++++++++++++++++++++++++++++++++++++ hugolib/multilingual.go | 5 ++-- hugolib/page.go | 2 ++ hugolib/site_test.go | 6 +++-- vendor/vendor.json | 6 ++--- 7 files changed, 102 insertions(+), 16 deletions(-) diff --git a/helpers/content.go b/helpers/content.go index 516fc72b9..aa1327d74 100644 --- a/helpers/content.go +++ b/helpers/content.go @@ -27,7 +27,6 @@ import ( "github.com/miekg/mmark" "github.com/mitchellh/mapstructure" "github.com/russross/blackfriday" - "github.com/spf13/cast" bp "github.com/spf13/hugo/bufferpool" jww "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" @@ -60,7 +59,8 @@ type Blackfriday struct { // NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults. func NewBlackfriday(c ConfigProvider) *Blackfriday { - combinedParam := map[string]interface{}{ + + defaultParam := map[string]interface{}{ "smartypants": true, "angledQuotes": false, "fractions": true, @@ -73,17 +73,24 @@ func NewBlackfriday(c ConfigProvider) *Blackfriday { "sourceRelativeLinksProjectFolder": "/docs/content", } - siteParam := c.GetStringMap("blackfriday") - if siteParam != nil { - siteConfig := cast.ToStringMap(siteParam) + ToLowerMap(defaultParam) - for key, value := range siteConfig { - combinedParam[key] = value + siteParam := c.GetStringMap("blackfriday") + + siteConfig := make(map[string]interface{}) + + for k, v := range defaultParam { + siteConfig[k] = v + } + + if siteParam != nil { + for k, v := range siteParam { + siteConfig[k] = v } } combinedConfig := &Blackfriday{} - if err := mapstructure.Decode(combinedParam, combinedConfig); err != nil { + if err := mapstructure.Decode(siteConfig, combinedConfig); err != nil { jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error()) } diff --git a/helpers/general.go b/helpers/general.go index b420bfa2c..ba828ed8c 100644 --- a/helpers/general.go +++ b/helpers/general.go @@ -119,6 +119,29 @@ func ReaderToBytes(lines io.Reader) []byte { return bc } +// ToLowerMap makes all the keys in the given map lower cased and will do so +// recursively. +// Notes: +// * This will modify the map given. +// * Any nested map[interface{}]interface{} will be converted to map[string]interface{}. +func ToLowerMap(m map[string]interface{}) { + for k, v := range m { + switch v.(type) { + case map[interface{}]interface{}: + v = cast.ToStringMap(v) + ToLowerMap(v.(map[string]interface{})) + case map[string]interface{}: + ToLowerMap(v.(map[string]interface{})) + } + + lKey := strings.ToLower(k) + if k != lKey { + delete(m, k) + } + m[lKey] = v + } +} + // ReaderToString is the same as ReaderToBytes, but returns a string. func ReaderToString(lines io.Reader) string { if lines == nil { diff --git a/helpers/general_test.go b/helpers/general_test.go index 089bb9b1a..8afdb59eb 100644 --- a/helpers/general_test.go +++ b/helpers/general_test.go @@ -291,3 +291,56 @@ func TestDoArithmetic(t *testing.T) { } } } + +func TestToLowerMap(t *testing.T) { + + tests := []struct { + input map[string]interface{} + expected map[string]interface{} + }{ + { + map[string]interface{}{ + "abC": 32, + }, + map[string]interface{}{ + "abc": 32, + }, + }, + { + map[string]interface{}{ + "abC": 32, + "deF": map[interface{}]interface{}{ + 23: "A value", + 24: map[string]interface{}{ + "AbCDe": "A value", + "eFgHi": "Another value", + }, + }, + "gHi": map[string]interface{}{ + "J": 25, + }, + }, + map[string]interface{}{ + "abc": 32, + "def": map[string]interface{}{ + "23": "A value", + "24": map[string]interface{}{ + "abcde": "A value", + "efghi": "Another value", + }, + }, + "ghi": map[string]interface{}{ + "j": 25, + }, + }, + }, + } + + for i, test := range tests { + // ToLowerMap modifies input. + ToLowerMap(test.input) + if !reflect.DeepEqual(test.expected, test.input) { + t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input) + } + } +} diff --git a/hugolib/multilingual.go b/hugolib/multilingual.go index 2b0214e10..cf45e7233 100644 --- a/hugolib/multilingual.go +++ b/hugolib/multilingual.go @@ -17,7 +17,6 @@ import ( "sync" "sort" - "strings" "errors" "fmt" @@ -84,6 +83,7 @@ func toSortedLanguages(l map[string]interface{}) (helpers.Languages, error) { for lang, langConf := range l { langsMap, err := cast.ToStringMapE(langConf) + helpers.ToLowerMap(langsMap) if err != nil { return nil, fmt.Errorf("Language config is not a map: %T", langConf) @@ -91,8 +91,7 @@ func toSortedLanguages(l map[string]interface{}) (helpers.Languages, error) { language := helpers.NewLanguage(lang) - for k, v := range langsMap { - loki := strings.ToLower(k) + for loki, v := range langsMap { switch loki { case "title": language.Title = cast.ToString(v) diff --git a/hugolib/page.go b/hugolib/page.go index d2205e32f..99ef6e413 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -392,9 +392,11 @@ func (p *Page) getRenderingConfig() *helpers.Blackfriday { panic(fmt.Sprintf("nil language for %s with source lang %s", p.BaseFileName(), p.lang)) } p.renderingConfig = helpers.NewBlackfriday(p.Language()) + if err := mapstructure.Decode(pageParam, p.renderingConfig); err != nil { jww.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error()) } + }) return p.renderingConfig diff --git a/hugolib/site_test.go b/hugolib/site_test.go index b278456fc..9cf094e19 100644 --- a/hugolib/site_test.go +++ b/hugolib/site_test.go @@ -337,8 +337,9 @@ func doTestShouldAlwaysHaveUglyURLs(t *testing.T, uglyURLs bool) { viper.Set("DisableRSS", false) viper.Set("RSSUri", "index.xml") viper.Set("blackfriday", + // TODO(bep) https://github.com/spf13/viper/issues/261 map[string]interface{}{ - "plainIDAnchors": true}) + strings.ToLower("plainIDAnchors"): true}) viper.Set("UglyURLs", uglyURLs) @@ -964,8 +965,9 @@ func setupLinkingMockSite(t *testing.T) *Site { viper.Set("PluralizeListTitles", false) viper.Set("CanonifyURLs", false) viper.Set("blackfriday", + // TODO(bep) see https://github.com/spf13/viper/issues/261 map[string]interface{}{ - "sourceRelativeLinksProjectFolder": "/docs"}) + strings.ToLower("sourceRelativeLinksProjectFolder"): "/docs"}) site := &Site{ Source: &source.InMemorySource{ByteSource: sources}, diff --git a/vendor/vendor.json b/vendor/vendor.json index 04ff19b06..c4208e0e0 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -299,10 +299,10 @@ "revisionTime": "2016-10-06T16:53:40Z" }, { - "checksumSHA1": "+RJudGkFugn3gRJYUIan1Wbugdw=", + "checksumSHA1": "2EeKIC5kUssQK8g49DOa78FoMgs=", "path": "github.com/spf13/viper", - "revision": "51f23d1f1c56a7773ae8f2cfd038f7996ecc9ac2", - "revisionTime": "2016-10-10T11:40:38Z" + "revision": "50515b700e02658272117a72bd641b6b7f1222e5", + "revisionTime": "2016-10-14T09:24:45Z" }, { "checksumSHA1": "Q2V7Zs3diLmLfmfbiuLpSxETSuY=",