ref: bb549a0d57505a6b8f28930bb91a9ab44cbb3288
parent: 82eefded1353f0198fd8fe9f7df1aa620d3d50eb
author: Vas Sudanagunta <[email protected]>
date: Sun Feb 11 13:34:03 EST 2018
Account for array type data in data dir merge/override logic * Fixes #4366 * Error message to console for unsupported data types
--- a/hugolib/datafiles_test.go
+++ b/hugolib/datafiles_test.go
@@ -261,8 +261,7 @@
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 @@
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
@@ -297,6 +295,27 @@
"a": map[string]interface{}{
"b1": []interface{}{"1", "2", "3"},
},
+ }
+
+ 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")
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -812,24 +812,50 @@
return nil
}
- // Copy content from current to data when needed
- if _, ok := current[r.BaseFileName()]; ok {
- data := data.(map[string]interface{})
+ // 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()]
- 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())
+ 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
}