shithub: hugo

Download patch

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
 }