Account for array type data in data dir merge/override logic

* Fixes #4366

* Error message to console for unsupported data types
This commit is contained in:
Vas Sudanagunta 2018-02-11 18:34:03 -05:00 committed by Bjørn Erik Pedersen
parent 82eefded13
commit bb549a0d57
2 changed files with 63 additions and 18 deletions

View file

@ -261,8 +261,7 @@ func TestDataDirMultipleSourcesCommingled(t *testing.T) {
doTestDataDir(t, dd, expected, "theme", "mytheme") doTestDataDir(t, dd, expected, "theme", "mytheme")
} }
// TODO Issue #4366 unresolved func TestDataDirCollidingChildArrays(t *testing.T) {
func _TestDataDirMultipleSourcesCollidingChildArrays(t *testing.T) {
t.Parallel() t.Parallel()
var dd dataDir var dd dataDir
@ -284,8 +283,7 @@ func _TestDataDirMultipleSourcesCollidingChildArrays(t *testing.T) {
doTestDataDir(t, dd, expected, "theme", "mytheme") doTestDataDir(t, dd, expected, "theme", "mytheme")
} }
// TODO Issue #4366 unresolved func TestDataDirCollidingTopLevelArrays(t *testing.T) {
func _TestDataDirMultipleSourcesCollidingTopLevelArrays(t *testing.T) {
t.Parallel() t.Parallel()
var dd dataDir var dd dataDir
@ -302,6 +300,27 @@ func _TestDataDirMultipleSourcesCollidingTopLevelArrays(t *testing.T) {
doTestDataDir(t, dd, expected, "theme", "mytheme") 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 { type dataDir struct {
sources [][2]string sources [][2]string
} }

View file

@ -812,24 +812,50 @@ func (s *Site) handleDataFile(r source.ReadableFile) error {
return nil 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 '.' // filepath.Walk walks the files in lexical order, '/' comes before '.'
// this warning could happen if // this warning could happen if
// 1. A theme uses the same key; the main data folder wins // 1. A theme uses the same key; the main data folder wins
// 2. A sub folder uses the same key: the sub 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()) 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 case []interface{}:
if higherPrecedentData == nil {
current[r.BaseFileName()] = data 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 return nil
} }