From bb549a0d57505a6b8f28930bb91a9ab44cbb3288 Mon Sep 17 00:00:00 2001 From: Vas Sudanagunta Date: Sun, 11 Feb 2018 18:34:03 -0500 Subject: Account for array type data in data dir merge/override logic * Fixes #4366 * Error message to console for unsupported data types --- hugolib/datafiles_test.go | 27 +++++++++++++++++++---- hugolib/site.go | 56 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 19 deletions(-) (limited to 'hugolib') diff --git a/hugolib/datafiles_test.go b/hugolib/datafiles_test.go index a11929542..de124a77d 100644 --- a/hugolib/datafiles_test.go +++ b/hugolib/datafiles_test.go @@ -261,8 +261,7 @@ func TestDataDirMultipleSourcesCommingled(t *testing.T) { doTestDataDir(t, dd, expected, "theme", "mytheme") } -// TODO Issue #4366 unresolved -func _TestDataDirMultipleSourcesCollidingChildArrays(t *testing.T) { +func TestDataDirCollidingChildArrays(t *testing.T) { t.Parallel() var dd dataDir @@ -284,8 +283,7 @@ func _TestDataDirMultipleSourcesCollidingChildArrays(t *testing.T) { doTestDataDir(t, dd, expected, "theme", "mytheme") } -// TODO Issue #4366 unresolved -func _TestDataDirMultipleSourcesCollidingTopLevelArrays(t *testing.T) { +func TestDataDirCollidingTopLevelArrays(t *testing.T) { t.Parallel() var dd dataDir @@ -302,6 +300,27 @@ func _TestDataDirMultipleSourcesCollidingTopLevelArrays(t *testing.T) { doTestDataDir(t, dd, expected, "theme", "mytheme") } +func TestDataDirCollidingMapsAndArrays(t *testing.T) { + t.Parallel() + + var dd dataDir + // on + dd.addSource("themes/mytheme/data/a.json", `["1", "2", "3"]`) + dd.addSource("themes/mytheme/data/b.json", `{ "film" : "Logan Lucky" }`) + dd.addSource("data/a.json", `{ "music" : "Queen's Rebuke" }`) + dd.addSource("data/b.json", `["x", "y", "z"]`) + + expected := + map[string]interface{}{ + "a": map[string]interface{}{ + "music": "Queen's Rebuke", + }, + "b": []interface{}{"x", "y", "z"}, + } + + doTestDataDir(t, dd, expected, "theme", "mytheme") +} + type dataDir struct { sources [][2]string } diff --git a/hugolib/site.go b/hugolib/site.go index 044866cca..d62662814 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -812,24 +812,50 @@ func (s *Site) handleDataFile(r source.ReadableFile) error { return nil } - // Copy content from current to data when needed - if _, ok := current[r.BaseFileName()]; ok { - data := data.(map[string]interface{}) - - for key, value := range current[r.BaseFileName()].(map[string]interface{}) { - if _, override := data[key]; override { - // filepath.Walk walks the files in lexical order, '/' comes before '.' - // this warning could happen if - // 1. A theme uses the same key; the main data folder wins - // 2. A sub folder uses the same key: the sub folder wins - s.Log.WARN.Printf("Data for key '%s' in path '%s' is overridden in subfolder", key, r.Path()) + // filepath.Walk walks the files in lexical order, '/' comes before '.' + // this warning could happen if + // 1. A theme uses the same key; the main data folder wins + // 2. A sub folder uses the same key: the sub folder wins + higherPrecedentData := current[r.BaseFileName()] + + switch data.(type) { + case nil: + // hear the crickets? + + case map[string]interface{}: + + switch higherPrecedentData.(type) { + case nil: + current[r.BaseFileName()] = data + case map[string]interface{}: + // merge maps: insert entries from data for keys that + // don't already exist in higherPrecedentData + higherPrecedentMap := higherPrecedentData.(map[string]interface{}) + for key, value := range data.(map[string]interface{}) { + if _, exists := higherPrecedentMap[key]; exists { + s.Log.WARN.Printf("Data for key '%s' in path '%s' is overridden higher precedence data already in the data tree", key, r.Path()) + } else { + higherPrecedentMap[key] = value + } } - data[key] = value + default: + // can't merge: higherPrecedentData is not a map + s.Log.WARN.Printf("The %T data from '%s' overridden by "+ + "higher precedence %T data already in the data tree", data, r.Path(), higherPrecedentData) } - } - // Insert data - current[r.BaseFileName()] = data + case []interface{}: + if higherPrecedentData == nil { + current[r.BaseFileName()] = data + } else { + // we don't merge array data + s.Log.WARN.Printf("The %T data from '%s' overridden by "+ + "higher precedence %T data already in the data tree", data, r.Path(), higherPrecedentData) + } + + default: + s.Log.ERROR.Printf("unexpected data type %T in file %s", data, r.LogicalName()) + } return nil } -- cgit v1.2.3