shithub: hugo

Download patch

ref: b799b12f4a693dfeae8a5a362f131081a727bb8f
parent: 701486728e21bc0c6c78c2a8edb988abdf6116c7
author: Bjørn Erik Pedersen <[email protected]>
date: Mon Apr 15 05:38:14 EDT 2019

hugolib: Fix panic for unused taxonomy content files

In Hugo 0.55 we connected the taxonomy nodes with their owning Page.

This failed if you had, say, a content file for a author that did not author anything in the site:

```
content/authors/silent-persin/_index.md
```

Fixes #5847

--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -14,7 +14,9 @@
 package hugolib
 
 import (
+	"fmt"
 	"io"
+	"path"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -650,7 +652,19 @@
 
 			// Make them navigable from WeightedPage etc.
 			for _, p := range taxonomyPages {
-				p.getTaxonomyNodeInfo().TransferValues(p)
+				ni := p.getTaxonomyNodeInfo()
+				if ni == nil {
+					// This can be nil for taxonomies, e.g. an author,
+					// with a content file, but no actual usage.
+					// Create one.
+					sections := p.SectionsEntries()
+					if len(sections) < 2 {
+						// Invalid state
+						panic(fmt.Sprintf("invalid taxonomy state for %q with sections %v", p.pathOrTitle(), sections))
+					}
+					ni = p.s.taxonomyNodes.GetOrAdd(sections[0], path.Join(sections[1:]...))
+				}
+				ni.TransferValues(p)
 			}
 			for _, p := range taxonomyTermsPages {
 				p.getTaxonomyNodeInfo().TransferValues(p)
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -746,8 +746,10 @@
 	info := p.s.taxonomyNodes.Get(p.SectionsEntries()...)
 
 	if info == nil {
-		// This should never happpen
-		panic(fmt.Sprintf("invalid taxonomy state for %q with sections %v", p.pathOrTitle(), p.SectionsEntries()))
+		// There can be unused content pages for taxonomies (e.g. author that
+		// has not written anything, yet), and these will not have a taxonomy
+		// node created in the assemble taxonomies step.
+		return nil
 	}
 
 	return info
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -94,7 +94,7 @@
 
 	Taxonomies TaxonomyList
 
-	taxonomyNodes taxonomyNodeInfos
+	taxonomyNodes *taxonomyNodeInfos
 
 	Sections Taxonomy
 	Info     SiteInfo
@@ -1566,23 +1566,22 @@
 		s.Taxonomies[plural] = make(Taxonomy)
 	}
 
-	s.taxonomyNodes = make(taxonomyNodeInfos)
+	s.taxonomyNodes = &taxonomyNodeInfos{
+		m:      make(map[string]*taxonomyNodeInfo),
+		getKey: s.getTaxonomyKey,
+	}
 
 	s.Log.INFO.Printf("found taxonomies: %#v\n", taxonomies)
 
 	for singular, plural := range taxonomies {
-		parent := s.taxonomyNodes.GetOrCreate(plural, "", "")
+		parent := s.taxonomyNodes.GetOrCreate(plural, "")
 		parent.singular = singular
 
 		addTaxonomy := func(plural, term string, weight int, p page.Page) {
 			key := s.getTaxonomyKey(term)
 
-			n := s.taxonomyNodes.GetOrCreate(plural, key, term)
+			n := s.taxonomyNodes.GetOrCreate(plural, term)
 			n.parent = parent
-
-			// There may be different spellings before normalization, so the
-			// last one will win, e.g. "hugo" vs "Hugo".
-			n.term = term
 
 			w := page.NewWeightedPage(weight, p, n.owner)
 
--- a/hugolib/taxonomy.go
+++ b/hugolib/taxonomy.go
@@ -193,16 +193,33 @@
 
 // Maps either plural or plural/term to a taxonomy node.
 // TODO(bep) consolidate somehow with s.Taxonomies
-type taxonomyNodeInfos map[string]*taxonomyNodeInfo
+type taxonomyNodeInfos struct {
+	m      map[string]*taxonomyNodeInfo
+	getKey func(string) string
+}
 
+// map[string]*taxonomyNodeInfo
 func (t taxonomyNodeInfos) key(parts ...string) string {
 	return path.Join(parts...)
 }
 
-func (t taxonomyNodeInfos) GetOrCreate(plural, termKey, term string) *taxonomyNodeInfo {
+// GetOrAdd will get or create and add a new taxonomy node to the parent identified with plural.
+// It will panic if the parent does not exist.
+func (t taxonomyNodeInfos) GetOrAdd(plural, term string) *taxonomyNodeInfo {
+	parent := t.GetOrCreate(plural, "")
+	if parent == nil {
+		panic(fmt.Sprintf("no parent found with plural %q", plural))
+	}
+	child := t.GetOrCreate(plural, term)
+	child.parent = parent
+	return child
+}
+
+func (t taxonomyNodeInfos) GetOrCreate(plural, term string) *taxonomyNodeInfo {
+	termKey := t.getKey(term)
 	key := t.key(plural, termKey)
 
-	n, found := t[key]
+	n, found := t.m[key]
 	if found {
 		return n
 	}
@@ -214,7 +231,7 @@
 		owner:   &page.PageWrapper{}, // Page will be assigned later.
 	}
 
-	t[key] = n
+	t.m[key] = n
 
 	return n
 }
@@ -222,7 +239,7 @@
 func (t taxonomyNodeInfos) Get(sections ...string) *taxonomyNodeInfo {
 	key := t.key(sections...)
 
-	n, found := t[key]
+	n, found := t.m[key]
 	if found {
 		return n
 	}
--- a/hugolib/taxonomy_test.go
+++ b/hugolib/taxonomy_test.go
@@ -117,6 +117,9 @@
 	writeNewContentFile(t, fs.Source, "Category Terms", "2017-01-01", "content/categories/_index.md", 10)
 	writeNewContentFile(t, fs.Source, "Tag1 List", "2017-01-01", "content/tags/Tag1/_index.md", 10)
 
+	// https://github.com/gohugoio/hugo/issues/5847
+	writeNewContentFile(t, fs.Source, "Unused Tag List", "2018-01-01", "content/tags/not-used/_index.md", 10)
+
 	err := h.Build(BuildCfg{})
 
 	require.NoError(t, err)
@@ -159,7 +162,7 @@
 	// Make sure that each page.KindTaxonomyTerm page has an appropriate number
 	// of page.KindTaxonomy pages in its Pages slice.
 	taxonomyTermPageCounts := map[string]int{
-		"tags":         2,
+		"tags":         3,
 		"categories":   2,
 		"others":       2,
 		"empties":      0,