Account for array type data in data dir merge/override logic - hugo - [fork] hugo port for 9front
 (HTM) git clone git@git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit bb549a0d57505a6b8f28930bb91a9ab44cbb3288
 (DIR) parent 82eefded1353f0198fd8fe9f7df1aa620d3d50eb
 (HTM) Author: Vas Sudanagunta <vas@commonkarma.org>
       Date:   Sun, 11 Feb 2018 18:34:03 -0500
       
       Account for array type data in data dir merge/override logic
       
       * Fixes #4366
       
       * Error message to console for unsupported data types
       
       Diffstat:
         M hugolib/datafiles_test.go           |      27 +++++++++++++++++++++++----
         M hugolib/site.go                     |      56 ++++++++++++++++++++++---------
       
       2 files changed, 64 insertions(+), 19 deletions(-)
       ---
 (DIR) diff --git 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
        }
 (DIR) diff --git 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
        }